X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Futil%2Fu_debug_symbol.c;h=334803d008ee67fa2e6dd59db8cafd0325a75098;hb=c0f7f833eb9c968e9f1491117d3ddc072eefddb7;hp=bae9be87a26df06af274f30e7974a7da2eca3120;hpb=52ad45677dd3d8a50836edea9f5841aa12d70419;p=mesa.git diff --git a/src/gallium/auxiliary/util/u_debug_symbol.c b/src/gallium/auxiliary/util/u_debug_symbol.c index bae9be87a26..334803d008e 100644 --- a/src/gallium/auxiliary/util/u_debug_symbol.c +++ b/src/gallium/auxiliary/util/u_debug_symbol.c @@ -34,13 +34,14 @@ #include "pipe/p_compiler.h" #include "os/os_thread.h" -#include "u_string.h" +#include "util/u_string.h" -#include "u_debug.h" +#include "util/u_debug.h" #include "u_debug_symbol.h" #include "u_hash_table.h" -#if defined(PIPE_OS_WINDOWS) && defined(PIPE_ARCH_X86) + +#if defined(PIPE_OS_WINDOWS) #include #include @@ -48,142 +49,216 @@ #include "dbghelp.h" -static BOOL bSymInitialized = FALSE; - -static HMODULE hModule_Dbghelp = NULL; +/** + * SymInitialize() must be called once for each process (in this case, the + * current process), before any of the other functions can be called. + */ +static BOOL g_bSymInitialized = FALSE; -static -FARPROC WINAPI __GetProcAddress(LPCSTR lpProcName) +/** + * Lookup the address of a DbgHelp function. + */ +static FARPROC WINAPI +getDbgHelpProcAddress(LPCSTR lpProcName) { + static HMODULE hModule = NULL; + + if (!hModule) { + static boolean bail = FALSE; + + if (bail) { + return NULL; + } + #ifdef PIPE_CC_GCC - if (!hModule_Dbghelp) { /* - * bfdhelp.dll is a dbghelp.dll look-alike replacement, which is able to - * understand MinGW symbols using BFD library. It is available from - * http://people.freedesktop.org/~jrfonseca/bfdhelp/ for now. + * DbgHelp does not understand the debug information generated by MinGW toolchain. + * + * mgwhelp.dll is a dbghelp.dll look-alike replacement, which is able to + * understand MinGW symbols, including on 64-bit builds. */ - hModule_Dbghelp = LoadLibraryA("bfdhelp.dll"); - } + if (!hModule) { + hModule = LoadLibraryA("mgwhelp.dll"); + if (!hModule) { + _debug_printf("warning: mgwhelp.dll not found: symbol names will not be resolved\n" + "warning: download it from https://github.com/jrfonseca/drmingw/#mgwhelp\n"); + } + } #endif - if (!hModule_Dbghelp) { - hModule_Dbghelp = LoadLibraryA("dbghelp.dll"); - if (!hModule_Dbghelp) { + /* + * Fallback to the real DbgHelp. + */ + if (!hModule) { + hModule = LoadLibraryA("dbghelp.dll"); + } + + if (!hModule) { + bail = TRUE; return NULL; } } - return GetProcAddress(hModule_Dbghelp, lpProcName); + return GetProcAddress(hModule, lpProcName); } -typedef BOOL (WINAPI *PFNSYMINITIALIZE)(HANDLE, LPSTR, BOOL); -static PFNSYMINITIALIZE pfnSymInitialize = NULL; +/** + * Generic macro to dispatch a DbgHelp functions. + */ +#define DBGHELP_DISPATCH(_name, _ret_type, _ret_default, _arg_types, _arg_names) \ + static _ret_type WINAPI \ + j_##_name _arg_types \ + { \ + typedef BOOL (WINAPI *PFN) _arg_types; \ + static PFN pfn = NULL; \ + if (!pfn) { \ + pfn = (PFN) getDbgHelpProcAddress(#_name); \ + if (!pfn) { \ + return _ret_default; \ + } \ + } \ + return pfn _arg_names; \ + } -static -BOOL WINAPI j_SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess) -{ - if( - (pfnSymInitialize || (pfnSymInitialize = (PFNSYMINITIALIZE) __GetProcAddress("SymInitialize"))) - ) - return pfnSymInitialize(hProcess, UserSearchPath, fInvadeProcess); - else - return FALSE; -} +DBGHELP_DISPATCH(SymInitialize, + BOOL, 0, + (HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess), + (hProcess, UserSearchPath, fInvadeProcess)) -typedef DWORD (WINAPI *PFNSYMSETOPTIONS)(DWORD); -static PFNSYMSETOPTIONS pfnSymSetOptions = NULL; +DBGHELP_DISPATCH(SymSetOptions, + DWORD, FALSE, + (DWORD SymOptions), + (SymOptions)) -static -DWORD WINAPI j_SymSetOptions(DWORD SymOptions) -{ - if( - (pfnSymSetOptions || (pfnSymSetOptions = (PFNSYMSETOPTIONS) __GetProcAddress("SymSetOptions"))) - ) - return pfnSymSetOptions(SymOptions); - else - return FALSE; -} +DBGHELP_DISPATCH(SymFromAddr, + BOOL, FALSE, + (HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol), + (hProcess, Address, Displacement, Symbol)) -typedef BOOL (WINAPI *PFNSYMGETSYMFROMADDR)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO); -static PFNSYMGETSYMFROMADDR pfnSymFromAddr = NULL; +DBGHELP_DISPATCH(SymGetLineFromAddr64, + BOOL, FALSE, + (HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line), + (hProcess, dwAddr, pdwDisplacement, Line)) -static -BOOL WINAPI j_SymFromAddr(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol) -{ - if( - (pfnSymFromAddr || (pfnSymFromAddr = (PFNSYMGETSYMFROMADDR) __GetProcAddress("SymFromAddr"))) - ) - return pfnSymFromAddr(hProcess, Address, Displacement, Symbol); - else - return FALSE; -} + +#undef DBGHELP_DISPATCH -static INLINE void +static inline boolean debug_symbol_name_dbghelp(const void *addr, char* buf, unsigned size) { - HANDLE hProcess; - BYTE symbolBuffer[1024]; - PSYMBOL_INFO pSymbol = (PSYMBOL_INFO) symbolBuffer; - DWORD64 dwDisplacement = 0; /* Displacement of the input address, relative to the start of the symbol */ + DWORD64 dwAddr = (DWORD64)(uintptr_t)addr; + HANDLE hProcess = GetCurrentProcess(); + + /* General purpose buffer, to back pSymbol and other temporary stuff. + * Must not be too memory hungry here to avoid stack overflows. + */ + CHAR buffer[512]; - hProcess = GetCurrentProcess(); + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO) buffer; + DWORD64 dwDisplacement = 0; /* Displacement of the input address, relative to the start of the symbol */ + DWORD dwLineDisplacement = 0; + IMAGEHLP_LINE64 Line; memset(pSymbol, 0, sizeof *pSymbol); - pSymbol->SizeOfStruct = sizeof(symbolBuffer); - pSymbol->MaxNameLen = sizeof(symbolBuffer) - offsetof(SYMBOL_INFO, Name); + pSymbol->SizeOfStruct = sizeof buffer; + pSymbol->MaxNameLen = sizeof buffer - offsetof(SYMBOL_INFO, Name); - if(!bSymInitialized) { + if (!g_bSymInitialized) { j_SymSetOptions(/* SYMOPT_UNDNAME | */ SYMOPT_LOAD_LINES); - if(j_SymInitialize(hProcess, NULL, TRUE)) - bSymInitialized = TRUE; + if (j_SymInitialize(hProcess, NULL, TRUE)) { + g_bSymInitialized = TRUE; + } } - if(!j_SymFromAddr(hProcess, (DWORD64)(uintptr_t)addr, &dwDisplacement, pSymbol)) - buf[0] = 0; - else - { - strncpy(buf, pSymbol->Name, size); - buf[size - 1] = 0; + /* Lookup symbol name */ + if (!g_bSymInitialized || + !j_SymFromAddr(hProcess, dwAddr, &dwDisplacement, pSymbol)) { + /* + * We couldn't obtain symbol information. At least tell which module the address belongs. + */ + + HMODULE hModule = NULL; + + if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (LPCTSTR)addr, + &hModule)) { + return FALSE; + } + + if (GetModuleFileNameA(hModule, buffer, sizeof buffer) == sizeof buffer) { + return FALSE; + } + snprintf(buf, size, "%p at %s+0x%lx", + addr, buffer, + (unsigned long)((uintptr_t)addr - (uintptr_t)hModule)); + + return TRUE; } + + /* + * Try to get filename and line number. + */ + memset(&Line, 0, sizeof Line); + Line.SizeOfStruct = sizeof Line; + if (!j_SymGetLineFromAddr64(hProcess, dwAddr, &dwLineDisplacement, &Line)) { + Line.FileName = NULL; + } + + if (Line.FileName) { + snprintf(buf, size, "%s at %s:%lu", pSymbol->Name, Line.FileName, Line.LineNumber); + } else { + snprintf(buf, size, "%s", pSymbol->Name); + } + + return TRUE; } -#endif -#ifdef __GLIBC__ +#endif /* PIPE_OS_WINDOWS */ + + +#if defined(HAVE_EXECINFO_H) + #include /* This can only provide dynamic symbols, or binary offsets into a file. * * To fix this, post-process the output with tools/addr2line.sh */ -static INLINE void +static inline boolean debug_symbol_name_glibc(const void *addr, char* buf, unsigned size) { char** syms = backtrace_symbols((void**)&addr, 1); - strncpy(buf, syms[0], size); + if (!syms) { + return FALSE; + } + strncpy(buf, syms[0], size - 1); buf[size - 1] = 0; free(syms); + return TRUE; } -#endif + +#endif /* defined(HAVE_EXECINFO_H) */ + void debug_symbol_name(const void *addr, char* buf, unsigned size) { -#if defined(PIPE_OS_WINDOWS) && defined(PIPE_ARCH_X86) - debug_symbol_name_dbghelp(addr, buf, size); - if(buf[0]) +#if defined(PIPE_OS_WINDOWS) + if (debug_symbol_name_dbghelp(addr, buf, size)) { return; + } #endif -#ifdef __GLIBC__ - debug_symbol_name_glibc(addr, buf, size); - if(buf[0]) - return; -#endif +#if defined(HAVE_EXECINFO_H) + if (debug_symbol_name_glibc(addr, buf, size)) { + return; + } +#endif /* defined(HAVE_EXECINFO_H) */ - util_snprintf(buf, size, "%p", addr); + snprintf(buf, size, "%p", addr); buf[size - 1] = 0; } @@ -195,40 +270,25 @@ debug_symbol_print(const void *addr) debug_printf("\t%s\n", buf); } -struct util_hash_table* symbols_hash; -pipe_static_mutex(symbols_mutex); - -static unsigned hash_ptr(void* p) -{ - return (unsigned)(uintptr_t)p; -} - -static int compare_ptr(void* a, void* b) -{ - if(a == b) - return 0; - else if(a < b) - return -1; - else - return 1; -} +struct hash_table* symbols_hash; +static mtx_t symbols_mutex = _MTX_INITIALIZER_NP; const char* debug_symbol_name_cached(const void *addr) { const char* name; -#ifdef PIPE_SUBSYSTEM_WINDOWS_USER +#ifdef PIPE_OS_WINDOWS static boolean first = TRUE; if (first) { - pipe_mutex_init(symbols_mutex); + (void) mtx_init(&symbols_mutex, mtx_plain); first = FALSE; } #endif - pipe_mutex_lock(symbols_mutex); + mtx_lock(&symbols_mutex); if(!symbols_hash) - symbols_hash = util_hash_table_create(hash_ptr, compare_ptr); + symbols_hash = util_hash_table_create_ptr_keys(); name = util_hash_table_get(symbols_hash, (void*)addr); if(!name) { @@ -236,8 +296,8 @@ debug_symbol_name_cached(const void *addr) debug_symbol_name(addr, buf, sizeof(buf)); name = strdup(buf); - util_hash_table_set(symbols_hash, (void*)addr, (void*)name); + _mesa_hash_table_insert(symbols_hash, (void*)addr, (void*)name); } - pipe_mutex_unlock(symbols_mutex); + mtx_unlock(&symbols_mutex); return name; }