X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Futil%2Fu_debug_symbol.c;h=73225e9e49544ed443c7696f1c5da2099f633207;hp=6e250575d66756592a7cfc03aca502724e1685a6;hb=e487043fd09a2307f868ebcba50abcafe0a2d4fe;hpb=431a51b9af32980ae8a544d129bf567287887376 diff --git a/src/gallium/auxiliary/util/u_debug_symbol.c b/src/gallium/auxiliary/util/u_debug_symbol.c index 6e250575d66..73225e9e495 100644 --- a/src/gallium/auxiliary/util/u_debug_symbol.c +++ b/src/gallium/auxiliary/util/u_debug_symbol.c @@ -33,123 +33,274 @@ */ #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 "util/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; -typedef DWORD (WINAPI *PFNSYMSETOPTIONS)(DWORD); -static PFNSYMSETOPTIONS pfnSymSetOptions = NULL; + if (!hModule) { + static boolean bail = FALSE; -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; -} + if (bail) { + return NULL; + } -typedef PGET_MODULE_BASE_ROUTINE PFNSYMGETMODULEBASE; -static PFNSYMGETMODULEBASE pfnSymGetModuleBase = 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 -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; -} + /* + * Fallback to the real DbgHelp. + */ + if (!hModule) { + hModule = LoadLibraryA("dbghelp.dll"); + } -typedef BOOL (WINAPI *PFNSYMGETSYMFROMADDR)(HANDLE, DWORD, LPDWORD, PIMAGEHLP_SYMBOL); -static PFNSYMGETSYMFROMADDR pfnSymGetSymFromAddr = NULL; + if (!hModule) { + bail = TRUE; + return NULL; + } + } -static -BOOL WINAPI j_SymGetSymFromAddr(HANDLE hProcess, DWORD Address, PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol) -{ - if( - (hModule_Imagehlp || (hModule_Imagehlp = LoadLibraryA("IMAGEHLP.DLL"))) && - (pfnSymGetSymFromAddr || (pfnSymGetSymFromAddr = (PFNSYMGETSYMFROMADDR) GetProcAddress(hModule_Imagehlp, "SymGetSymFromAddr"))) - ) - return pfnSymGetSymFromAddr(hProcess, Address, Displacement, Symbol); - else - return FALSE; + return GetProcAddress(hModule, lpProcName); } -static INLINE boolean -debug_symbol_print_imagehlp(const void *addr) +/** + * 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; \ + } + +DBGHELP_DISPATCH(SymInitialize, + BOOL, 0, + (HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess), + (hProcess, UserSearchPath, fInvadeProcess)) + +DBGHELP_DISPATCH(SymSetOptions, + DWORD, FALSE, + (DWORD SymOptions), + (SymOptions)) + +DBGHELP_DISPATCH(SymFromAddr, + BOOL, FALSE, + (HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol), + (hProcess, Address, Displacement, Symbol)) + +DBGHELP_DISPATCH(SymGetLineFromAddr64, + BOOL, FALSE, + (HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line), + (hProcess, dwAddr, pdwDisplacement, Line)) + + +#undef DBGHELP_DISPATCH + + +static inline boolean +debug_symbol_name_dbghelp(const void *addr, char* buf, unsigned size) { - 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 */ + DWORD64 dwAddr = (DWORD64)(uintptr_t)addr; + HANDLE hProcess = GetCurrentProcess(); - 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]; - pSymbol->SizeOfStruct = sizeof(symbolBuffer); - pSymbol->MaxNameLength = sizeof(symbolBuffer) - offsetof(IMAGEHLP_SYMBOL, Name); + 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; - if(!bSymInitialized) { + memset(pSymbol, 0, sizeof *pSymbol); + pSymbol->SizeOfStruct = sizeof buffer; + pSymbol->MaxNameLen = sizeof buffer - offsetof(SYMBOL_INFO, Name); + + 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_SymGetSymFromAddr(hProcess, (DWORD)addr, &dwDisplacement, pSymbol)) - return FALSE; - debug_printf("\t%s\n", pSymbol->Name); + /* 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 /* 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); +} + +static struct hash_table* symbols_hash; +#ifdef PIPE_OS_WINDOWS +static mtx_t symbols_mutex; +#else +static mtx_t symbols_mutex = _MTX_INITIALIZER_NP; #endif - - debug_printf("\t%p\n", addr); + +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 + + mtx_lock(&symbols_mutex); + if(!symbols_hash) + symbols_hash = _mesa_pointer_hash_table_create(NULL); + struct hash_entry *entry = _mesa_hash_table_search(symbols_hash, addr); + if (!entry) { + char buf[1024]; + debug_symbol_name(addr, buf, sizeof(buf)); + name = strdup(buf); + + entry = _mesa_hash_table_insert(symbols_hash, addr, (void*)name); + } + mtx_unlock(&symbols_mutex); + return entry->data; }