u_debug_symbol.c revision 63c05c96e798e68fdec93e6a1184ec06d3713d98
1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28/** 29 * @file 30 * Symbol lookup. 31 * 32 * @author Jose Fonseca <jfonseca@vmware.com> 33 */ 34 35#include "pipe/p_compiler.h" 36#include "os/os_thread.h" 37#include "u_string.h" 38 39#include "u_debug.h" 40#include "u_debug_symbol.h" 41#include "u_hash_table.h" 42 43#if defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86) 44 45#include <windows.h> 46#include <stddef.h> 47#include <imagehlp.h> 48 49/* 50 * TODO: Cleanup code. 51 * TODO: Support x86_64 52 */ 53 54static BOOL bSymInitialized = FALSE; 55 56static HMODULE hModule_Imagehlp = NULL; 57 58typedef BOOL (WINAPI *PFNSYMINITIALIZE)(HANDLE, LPSTR, BOOL); 59static PFNSYMINITIALIZE pfnSymInitialize = NULL; 60 61static 62BOOL WINAPI j_SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess) 63{ 64 if( 65 (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && 66 (pfnSymInitialize || (pfnSymInitialize = (PFNSYMINITIALIZE) GetProcAddress(hModule_Imagehlp, "SymInitialize"))) 67 ) 68 return pfnSymInitialize(hProcess, UserSearchPath, fInvadeProcess); 69 else 70 return FALSE; 71} 72 73typedef DWORD (WINAPI *PFNSYMSETOPTIONS)(DWORD); 74static PFNSYMSETOPTIONS pfnSymSetOptions = NULL; 75 76static 77DWORD WINAPI j_SymSetOptions(DWORD SymOptions) 78{ 79 if( 80 (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && 81 (pfnSymSetOptions || (pfnSymSetOptions = (PFNSYMSETOPTIONS) GetProcAddress(hModule_Imagehlp, "SymSetOptions"))) 82 ) 83 return pfnSymSetOptions(SymOptions); 84 else 85 return FALSE; 86} 87 88typedef PGET_MODULE_BASE_ROUTINE PFNSYMGETMODULEBASE; 89static PFNSYMGETMODULEBASE pfnSymGetModuleBase = NULL; 90 91static 92DWORD WINAPI j_SymGetModuleBase(HANDLE hProcess, DWORD dwAddr) 93{ 94 if( 95 (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && 96 (pfnSymGetModuleBase || (pfnSymGetModuleBase = (PFNSYMGETMODULEBASE) GetProcAddress(hModule_Imagehlp, "SymGetModuleBase"))) 97 ) 98 return pfnSymGetModuleBase(hProcess, dwAddr); 99 else 100 return 0; 101} 102 103typedef BOOL (WINAPI *PFNSYMGETSYMFROMADDR)(HANDLE, DWORD, LPDWORD, PIMAGEHLP_SYMBOL); 104static PFNSYMGETSYMFROMADDR pfnSymGetSymFromAddr = NULL; 105 106static 107BOOL WINAPI j_SymGetSymFromAddr(HANDLE hProcess, DWORD Address, PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol) 108{ 109 if( 110 (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && 111 (pfnSymGetSymFromAddr || (pfnSymGetSymFromAddr = (PFNSYMGETSYMFROMADDR) GetProcAddress(hModule_Imagehlp, "SymGetSymFromAddr"))) 112 ) 113 return pfnSymGetSymFromAddr(hProcess, Address, Displacement, Symbol); 114 else 115 return FALSE; 116} 117 118 119static INLINE void 120debug_symbol_name_imagehlp(const void *addr, char* buf, unsigned size) 121{ 122 HANDLE hProcess; 123 BYTE symbolBuffer[1024]; 124 PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL) symbolBuffer; 125 DWORD dwDisplacement = 0; /* Displacement of the input address, relative to the start of the symbol */ 126 127 hProcess = GetCurrentProcess(); 128 129 pSymbol->SizeOfStruct = sizeof(symbolBuffer); 130 pSymbol->MaxNameLength = sizeof(symbolBuffer) - offsetof(IMAGEHLP_SYMBOL, Name); 131 132 if(!bSymInitialized) { 133 j_SymSetOptions(/* SYMOPT_UNDNAME | */ SYMOPT_LOAD_LINES); 134 if(j_SymInitialize(hProcess, NULL, TRUE)) 135 bSymInitialized = TRUE; 136 } 137 138 if(!j_SymGetSymFromAddr(hProcess, (DWORD)addr, &dwDisplacement, pSymbol)) 139 buf[0] = 0; 140 else 141 { 142 strncpy(buf, pSymbol->Name, size); 143 buf[size - 1] = 0; 144 } 145} 146#endif 147 148#ifdef __GLIBC__ 149#include <execinfo.h> 150 151/* This can only provide dynamic symbols, or binary offsets into a file. 152 * 153 * To fix this, post-process the output with tools/addr2line.sh 154 */ 155static INLINE void 156debug_symbol_name_glibc(const void *addr, char* buf, unsigned size) 157{ 158 char** syms = backtrace_symbols((void**)&addr, 1); 159 strncpy(buf, syms[0], size); 160 buf[size - 1] = 0; 161 free(syms); 162} 163#endif 164 165void 166debug_symbol_name(const void *addr, char* buf, unsigned size) 167{ 168#if defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86) 169 debug_symbol_name_imagehlp(addr, buf, size); 170 if(buf[0]) 171 return; 172#endif 173 174#ifdef __GLIBC__ 175 debug_symbol_name_glibc(addr, buf, size); 176 if(buf[0]) 177 return; 178#endif 179 180 util_snprintf(buf, size, "%p", addr); 181 buf[size - 1] = 0; 182} 183 184void 185debug_symbol_print(const void *addr) 186{ 187 char buf[1024]; 188 debug_symbol_name(addr, buf, sizeof(buf)); 189 debug_printf("\t%s\n", buf); 190} 191 192struct util_hash_table* symbols_hash; 193pipe_mutex symbols_mutex; 194 195static unsigned hash_ptr(void* p) 196{ 197 return (unsigned)(uintptr_t)p; 198} 199 200static int compare_ptr(void* a, void* b) 201{ 202 if(a == b) 203 return 0; 204 else if(a < b) 205 return -1; 206 else 207 return 1; 208} 209 210const char* 211debug_symbol_name_cached(const void *addr) 212{ 213 const char* name; 214 pipe_mutex_lock(symbols_mutex); 215 if(!symbols_hash) 216 symbols_hash = util_hash_table_create(hash_ptr, compare_ptr); 217 name = util_hash_table_get(symbols_hash, (void*)addr); 218 if(!name) 219 { 220 char buf[1024]; 221 debug_symbol_name(addr, buf, sizeof(buf)); 222 name = strdup(buf); 223 224 util_hash_table_set(symbols_hash, (void*)addr, (void*)name); 225 } 226 pipe_mutex_unlock(symbols_mutex); 227 return name; 228} 229