int CMiniDumpReader::StackWalk(DWORD dwThreadId) { int nThreadIndex = GetThreadRowIdByThreadId(dwThreadId); if(m_DumpData.m_Threads[nThreadIndex].m_bStackWalk == TRUE) return 0; // Already done CONTEXT* pThreadContext = NULL; if(m_DumpData.m_Threads[nThreadIndex].m_dwThreadId==m_DumpData.m_uExceptionThreadId) pThreadContext = m_DumpData.m_pExceptionThreadContext; else pThreadContext = m_DumpData.m_Threads[nThreadIndex].m_pThreadContext; if(pThreadContext==NULL) return 1; // Make modifiable context CONTEXT Context; memcpy(&Context, pThreadContext, sizeof(CONTEXT)); g_pMiniDumpReader = this; // Init stack frame with correct initial values // See this: // http://www.codeproject.com/KB/threads/StackWalker.aspx // // Given a current dbghelp, your code should: // 1. Always use StackWalk64 // 2. Always set AddrPC to the current instruction pointer (Eip on x86, Rip on x64 and StIIP on IA64) // 3. Always set AddrStack to the current stack pointer (Esp on x86, Rsp on x64 and IntSp on IA64) // 4. Set AddrFrame to the current frame pointer when meaningful. On x86 this is Ebp, on x64 you // can use Rbp (but is not used by VC2005B2; instead it uses Rdi!) and on IA64 you can use RsBSP. // StackWalk64 will ignore the value when it isn't needed for unwinding. // 5. Set AddrBStore to RsBSP for IA64. STACKFRAME64 sf; memset(&sf, 0, sizeof(STACKFRAME64)); sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrStack.Mode = AddrModeFlat; sf.AddrBStore.Mode = AddrModeFlat; DWORD dwMachineType = 0; switch(m_DumpData.m_uProcessorArchitecture) { #ifdef _X86_ case PROCESSOR_ARCHITECTURE_INTEL: dwMachineType = IMAGE_FILE_MACHINE_I386; sf.AddrPC.Offset = pThreadContext->Eip; sf.AddrStack.Offset = pThreadContext->Esp; sf.AddrFrame.Offset = pThreadContext->Ebp; break; #endif #ifdef _AMD64_ case PROCESSOR_ARCHITECTURE_AMD64: dwMachineType = IMAGE_FILE_MACHINE_AMD64; sf.AddrPC.Offset = pThreadContext->Rip; sf.AddrStack.Offset = pThreadContext->Rsp; sf.AddrFrame.Offset = pThreadContext->Rbp; break; #endif #ifdef _IA64_ case PROCESSOR_ARCHITECTURE_AMD64: dwMachineType = IMAGE_FILE_MACHINE_IA64; sf.AddrPC.Offset = pThreadContext->StIIP; sf.AddrStack.Offset = pThreadContext->IntSp; sf.AddrFrame.Offset = pThreadContext->RsBSP; sf.AddrBStore.Offset = pThreadContext->RsBSP; break; #endif default: { assert(0); return 1; // Unsupported architecture } } for(;;) { BOOL bWalk = ::StackWalk64( dwMachineType, // machine type m_DumpData.m_hProcess, // our process handle (HANDLE)dwThreadId, // thread ID &sf, // stack frame dwMachineType==IMAGE_FILE_MACHINE_I386?NULL:(&Context), // used for non-I386 machines ReadProcessMemoryProc64, // our routine FunctionTableAccessProc64, // our routine GetModuleBaseProc64, // our routine NULL // safe to be NULL ); if(!bWalk) break; MdmpStackFrame stack_frame; stack_frame.m_dwAddrPCOffset = sf.AddrPC.Offset; // Get module info IMAGEHLP_MODULE64 mi; memset(&mi, 0, sizeof(IMAGEHLP_MODULE64)); mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); BOOL bGetModuleInfo = SymGetModuleInfo64(m_DumpData.m_hProcess, sf.AddrPC.Offset, &mi); if(bGetModuleInfo) { stack_frame.m_nModuleRowID = GetModuleRowIdByBaseAddr(mi.BaseOfImage); } // Get symbol info DWORD64 dwDisp64; BYTE buffer[4096]; SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer; sym_info->SizeOfStruct = sizeof(SYMBOL_INFO); sym_info->MaxNameLen = 4096-sizeof(SYMBOL_INFO)-1; BOOL bGetSym = SymFromAddr( m_DumpData.m_hProcess, sf.AddrPC.Offset, &dwDisp64, sym_info); if(bGetSym) { stack_frame.m_sSymbolName = CString(sym_info->Name, sym_info->NameLen); stack_frame.m_dw64OffsInSymbol = dwDisp64; } // Get source filename and line DWORD dwDisplacement; IMAGEHLP_LINE64 line; BOOL bGetLine = SymGetLineFromAddr64( m_DumpData.m_hProcess, sf.AddrPC.Offset, &dwDisplacement, &line); if(bGetLine) { stack_frame.m_sSrcFileName = line.FileName; stack_frame.m_nSrcLineNumber = line.LineNumber; } m_DumpData.m_Threads[nThreadIndex].m_StackTrace.push_back(stack_frame); } CString sStackTrace; UINT i; for(i=0; i<m_DumpData.m_Threads[nThreadIndex].m_StackTrace.size(); i++) { MdmpStackFrame& frame = m_DumpData.m_Threads[nThreadIndex].m_StackTrace[i]; if(frame.m_sSymbolName.IsEmpty()) continue; CString sModuleName; CString sAddrPCOffset; CString sSymbolName; CString sOffsInSymbol; CString sSourceFile; CString sSourceLine; if(frame.m_nModuleRowID>=0) { sModuleName = m_DumpData.m_Modules[frame.m_nModuleRowID].m_sModuleName; } sSymbolName = frame.m_sSymbolName; sAddrPCOffset.Format(_T("0x%I64x"), frame.m_dwAddrPCOffset); sSourceFile = frame.m_sSrcFileName; sSourceLine.Format(_T("%d"), frame.m_nSrcLineNumber); sOffsInSymbol.Format(_T("0x%I64x"), frame.m_dw64OffsInSymbol); CString str; str = sModuleName; if(!str.IsEmpty()) str += _T("!"); if(sSymbolName.IsEmpty()) str += sAddrPCOffset; else { str += sSymbolName; str += _T("+"); str += sOffsInSymbol; } if(!sSourceFile.IsEmpty()) { int pos = sSourceFile.ReverseFind('\\'); if(pos>=0) sSourceFile = sSourceFile.Mid(pos+1); str += _T(" [ "); str += sSourceFile; str += _T(": "); str += sSourceLine; str += _T(" ] "); } sStackTrace += str; sStackTrace += _T("\n"); } if(!sStackTrace.IsEmpty()) { strconv_t strconv; LPCSTR szStackTrace = strconv.t2utf8(sStackTrace); MD5 md5; MD5_CTX md5_ctx; unsigned char md5_hash[16]; md5.MD5Init(&md5_ctx); md5.MD5Update(&md5_ctx, (unsigned char*)szStackTrace, (unsigned int)strlen(szStackTrace)); md5.MD5Final(md5_hash, &md5_ctx); for(i=0; i<16; i++) { CString number; number.Format(_T("%02x"), md5_hash[i]); m_DumpData.m_Threads[nThreadIndex].m_sStackTraceMD5 += number; } } m_DumpData.m_Threads[nThreadIndex].m_bStackWalk = TRUE; return 0; }
/** * Logs the stack back trace leading up to this function call. * @param ex Pointer to stack context (PCONTEXT on Windows), NULL to use current context. */ void stackTrace(void *ctx) { #ifdef _WIN32 const int MAX_SYMBOL_LENGTH = 1024; CONTEXT context; if (ctx != 0) { context = *((PCONTEXT)ctx); } else { #ifdef _MSC_VER memset(&context, 0, sizeof(CONTEXT)); context.ContextFlags = CONTEXT_FULL; RtlCaptureContext(&context); #else // TODO: Doesn't work on MinGW return; #endif } HANDLE thread = GetCurrentThread(); HANDLE process = GetCurrentProcess(); STACKFRAME64 frame; memset(&frame, 0, sizeof(STACKFRAME64)); DWORD image; #ifdef _M_IX86 image = IMAGE_FILE_MACHINE_I386; frame.AddrPC.Offset = context.Eip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Ebp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = context.Esp; frame.AddrStack.Mode = AddrModeFlat; #elif _M_X64 image = IMAGE_FILE_MACHINE_AMD64; frame.AddrPC.Offset = context.Rip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Rbp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = context.Rsp; frame.AddrStack.Mode = AddrModeFlat; #elif _M_IA64 image = IMAGE_FILE_MACHINE_IA64; frame.AddrPC.Offset = context.StIIP; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.IntSp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrBStore.Offset = context.RsBSP; frame.AddrBStore.Mode = AddrModeFlat; frame.AddrStack.Offset = context.IntSp; frame.AddrStack.Mode = AddrModeFlat; #else // TODO: Stack trace not supported on this architecture Log(LOG_FATAL) << "Unfortunately, no stack trace information is available"; return; #endif SYMBOL_INFO *symbol = (SYMBOL_INFO *)malloc(sizeof(SYMBOL_INFO) + (MAX_SYMBOL_LENGTH - 1) * sizeof(TCHAR)); symbol->MaxNameLen = MAX_SYMBOL_LENGTH; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64)); line->SizeOfStruct = sizeof(IMAGEHLP_LINE64); DWORD displacement; SymInitialize(process, NULL, TRUE); while (StackWalk64(image, process, thread, &frame, &context, NULL, NULL, NULL, NULL)) { if (SymFromAddr(process, frame.AddrPC.Offset, NULL, symbol)) { if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &displacement, line)) { std::string filename = line->FileName; size_t n = filename.find_last_of(PATH_SEPARATOR); if (n != std::string::npos) { filename = filename.substr(n + 1); } Log(LOG_FATAL) << "0x" << std::hex << symbol->Address << std::dec << " " << symbol->Name << " (" << filename << ":" << line->LineNumber << ")"; } else { Log(LOG_FATAL) << "0x" << std::hex << symbol->Address << std::dec << " " << symbol->Name << " (??: " << GetLastError() << ")"; } } else { Log(LOG_FATAL) << "??: " << GetLastError(); } } DWORD err = GetLastError(); if (err) { Log(LOG_FATAL) << "No stack trace generated: " << err; } SymCleanup(process); #else const int MAX_STACK_FRAMES = 16; void *array[MAX_STACK_FRAMES]; size_t size = backtrace(array, MAX_STACK_FRAMES); char **strings = backtrace_symbols(array, size); for (size_t i = 0; i < size; ++i) { Log(LOG_FATAL) << strings[i]; } free(strings); #endif }
void printStackTrace(MemoryAllocationRecord* rec) { const unsigned int bufferSize = 512; // Resolve the program counter to the corresponding function names. unsigned int pc; for (int i = 0; i < MAX_STACK_FRAMES; i++) { // Check to see if we are at the end of the stack trace. pc = rec->pc[i]; if (pc == 0) break; // Get the function name. unsigned char buffer[sizeof(IMAGEHLP_SYMBOL64) + bufferSize]; IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)buffer; DWORD64 displacement; memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64) + bufferSize); symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); symbol->MaxNameLength = bufferSize; if (!SymGetSymFromAddr64(GetCurrentProcess(), pc, &displacement, symbol)) { gameplay::print("[memory] STACK TRACE: <unknown location>\n"); } else { symbol->Name[bufferSize - 1] = '\0'; // Check if we need to go further up the stack. if (strncmp(symbol->Name, "operator new", 12) == 0) { // In operator new or new[], keep going... } else { // Get the file and line number. if (pc != 0) { IMAGEHLP_LINE64 line; DWORD displacement; memset(&line, 0, sizeof(line)); line.SizeOfStruct = sizeof(line); if (!SymGetLineFromAddr64(GetCurrentProcess(), pc, &displacement, &line)) { gameplay::print("[memory] STACK TRACE: %s - <unknown file>:<unknown line number>\n", symbol->Name); } else { const char* file = strrchr(line.FileName, '\\'); if(!file) file = line.FileName; else file++; gameplay::print("[memory] STACK TRACE: %s - %s:%d\n", symbol->Name, file, line.LineNumber); } } } } } }
void PrintBacktrace(PCONTEXT context) { HANDLE hProcess = GetCurrentProcess(); HANDLE hThread = GetCurrentThread(); char appDir[MAX_PATH + 1]; GetModuleFileName(nullptr, appDir, sizeof(appDir)); char* end = strrchr(appDir, PATH_SEPARATOR); if (end) *end = '\0'; SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS); if (!SymInitialize(hProcess, appDir, TRUE)) { warn("Could not obtain detailed exception information: SymInitialize failed"); return; } const int MAX_NAMELEN = 1024; IMAGEHLP_SYMBOL64* sym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_NAMELEN); memset(sym, 0, sizeof(IMAGEHLP_SYMBOL64) + MAX_NAMELEN); sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); sym->MaxNameLength = MAX_NAMELEN; IMAGEHLP_LINE64 ilLine; memset(&ilLine, 0, sizeof(ilLine)); ilLine.SizeOfStruct = sizeof(ilLine); STACKFRAME64 sfStackFrame; memset(&sfStackFrame, 0, sizeof(sfStackFrame)); DWORD imageType; #ifdef _M_IX86 imageType = IMAGE_FILE_MACHINE_I386; sfStackFrame.AddrPC.Offset = context->Eip; sfStackFrame.AddrPC.Mode = AddrModeFlat; sfStackFrame.AddrFrame.Offset = context->Ebp; sfStackFrame.AddrFrame.Mode = AddrModeFlat; sfStackFrame.AddrStack.Offset = context->Esp; sfStackFrame.AddrStack.Mode = AddrModeFlat; #elif _M_X64 imageType = IMAGE_FILE_MACHINE_AMD64; sfStackFrame.AddrPC.Offset = context->Rip; sfStackFrame.AddrPC.Mode = AddrModeFlat; sfStackFrame.AddrFrame.Offset = context->Rsp; sfStackFrame.AddrFrame.Mode = AddrModeFlat; sfStackFrame.AddrStack.Offset = context->Rsp; sfStackFrame.AddrStack.Mode = AddrModeFlat; #else warn("Could not obtain detailed exception information: platform not supported"); return; #endif for (int frameNum = 0; ; frameNum++) { if (frameNum > 1000) { warn("Endless stack, abort tracing"); return; } if (!StackWalk64(imageType, hProcess, hThread, &sfStackFrame, context, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr)) { warn("Could not obtain detailed exception information: StackWalk64 failed"); return; } DWORD64 dwAddr = sfStackFrame.AddrPC.Offset; BString<1024> symName; BString<1024> srcFileName; int lineNumber = 0; DWORD64 dwSymbolDisplacement; if (SymGetSymFromAddr64(hProcess, dwAddr, &dwSymbolDisplacement, sym)) { UnDecorateSymbolName(sym->Name, symName, symName.Capacity(), UNDNAME_COMPLETE); symName[sizeof(symName) - 1] = '\0'; } else { symName = "<symbol not available>"; } DWORD dwLineDisplacement; if (SymGetLineFromAddr64(hProcess, dwAddr, &dwLineDisplacement, &ilLine)) { lineNumber = ilLine.LineNumber; char* useFileName = ilLine.FileName; char* root = strstr(useFileName, "\\daemon\\"); if (root) { useFileName = root; } srcFileName = useFileName; } else { srcFileName = "<filename not available>"; } info("%s (%i) : %s", *srcFileName, lineNumber, *symName); if (sfStackFrame.AddrReturn.Offset == 0) { break; } } }
/*********************************************************************** * symbol_get_lvalue * * Get the address of a named symbol. * Return values: * sglv_found: if the symbol is found * sglv_unknown: if the symbol isn't found * sglv_aborted: some error occurred (likely, many symbols of same name exist, * and user didn't pick one of them) */ enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno, struct dbg_lvalue* rtn, BOOL bp_disp) { struct sgv_data sgv; int i; char buffer[512]; DWORD opt; IMAGEHLP_STACK_FRAME ihsf; if (strlen(name) + 4 > sizeof(buffer)) { WINE_WARN("Too long symbol (%s)\n", name); return sglv_unknown; } sgv.num = 0; sgv.num_thunks = 0; sgv.name = &buffer[2]; sgv.do_thunks = DBG_IVAR(AlwaysShowThunks); if (strchr(name, '!')) { strcpy(buffer, name); } else { buffer[0] = '*'; buffer[1] = '!'; strcpy(&buffer[2], name); } /* this is a wine specific options to return also ELF modules in the * enumeration */ SymSetOptions((opt = SymGetOptions()) | 0x40000000); SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv); if (!sgv.num) { const char* ptr = strchr(name, '!'); if ((ptr && ptr[1] != '_') || (!ptr && *name != '_')) { if (ptr) { int offset = ptr - name; memcpy(buffer, name, offset + 1); buffer[offset + 1] = '_'; strcpy(&buffer[offset + 2], ptr + 1); } else { buffer[0] = '*'; buffer[1] = '!'; buffer[2] = '_'; strcpy(&buffer[3], name); } SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv); } } SymSetOptions(opt); /* now grab local symbols */ if (stack_get_current_frame(&ihsf) && sgv.num < NUMDBGV) { sgv.frame_offset = ihsf.FrameOffset; SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv); } if (!sgv.num) { dbg_printf("No symbols found for %s\n", name); return sglv_unknown; } /* recompute potential offsets for functions (linenumber, skip prolog) */ for (i = 0; i < sgv.num; i++) { if (sgv.syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL|SYMFLAG_LOCAL|SYMFLAG_THUNK)) continue; if (lineno == -1) { struct dbg_type type; ULONG64 addr; type.module = sgv.syms[i].lvalue.type.module; type.id = sgv.syms[i].sym_info; if (bp_disp && symbol_get_debug_start(&type, &addr)) sgv.syms[i].lvalue.addr.Offset = addr; } else { DWORD disp; IMAGEHLP_LINE64 il; BOOL found = FALSE; il.SizeOfStruct = sizeof(il); SymGetLineFromAddr64(dbg_curr_process->handle, (DWORD_PTR)memory_to_linear_addr(&sgv.syms[i].lvalue.addr), &disp, &il); do { if (lineno == il.LineNumber) { sgv.syms[i].lvalue.addr.Offset = il.Address; found = TRUE; break; } } while (SymGetLineNext64(dbg_curr_process->handle, &il)); if (!found) WINE_FIXME("No line (%d) found for %s (setting to symbol start)\n", lineno, name); } } if (sgv.num - sgv.num_thunks > 1 || /* many symbols non thunks (and showing only non thunks) */ (sgv.num > 1 && DBG_IVAR(AlwaysShowThunks)) || /* many symbols (showing symbols & thunks) */ (sgv.num == sgv.num_thunks && sgv.num_thunks > 1)) { return symbol_current_picker(name, &sgv, rtn); } /* first symbol is the one we want: * - only one symbol found, * - or many symbols but only one non thunk when AlwaysShowThunks is FALSE */ *rtn = sgv.syms[0].lvalue; return sglv_found; }
/*********************************************************************** * symbol_get_line * * Find the symbol nearest to a given address. * Returns sourcefile name and line number in a format that the listing * handler can deal with. */ BOOL symbol_get_line(const char* filename, const char* name, IMAGEHLP_LINE64* line) { struct sgv_data sgv; char buffer[512]; DWORD opt, disp; unsigned i, found = FALSE; IMAGEHLP_LINE64 il; sgv.num = 0; sgv.num_thunks = 0; sgv.name = &buffer[2]; sgv.do_thunks = FALSE; buffer[0] = '*'; buffer[1] = '!'; strcpy(&buffer[2], name); /* this is a wine specific options to return also ELF modules in the * enumeration */ SymSetOptions((opt = SymGetOptions()) | 0x40000000); if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv)) { SymSetOptions(opt); return FALSE; } if (!sgv.num && (name[0] != '_')) { buffer[2] = '_'; strcpy(&buffer[3], name); if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv)) { SymSetOptions(opt); return FALSE; } } SymSetOptions(opt); for (i = 0; i < sgv.num; i++) { DWORD_PTR linear = (DWORD_PTR)memory_to_linear_addr(&sgv.syms[i].lvalue.addr); il.SizeOfStruct = sizeof(il); if (!SymGetLineFromAddr64(dbg_curr_process->handle, linear, &disp, &il)) continue; if (filename && strcmp(il.FileName, filename)) continue; if (found) { WINE_FIXME("Several found, returning first (may not be what you want)...\n"); break; } found = TRUE; *line = il; } if (!found) { if (filename) dbg_printf("No such function %s in %s\n", name, filename); else dbg_printf("No such function %s\n", name); return FALSE; } return TRUE; }
bool CATDbgHelper::AddressToLine( CATMemoryAddress* result ) { LOG_FUNC_ENTRY("CATDbgHelper::AddressToLine"); // Set state out of range result->SetAddressToLineState( CATMemoryAddress::OUT_OF_RANGE ); // check that dbghelper has been initialized successfully. if ( ! CDBGHELPER_OPEN ) return false; // Check has binary been moved, if so unload and load to new base address. if ( result->GetModuleStartAddress() + AT_VIRTUAL_OFFSET_DBGHELPER != m_BaseAddress ) { // Unload. if ( SymUnloadModule64( GetCurrentProcess(), m_BaseAddress ) ) { // Set new base address. m_BaseAddress = result->GetModuleStartAddress() + AT_VIRTUAL_OFFSET_DBGHELPER; // (Re)load. DWORD64 loading = SymLoadModule64( GetCurrentProcess(), NULL, m_pBinaryFile, NULL, m_BaseAddress, NULL ); if ( loading != m_BaseAddress && loading != 0) { LOG_STRING("Dbghelp:Module load failed " << (int) GetLastError()); return false; } } else LOG_STRING("Dbghelp:Module unload failed " << (int) GetLastError() ); } // Address to find (offset+given address). unsigned long iAddressToFind = result->GetAddress() + AT_VIRTUAL_OFFSET_DBGHELPER; // Displacements of line/symbol information. DWORD64 displacementSymbol; DWORD displacementLine; // Structure to get symbol information. CSymbolInfo symbol; // Structure to get line information. CLineInfo line; // Find Symbol for given address if( ! SymFromAddr( GetCurrentProcess(), iAddressToFind , &displacementSymbol, &symbol.si ) ) { LOG_STRING("Failed to find symbol information for given line."); return AddressToFunction( result ); } // Find line information if( ! SymGetLineFromAddr64( GetCurrentProcess(), iAddressToFind, &displacementLine, &line ) ) { // If it fails get symbol line information LOG_STRING("Dbghelp:Failed to find line information for address, trying for symbol of address."); if( ! SymGetLineFromAddr64( GetCurrentProcess(), symbol.si.Address, &displacementLine, &line ) ) { LOG_STRING("Dbghelp:Failed to find line information for symbol address."); return AddressToFunction( result ); } } // Set the results. result->SetFileName( string( line.FileName ) ); result->SetFunctionName( string( symbol.si.Name ) ); result->SetExactLineNumber( (int) line.LineNumber ); result->SetAddressToLineState( CATMemoryAddress::EXACT ); // Return. return true; }
static void dlgPrint( uint64_t addr,const char *filename,int lineno,const char *funcname, void *context,int columnno ) { struct dialog_info *di = context; #ifndef NO_DBGHELP char buffer[sizeof(SYMBOL_INFO)+MAX_SYM_NAME]; SYMBOL_INFO *si = (SYMBOL_INFO*)&buffer; if( lineno==DWST_NO_DBG_SYM ) { IMAGEHLP_LINE64 ihl; memset( &ihl,0,sizeof(IMAGEHLP_LINE64) ); ihl.SizeOfStruct = sizeof(IMAGEHLP_LINE64); DWORD displ; if( SymGetLineFromAddr64(GetCurrentProcess(),addr,&displ,&ihl) ) { filename = ihl.FileName; lineno = ihl.LineNumber; } DWORD64 displ2; si->SizeOfStruct = sizeof(SYMBOL_INFO); si->MaxNameLen = MAX_SYM_NAME; if( SymFromAddr(GetCurrentProcess(),addr,&displ2,si) ) { char *fn = si->Name; fn[MAX_SYM_NAME] = 0; funcname = fn; } } #endif const char *delim = strrchr( filename,'/' ); if( delim ) filename = delim + 1; delim = strrchr( filename,'\\' ); if( delim ) filename = delim + 1; void *ptr = (void*)(uintptr_t)addr; switch( lineno ) { case DWST_BASE_ADDR: if( ptr==di->lastBase ) break; di->lastBase = ptr; printAddr( di->hwnd,TEXT("base address"),-1, ptr,filename,0,NULL,0 ); break; case DWST_NOT_FOUND: case DWST_NO_DBG_SYM: case DWST_NO_SRC_FILE: printAddr( di->hwnd,TEXT(" stack "),di->count++, ptr,NULL,0,funcname,0 ); break; default: printAddr( di->hwnd,TEXT(" stack "),di->count, ptr,filename,lineno,funcname,columnno ); if( ptr ) di->count++; break; } }
void printBacktrace(std::ostream * os) { if(os == 0) os = &std::cout; const int SIZE = 100; const int NAME_SIZE = 256; #if defined(_WIN32) HANDLE process = GetCurrentProcess(); SymSetOptions(SYMOPT_LOAD_LINES); SymInitialize(process, NULL, TRUE); void * stack[SIZE]; unsigned short frames = CaptureStackBackTrace(0, SIZE, stack, NULL); SYMBOL_INFO * symbol = (SYMBOL_INFO * )calloc(sizeof(SYMBOL_INFO) + NAME_SIZE * sizeof(char), 1); symbol->MaxNameLen = NAME_SIZE; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); for(unsigned short i = 0; i < frames; i++ ) { SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol); IMAGEHLP_LINE64 line; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); DWORD dwDisplacement; if(!strstr(symbol->Name, __FUNCTION__) && !strstr(symbol->Name,"pgr::debugCallback") && SymGetLineFromAddr64(process, (DWORD64)(stack[i]), &dwDisplacement, &line)) { *os << symbol->Name << "():" << line.LineNumber << std::endl; } if(strcmp(symbol->Name, "main") == 0) break; } free(symbol); #elif defined(__linux__) int j; void *buffer[SIZE]; char **strings; int nptrs = backtrace(buffer, SIZE); strings = backtrace_symbols(buffer, nptrs); if(strings == NULL) { *os << "error in backtrace_symbols" << std::endl; return; } for (j = 0; j < nptrs; j++) *os << strings[j] << std::endl; free(strings); #else *os << "backtrace not supported on this platform" << std::endl; #endif }
std::vector<std::string> backtrace_get(int skip) { unsigned int i; void * stack[ 100 ]; unsigned short frames; SYMBOL_INFO * symbol; HANDLE process; IMAGEHLP_LINE *line = (IMAGEHLP_LINE *)malloc(sizeof(IMAGEHLP_LINE)); line->SizeOfStruct = sizeof(IMAGEHLP_LINE); IMAGEHLP_LINE64 *line64 = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64)); line64->SizeOfStruct = sizeof(IMAGEHLP_LINE64); IMAGEHLP_MODULE *mod = (IMAGEHLP_MODULE *)malloc(sizeof(IMAGEHLP_MODULE)); mod->SizeOfStruct = sizeof(IMAGEHLP_MODULE); IMAGEHLP_MODULE64 *mod64 = (IMAGEHLP_MODULE64 *)malloc(sizeof(IMAGEHLP_MODULE64)); mod->SizeOfStruct = sizeof(IMAGEHLP_MODULE64); process = GetCurrentProcess(); SymSetOptions(SYMOPT_LOAD_LINES); SymInitialize( process, NULL, TRUE ); frames = CaptureStackBackTrace( 0, 100, stack, NULL ); symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 ); symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof( SYMBOL_INFO ); char *buf = (char *)malloc(1024); std::vector<std::string> vs; for( i = skip; i < frames; i++ ){ SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol ); bool m64 = false; BOOL mod_status = SymGetModuleInfo(process, symbol->Address, mod); if (!mod_status) { mod_status = SymGetModuleInfo64(process, symbol->Address, mod64); m64 = true; } DWORD dwDisplacement; bool l64 = false; BOOL line_status = SymGetLineFromAddr(process, (ULONG64)stack[i], &dwDisplacement, line); if (!line_status) { line_status = SymGetLineFromAddr64(process, (ULONG64)stack[i], &dwDisplacement, line64); l64 = true; } sprintf(buf, "%-3d %*p %s(%s + 0x%I64x)", frames - i - 1, int(2 + sizeof(void*) * 2), stack[i], mod_status ? (m64 ? mod64->ModuleName : mod->ModuleName) : "<unknown dll>", symbol->Name, symbol->Address); vs.push_back(std::string(buf)); if (line_status) { sprintf(buf, "\t\t%s:%d", l64 ? line64->FileName : line->FileName, l64 ? line64->LineNumber : line->LineNumber); vs.push_back(std::string(buf)); } } free(buf); free(symbol); SymCleanup(process); return vs; }
PXR_NAMESPACE_OPEN_SCOPE bool ArchGetAddressInfo( void* address, std::string* objectPath, void** baseAddress, std::string* symbolName, void** symbolAddress) { #if defined(_GNU_SOURCE) || defined(ARCH_OS_DARWIN) Dl_info info; if (dladdr(address, &info)) { if (objectPath) { // The object filename may be a relative path if, for instance, // the given address comes from an executable that was invoked // with a relative path, or from a shared library that was // dlopen'd with a relative path. We want to always return // absolute paths, so do the resolution here. // // This may be incorrect if the current working directory was // changed after the source object was loaded. *objectPath = ArchAbsPath(info.dli_fname); } if (baseAddress) { *baseAddress = info.dli_fbase; } if (symbolName) { *symbolName = info.dli_sname ? info.dli_sname : ""; } if (symbolAddress) { *symbolAddress = info.dli_saddr; } return true; } return false; #elif defined(ARCH_OS_WINDOWS) if (!address) { return false; } HMODULE module = nullptr; if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCSTR>(address), &module)) { return false; } if (objectPath) { char modName[MAX_PATH] = {0}; if (GetModuleFileName(module, modName, MAX_PATH)) { objectPath->assign(modName); } } if (baseAddress || symbolName || symbolAddress) { DWORD displacement; HANDLE process = GetCurrentProcess(); SymInitialize(process, NULL, TRUE); // Symbol ULONG64 symBuffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; SYMBOL_INFO *symbol = (SYMBOL_INFO*)symBuffer; symbol->MaxNameLen = MAX_SYM_NAME; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); // Line IMAGEHLP_LINE64 line = {0}; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); DWORD64 dwAddress = (DWORD64)address; SymFromAddr(process, dwAddress, NULL, symbol); if (!SymGetLineFromAddr64(process, dwAddress, &displacement, &line)) { return false; } if (baseAddress) { MODULEINFO moduleInfo = {0}; if (!GetModuleInformation(process, module, &moduleInfo, sizeof(moduleInfo))) { return false; } *baseAddress = moduleInfo.lpBaseOfDll; } if (symbolName) { *symbolName = symbol->Name ? symbol->Name : ""; } if (symbolAddress) { *symbolAddress = (void*)symbol->Address; } } return true; #else return false; #endif }
const char* MemoryManager::GetCallerForAllocation(AllocHeader* pAllocation) { #ifdef USE_STACKTRACE const size_t cnBufferSize=512; char szFile[cnBufferSize]; char szFunc[cnBufferSize]; unsigned int nLine; static char szBuff[cnBufferSize*3]; strcpy(szFile,"??"); nLine=0; DWORD64 nPC; for(int i=0;i<AllocHeader::cnMaxStackFrames;++i) { nPC=pAllocation->nPC[i]; if(nPC==0) break; unsigned char byBuffer[sizeof(IMAGEHLP_SYMBOL64)+cnBufferSize]; IMAGEHLP_SYMBOL64* pSymbol=(IMAGEHLP_SYMBOL64*)byBuffer; DWORD64 dwDisplacement; memset(pSymbol,0,sizeof(IMAGEHLP_SYMBOL64)+cnBufferSize); pSymbol->SizeOfStruct=sizeof(IMAGEHLP_SYMBOL64); pSymbol->MaxNameLength=cnBufferSize; if(!SymGetSymFromAddr64(GetCurrentProcess(),nPC,&dwDisplacement,pSymbol)) strcpy(szFunc,"??"); else { pSymbol->Name[cnBufferSize-1]='\0'; if(strncmp(pSymbol->Name,"MemMgr::",8)==0) { // In MemMgr,keep going... } else if(strncmp(pSymbol->Name,"operator new",12)==0) { // In operator new or new[],keep going... } else if(strncmp(pSymbol->Name,"std::",5)==0) { // In STL code,keep going... } else { // Found the allocator (Or near to it) strcpy(szFunc,pSymbol->Name); break; } } } if(nPC!=0) { IMAGEHLP_LINE64 theLine; DWORD dwDisplacement; memset(&theLine,0,sizeof(theLine)); theLine.SizeOfStruct=sizeof(theLine); if(!SymGetLineFromAddr64(GetCurrentProcess(),nPC,&dwDisplacement,&theLine)) { strcpy(szFile,"??"); nLine=0; } else { const char* pszFile=strrchr(theLine.FileName,'\\'); if(!pszFile) pszFile=theLine.FileName; else ++pszFile; strncpy(szFile,pszFile,cnBufferSize); nLine=theLine.LineNumber; } } sprintf(szBuff,"%s:%d (%s)",szFile,nLine,szFunc); return szBuff; #else UNREFERENCED_PARAMETER(pAllocation); return "Stack trace unavailable"; #endif }
int main(int argc, char *argv[]) { DWORD error; HANDLE process; ULONG64 module_base; int i; char* search; char buf[256]; /* Enough to hold one hex address, I trust! */ int rv = 0; /* We may add SYMOPT_UNDNAME if --demangle is specified: */ DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES; char* filename = "a.out"; /* The default if -e isn't specified */ int print_function_name = 0; /* Set to 1 if -f is specified */ for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--functions") == 0 || strcmp(argv[i], "-f") == 0) { print_function_name = 1; } else if (strcmp(argv[i], "--demangle") == 0 || strcmp(argv[i], "-C") == 0) { symopts |= SYMOPT_UNDNAME; } else if (strcmp(argv[i], "--exe") == 0 || strcmp(argv[i], "-e") == 0) { if (i + 1 >= argc) { fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n"); return 1; } filename = argv[i+1]; i++; /* to skip over filename too */ } else if (strcmp(argv[i], "--help") == 0) { usage(); exit(0); } else { usage(); exit(1); } } process = GetCurrentProcess(); if (!SymInitialize(process, NULL, FALSE)) { error = GetLastError(); fprintf(stderr, "SymInitialize returned error : %lu\n", error); return 1; } search = malloc(SEARCH_CAP); if (SymGetSearchPath(process, search, SEARCH_CAP)) { if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) { fprintf(stderr, "Search path too long\n"); SymCleanup(process); return 1; } strcat(search, ";" WEBSYM); } else { error = GetLastError(); fprintf(stderr, "SymGetSearchPath returned error : %lu\n", error); rv = 1; /* An error, but not a fatal one */ strcpy(search, WEBSYM); /* Use a default value */ } if (!SymSetSearchPath(process, search)) { error = GetLastError(); fprintf(stderr, "SymSetSearchPath returned error : %lu\n", error); rv = 1; /* An error, but not a fatal one */ } SymSetOptions(symopts); module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0); if (!module_base) { /* SymLoadModuleEx failed */ error = GetLastError(); fprintf(stderr, "SymLoadModuleEx returned error : %lu for %s\n", error, filename); SymCleanup(process); return 1; } buf[sizeof(buf)-1] = '\0'; /* Just to be safe */ while (fgets(buf, sizeof(buf)-1, stdin)) { /* GNU addr2line seems to just do a strtol and ignore any * weird characters it gets, so we will too. */ unsigned __int64 reladdr = _strtoui64(buf, NULL, 16); ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; memset(buffer, 0, sizeof(buffer)); PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; IMAGEHLP_LINE64 line; DWORD dummy; // Just ignore overflow. In an overflow scenario, the resulting address // will be lower than module_base which hasn't been mapped by any prior // SymLoadModuleEx() command. This will cause SymFromAddr() and // SymGetLineFromAddr64() both to return failures and print the correct // ?? and ??:0 message variant. ULONG64 absaddr = reladdr + module_base; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); // The length of the name is not including the null-terminating character. pSymbol->MaxNameLen = MAX_SYM_NAME - 1; if (print_function_name) { if (SymFromAddr(process, (DWORD64)absaddr, NULL, pSymbol)) { printf("%s\n", pSymbol->Name); } else { printf("??\n"); } } line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); if (SymGetLineFromAddr64(process, (DWORD64)absaddr, &dummy, &line)) { printf("%s:%d\n", line.FileName, (int)line.LineNumber); } else { printf("??:0\n"); } } SymUnloadModule64(process, module_base); SymCleanup(process); return rv; }