diff options
author | José Fonseca <[email protected]> | 2013-06-24 13:35:53 +0100 |
---|---|---|
committer | José Fonseca <[email protected]> | 2013-06-25 18:41:59 +0100 |
commit | 464c6949cb2998b80f4a2d70add99e6a7cf8c67d (patch) | |
tree | 4aae8d9206386c910740ef99ca8212dc97ede778 /src | |
parent | a26f834a39063b68466db62b154c6fe817f06008 (diff) |
util/debug: Cleanup/improve debug_symbol_name_dbghelp.
- use mgwhelp -- the successor for bfdhelp which does not have a hard
dependency on BFD, and works on 64bits.
- use a macro instead of hand-typing to dispatch DbgHelp functions
- dump line numbers
- dump module names when symbols are not available
- support 64bits.
- add comments
Reviewed-by: Brian Paul <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/gallium/auxiliary/util/u_debug_symbol.c | 239 |
1 files changed, 161 insertions, 78 deletions
diff --git a/src/gallium/auxiliary/util/u_debug_symbol.c b/src/gallium/auxiliary/util/u_debug_symbol.c index 0ef111c3b24..bba9122e7f5 100644 --- a/src/gallium/auxiliary/util/u_debug_symbol.c +++ b/src/gallium/auxiliary/util/u_debug_symbol.c @@ -40,7 +40,8 @@ #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 <windows.h> #include <stddef.h> @@ -48,139 +49,221 @@ #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 + * 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 http://code.google.com/p/jrfonseca/wiki/DrMingw#MgwHelp\n"); + } + } + + /* + * bfdhelp.dll was the predecessor of mgwhelp.dll. It is available from * http://people.freedesktop.org/~jrfonseca/bfdhelp/ for now. */ - hModule_Dbghelp = LoadLibraryA("bfdhelp.dll"); - } -#endif + if (!hModule) { + hModule = LoadLibraryA("bfdhelp.dll"); + } + #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(); - 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_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; + } + util_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) { + util_snprintf(buf, size, "%s at %s:%lu", pSymbol->Name, Line.FileName, Line.LineNumber); + } else { + util_snprintf(buf, size, "%s", pSymbol->Name); + } + + return TRUE; } -#endif + +#endif /* PIPE_OS_WINDOWS */ + #if defined(__GLIBC__) && !defined(__UCLIBC__) + #include <execinfo.h> /* 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); + if (!syms) { + return FALSE; + } strncpy(buf, syms[0], size); buf[size - 1] = 0; free(syms); + return TRUE; } -#endif + +#endif /* defined(__GLIBC__) && !defined(__UCLIBC__) */ + 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 #if defined(__GLIBC__) && !defined(__UCLIBC__) - debug_symbol_name_glibc(addr, buf, size); - if(buf[0]) - return; + if (debug_symbol_name_glibc(addr, buf, size)) { + return; + } #endif util_snprintf(buf, size, "%p", addr); |