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=417d0cf04c924350ed37dfc4d792d010fb9f7cb8;hpb=55770d09c18c4d33403abb97dfef4f897efbbe2a;p=mesa.git diff --git a/src/gallium/auxiliary/util/u_debug_symbol.c b/src/gallium/auxiliary/util/u_debug_symbol.c index 417d0cf04c9..334803d008e 100644 --- a/src/gallium/auxiliary/util/u_debug_symbol.c +++ b/src/gallium/auxiliary/util/u_debug_symbol.c @@ -33,218 +33,271 @@ */ #include "pipe/p_compiler.h" +#include "os/os_thread.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_SUBSYSTEM_WINDOWS_USER) && defined(PIPE_ARCH_X86) + +#if defined(PIPE_OS_WINDOWS) #include #include -#include -/* - * TODO: Cleanup code. - * TODO: Support x86_64 - */ +#include "dbghelp.h" -static BOOL bSymInitialized = FALSE; -static HMODULE hModule_Imagehlp = 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; -typedef BOOL (WINAPI *PFNSYMINITIALIZE)(HANDLE, LPSTR, BOOL); -static PFNSYMINITIALIZE pfnSymInitialize = NULL; -static -BOOL WINAPI j_SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess) +/** + * Lookup the address of a DbgHelp function. + */ +static FARPROC WINAPI +getDbgHelpProcAddress(LPCSTR lpProcName) { - if( - (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && - (pfnSymInitialize || (pfnSymInitialize = (PFNSYMINITIALIZE) GetProcAddress(hModule_Imagehlp, "SymInitialize"))) - ) - return pfnSymInitialize(hProcess, UserSearchPath, fInvadeProcess); - else - return FALSE; -} + static HMODULE hModule = NULL; + + if (!hModule) { + static boolean bail = FALSE; + + if (bail) { + return NULL; + } + +#ifdef PIPE_CC_GCC + /* + * 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. + */ + 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 -typedef BOOL (WINAPI *PFNSYMCLEANUP)(HANDLE); -static PFNSYMCLEANUP pfnSymCleanup = NULL; + /* + * Fallback to the real DbgHelp. + */ + if (!hModule) { + hModule = LoadLibraryA("dbghelp.dll"); + } + + if (!hModule) { + bail = TRUE; + return NULL; + } + } -static -BOOL WINAPI j_SymCleanup(HANDLE hProcess) -{ - if( - (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && - (pfnSymCleanup || (pfnSymCleanup = (PFNSYMCLEANUP) GetProcAddress(hModule_Imagehlp, "SymCleanup"))) - ) - return pfnSymCleanup(hProcess); - else - return FALSE; + return GetProcAddress(hModule, lpProcName); } -typedef DWORD (WINAPI *PFNSYMSETOPTIONS)(DWORD); -static PFNSYMSETOPTIONS pfnSymSetOptions = NULL; -static -DWORD WINAPI j_SymSetOptions(DWORD SymOptions) -{ - if( - (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && - (pfnSymSetOptions || (pfnSymSetOptions = (PFNSYMSETOPTIONS) GetProcAddress(hModule_Imagehlp, "SymSetOptions"))) - ) - return pfnSymSetOptions(SymOptions); - else - return FALSE; -} - -typedef BOOL (WINAPI *PFNSYMUNDNAME)(PIMAGEHLP_SYMBOL, PSTR, DWORD); -static PFNSYMUNDNAME pfnSymUnDName = 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_SymUnDName(PIMAGEHLP_SYMBOL Symbol, PSTR UnDecName, DWORD UnDecNameLength) -{ - if( - (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && - (pfnSymUnDName || (pfnSymUnDName = (PFNSYMUNDNAME) GetProcAddress(hModule_Imagehlp, "SymUnDName"))) - ) - return pfnSymUnDName(Symbol, UnDecName, UnDecNameLength); - else - return FALSE; -} +DBGHELP_DISPATCH(SymInitialize, + BOOL, 0, + (HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess), + (hProcess, UserSearchPath, fInvadeProcess)) -typedef PFUNCTION_TABLE_ACCESS_ROUTINE PFNSYMFUNCTIONTABLEACCESS; -static PFNSYMFUNCTIONTABLEACCESS pfnSymFunctionTableAccess = NULL; +DBGHELP_DISPATCH(SymSetOptions, + DWORD, FALSE, + (DWORD SymOptions), + (SymOptions)) -static -PVOID WINAPI j_SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase) -{ - if( - (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && - (pfnSymFunctionTableAccess || (pfnSymFunctionTableAccess = (PFNSYMFUNCTIONTABLEACCESS) GetProcAddress(hModule_Imagehlp, "SymFunctionTableAccess"))) - ) - return pfnSymFunctionTableAccess(hProcess, AddrBase); - else - return NULL; -} +DBGHELP_DISPATCH(SymFromAddr, + BOOL, FALSE, + (HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol), + (hProcess, Address, Displacement, Symbol)) -typedef PGET_MODULE_BASE_ROUTINE PFNSYMGETMODULEBASE; -static PFNSYMGETMODULEBASE pfnSymGetModuleBase = NULL; +DBGHELP_DISPATCH(SymGetLineFromAddr64, + BOOL, FALSE, + (HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line), + (hProcess, dwAddr, pdwDisplacement, Line)) -static -DWORD WINAPI j_SymGetModuleBase(HANDLE hProcess, DWORD dwAddr) -{ - if( - (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && - (pfnSymGetModuleBase || (pfnSymGetModuleBase = (PFNSYMGETMODULEBASE) GetProcAddress(hModule_Imagehlp, "SymGetModuleBase"))) - ) - return pfnSymGetModuleBase(hProcess, dwAddr); - else - return 0; -} -typedef BOOL (WINAPI *PFNSTACKWALK)(DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID, PREAD_PROCESS_MEMORY_ROUTINE, PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE); -static PFNSTACKWALK pfnStackWalk = NULL; - -static -BOOL WINAPI j_StackWalk( - DWORD MachineType, - HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME StackFrame, - PVOID ContextRecord, - PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, - PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE TranslateAddress -) -{ - if( - (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && - (pfnStackWalk || (pfnStackWalk = (PFNSTACKWALK) GetProcAddress(hModule_Imagehlp, "StackWalk"))) - ) - return pfnStackWalk( - MachineType, - hProcess, - hThread, - StackFrame, - ContextRecord, - ReadMemoryRoutine, - FunctionTableAccessRoutine, - GetModuleBaseRoutine, - TranslateAddress - ); - else - return FALSE; -} +#undef DBGHELP_DISPATCH -typedef BOOL (WINAPI *PFNSYMGETSYMFROMADDR)(HANDLE, DWORD, LPDWORD, PIMAGEHLP_SYMBOL); -static PFNSYMGETSYMFROMADDR pfnSymGetSymFromAddr = NULL; -static -BOOL WINAPI j_SymGetSymFromAddr(HANDLE hProcess, DWORD Address, PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol) +static inline boolean +debug_symbol_name_dbghelp(const void *addr, char* buf, unsigned size) { - if( - (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && - (pfnSymGetSymFromAddr || (pfnSymGetSymFromAddr = (PFNSYMGETSYMFROMADDR) GetProcAddress(hModule_Imagehlp, "SymGetSymFromAddr"))) - ) - return pfnSymGetSymFromAddr(hProcess, Address, Displacement, Symbol); - else - return FALSE; -} + DWORD64 dwAddr = (DWORD64)(uintptr_t)addr; + HANDLE hProcess = GetCurrentProcess(); -typedef BOOL (WINAPI *PFNSYMGETLINEFROMADDR)(HANDLE, DWORD, LPDWORD, PIMAGEHLP_LINE); -static PFNSYMGETLINEFROMADDR pfnSymGetLineFromAddr = NULL; + /* General purpose buffer, to back pSymbol and other temporary stuff. + * Must not be too memory hungry here to avoid stack overflows. + */ + CHAR buffer[512]; -static -BOOL WINAPI j_SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE Line) -{ - if( - (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && - (pfnSymGetLineFromAddr || (pfnSymGetLineFromAddr = (PFNSYMGETLINEFROMADDR) GetProcAddress(hModule_Imagehlp, "SymGetLineFromAddr"))) - ) - return pfnSymGetLineFromAddr(hProcess, dwAddr, pdwDisplacement, Line); - else - return FALSE; -} + 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 buffer; + pSymbol->MaxNameLen = sizeof buffer - offsetof(SYMBOL_INFO, Name); -static INLINE boolean -debug_symbol_print_imagehlp(const void *addr) -{ - HANDLE hProcess; - BYTE symbolBuffer[1024]; - PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL) symbolBuffer; - DWORD dwDisplacement = 0; /* Displacement of the input address, relative to the start of the symbol */ + if (!g_bSymInitialized) { + j_SymSetOptions(/* SYMOPT_UNDNAME | */ SYMOPT_LOAD_LINES); + if (j_SymInitialize(hProcess, NULL, TRUE)) { + g_bSymInitialized = TRUE; + } + } - hProcess = GetCurrentProcess(); + /* 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; + } - pSymbol->SizeOfStruct = sizeof(symbolBuffer); - pSymbol->MaxNameLength = sizeof(symbolBuffer) - offsetof(IMAGEHLP_SYMBOL, Name); + /* + * 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(!bSymInitialized) { - j_SymSetOptions(/* SYMOPT_UNDNAME | */ SYMOPT_LOAD_LINES); - if(j_SymInitialize(hProcess, NULL, TRUE)) - bSymInitialized = TRUE; + if (Line.FileName) { + snprintf(buf, size, "%s at %s:%lu", pSymbol->Name, Line.FileName, Line.LineNumber); + } else { + snprintf(buf, size, "%s", pSymbol->Name); } - - if(!j_SymGetSymFromAddr(hProcess, (DWORD)addr, &dwDisplacement, pSymbol)) - return FALSE; - debug_printf("\t%s\n", pSymbol->Name); + return TRUE; +} + +#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 boolean +debug_symbol_name_glibc(const void *addr, char* buf, unsigned size) +{ + char** syms = backtrace_symbols((void**)&addr, 1); + if (!syms) { + return FALSE; + } + strncpy(buf, syms[0], size - 1); + buf[size - 1] = 0; + free(syms); return TRUE; - } + +#endif /* defined(HAVE_EXECINFO_H) */ + + +void +debug_symbol_name(const void *addr, char* buf, unsigned size) +{ +#if defined(PIPE_OS_WINDOWS) + if (debug_symbol_name_dbghelp(addr, buf, size)) { + return; + } #endif +#if defined(HAVE_EXECINFO_H) + if (debug_symbol_name_glibc(addr, buf, size)) { + return; + } +#endif /* defined(HAVE_EXECINFO_H) */ + + snprintf(buf, size, "%p", addr); + buf[size - 1] = 0; +} void debug_symbol_print(const void *addr) { -#if defined(PIPE_SUBSYSTEM_WINDOWS_USER) && defined(PIPE_ARCH_X86) - if(debug_symbol_print_imagehlp(addr)) - return; + char buf[1024]; + debug_symbol_name(addr, buf, sizeof(buf)); + debug_printf("\t%s\n", buf); +} + +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_OS_WINDOWS + static boolean first = TRUE; + + if (first) { + (void) mtx_init(&symbols_mutex, mtx_plain); + first = FALSE; + } #endif - - debug_printf("\t%p\n", addr); + + mtx_lock(&symbols_mutex); + if(!symbols_hash) + symbols_hash = util_hash_table_create_ptr_keys(); + name = util_hash_table_get(symbols_hash, (void*)addr); + if(!name) + { + char buf[1024]; + debug_symbol_name(addr, buf, sizeof(buf)); + name = strdup(buf); + + _mesa_hash_table_insert(symbols_hash, (void*)addr, (void*)name); + } + mtx_unlock(&symbols_mutex); + return name; }