bool KImageModule::Load(char * filename, char *sympath) { _tcscpy(m_modulename, filename); memset(& m_image, 0, sizeof(m_image)); m_imagebase_loaded = (DWORD) GetModuleHandle(filename); if ( m_imagebase_loaded ) // module is already loaded, for example GDI32.DLL { m_imagebase_default = m_imagebase_loaded; m_bLoaded = false; PIMAGE_NT_HEADERS pNTHeader = ImageNtHeader((void *)m_imagebase_loaded); Output("%s already loaded at 0x%x %s\n", filename, m_imagebase_loaded, ctime( (time_t *) & pNTHeader->FileHeader.TimeDateStamp)); } else { if ( MapAndLoad(filename, NULL, & m_image, FALSE, TRUE) ) Output("%s loaded at 0x%x %s\n", m_image.ModuleName, m_image.MappedAddress, ctime( (time_t *) & m_image.FileHeader->FileHeader.TimeDateStamp)); else { Output("Unable to load %s\n", filename); return false; } m_imagebase_loaded = (DWORD) m_image.MappedAddress; m_imagebase_default = m_image.FileHeader->OptionalHeader.ImageBase; m_bLoaded = true; } if ( !SymInitialize(m_hProcess, sympath, FALSE) ) { Output("SymInitialize failed\n\n"); return false; } m_symbolbase = SymLoadModule(m_hProcess, NULL, filename, 0, m_imagebase_loaded, 0 ); if ( m_symbolbase==0 ) { Output("SymLoadModule failed\n\n"); return false; } IMAGEHLP_MODULE im; im.SizeOfStruct = sizeof(im); SymGetModuleInfo( m_hProcess, m_symbolbase, &im ); Output("""%s"" loaded. %s\n", im.LoadedImageName, ctime((time_t *) & im.TimeDateStamp)); return true; }
BOOL CMemLeakDetect::symModuleNameFromAddress( ADDR address, TCHAR* lpszModule ) { BOOL ret = FALSE; IMAGEHLP_MODULE moduleInfo; ::ZeroMemory( &moduleInfo, sizeof(IMAGEHLP_MODULE) ); moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE); if ( SymGetModuleInfo( m_hProcess, (ADDR)address, &moduleInfo ) ) { // Note. IMAGEHLP_MODULE::ModuleName seems to be hardcoded as 32 char/wchar_t (VS2008). #ifdef UNICODE int len = (int)_tcslen(lpszModule) + 1 ; char dest[1024] ; WideCharToMultiByte( CP_ACP, 0, lpszModule, -1, dest, len, NULL, NULL ); strcpy_s(moduleInfo.ModuleName, 32, dest); // bloody ANSI! #else strcpy_s(moduleInfo.ModuleName, 32, lpszModule); #endif ret = TRUE; } else { _tcscpy_s( lpszModule, MLD_MAX_NAME_LENGTH, MLD_TRACEINFO_NOSYMBOL); } return ret; }
/****************************************************************** * SymGetModuleInfoW (DBGHELP.@) * */ BOOL WINAPI SymGetModuleInfoW(HANDLE hProcess, DWORD dwAddr, PIMAGEHLP_MODULEW ModuleInfo) { IMAGEHLP_MODULE mi; IMAGEHLP_MODULEW miw; if (sizeof(miw) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n"); mi.SizeOfStruct = sizeof(mi); if (!SymGetModuleInfo(hProcess, dwAddr, &mi)) return FALSE; miw.SizeOfStruct = mi.SizeOfStruct; miw.BaseOfImage = mi.BaseOfImage; miw.ImageSize = mi.ImageSize; miw.TimeDateStamp = mi.TimeDateStamp; miw.CheckSum = mi.CheckSum; miw.NumSyms = mi.NumSyms; miw.SymType = mi.SymType; MultiByteToWideChar(CP_ACP, 0, mi.ModuleName, -1, miw.ModuleName, sizeof(miw.ModuleName) / sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, 0, mi.ImageName, -1, miw.ImageName, sizeof(miw.ImageName) / sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, 0, mi.LoadedImageName, -1, miw.LoadedImageName, sizeof(miw.LoadedImageName) / sizeof(WCHAR)); memcpy(ModuleInfo, &miw, ModuleInfo->SizeOfStruct); return TRUE; }
static BOOL CALLBACK symbols_info_cb(PSYMBOL_INFO sym, ULONG size, PVOID ctx) { struct dbg_type type; IMAGEHLP_MODULE mi; mi.SizeOfStruct = sizeof(mi); if (!SymGetModuleInfo(dbg_curr_process->handle, sym->ModBase, &mi)) mi.ModuleName[0] = '\0'; else { size_t len = strlen(mi.ModuleName); if (len > 5 && !strcmp(mi.ModuleName + len - 5, "<elf>")) mi.ModuleName[len - 5] = '\0'; } dbg_printf("%08lx: %s!%s", (ULONG_PTR)sym->Address, mi.ModuleName, sym->Name); type.id = sym->TypeIndex; type.module = sym->ModBase; if (sym->TypeIndex != dbg_itype_none && sym->TypeIndex != 0) { dbg_printf(" "); types_print_type(&type, FALSE); } dbg_printf("\n"); return TRUE; }
/*********************************************************************** * print_address * * Print an 16- or 32-bit address, with the nearest symbol if any. */ void print_address(const ADDRESS64* addr, BOOLEAN with_line) { char buffer[sizeof(SYMBOL_INFO) + 256]; SYMBOL_INFO* si = (SYMBOL_INFO*)buffer; void* lin = memory_to_linear_addr(addr); DWORD64 disp64; DWORD disp; print_bare_address(addr); si->SizeOfStruct = sizeof(*si); si->MaxNameLen = 256; if (!SymFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp64, si)) return; dbg_printf(" %s", si->Name); if (disp64) dbg_printf("+0x%lx", (DWORD_PTR)disp64); if (with_line) { IMAGEHLP_LINE il; IMAGEHLP_MODULE im; il.SizeOfStruct = sizeof(il); if (SymGetLineFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp, &il)) dbg_printf(" [%s:%lu]", il.FileName, il.LineNumber); im.SizeOfStruct = sizeof(im); if (SymGetModuleInfo(dbg_curr_process->handle, (DWORD_PTR)lin, &im)) dbg_printf(" in %s", im.ModuleName); } }
static DWORD __stdcall GetModuleBase(HANDLE hProcess, DWORD dwReturnAddress) { IMAGEHLP_MODULE moduleInfo; if (SymGetModuleInfo(hProcess, dwReturnAddress, &moduleInfo)) return moduleInfo.BaseOfImage; else { MEMORY_BASIC_INFORMATION memoryBasicInfo; if (::VirtualQueryEx(hProcess, (LPVOID) dwReturnAddress, &memoryBasicInfo, sizeof(memoryBasicInfo))) { DWORD cch = 0; char szFile[MAX_PATH] = { 0 }; cch = GetModuleFileNameA((HINSTANCE)memoryBasicInfo.AllocationBase, szFile, MAX_PATH); // Ignore the return code since we can't do anything with it. if (!SymLoadModule(hProcess, NULL, ((cch) ? szFile : NULL), NULL, (DWORD) memoryBasicInfo.AllocationBase, 0)) { DWORD dwError = GetLastError(); TRACE1("Error: %d\n", dwError); } return (DWORD) memoryBasicInfo.AllocationBase; } else TRACE1("Error is %d\n", GetLastError()); } return 0; }
BOOL CallStack::symModuleNameFromAddress( UINT address, TCHAR* lpszModule, UINT BufSizeTCHARs) { BOOL ret = FALSE; IMAGEHLP_MODULE moduleInfo; ::ZeroMemory( &moduleInfo, sizeof(IMAGEHLP_MODULE) ); moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE); if ( SymGetModuleInfo( m_hProcess, (DWORD)address, &moduleInfo ) ) { // Note. IMAGEHLP_MODULE::ModuleName seems to be hardcoded as 32 char/wchar_t (VS2008). #ifdef UNICODE int len = _tcslen(lpszModule) + 1 ; char dest[1024] ; WideCharToMultiByte( CP_ACP, 0, lpszModule, -1, dest, len, NULL, NULL ); strcpy_s(moduleInfo.ModuleName, 32, dest); // ANSI! #else strcpy_s(moduleInfo.ModuleName, 32, lpszModule); #endif ret = TRUE; } else { _tcscpy_s( lpszModule, BufSizeTCHARs, MLD_TRACEINFO_NOSYMBOL); } return ret; }
VOID DumpSymbols( PDEBUGPACKET dp ) { IMAGEHLP_MODULE mi; if (SymGetModuleInfo( dp->hProcess, 0, &mi )) { lprintf( MSG_SYMBOL_TABLE ); do { lprintfs( "%s\r\n\r\n", mi.ImageName ); SymEnumerateSymbols( dp->hProcess, mi.BaseOfImage, SymbolEnumFunc, NULL ); } while( SymGetModuleInfo( dp->hProcess, (DWORD)-1, &mi )); } }
BOOL ProcessModuleLoad ( PDEBUGPACKET dp, LPDEBUG_EVENT de ) /*++ Routine Description: Process all module load debug events, create process & dll load. The purpose is to allocate a MODULEINFO structure, fill in the necessary values, and load the symbol table. Arguments: dp - pointer to a debug packet de - pointer to a debug event structure Return Value: TRUE - everything worked FALSE - we're hosed --*/ { HANDLE hFile; DWORD dwBaseOfImage; LPSTR SymbolPath; if (de->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) { hFile = de->u.CreateProcessInfo.hFile; dwBaseOfImage = (DWORD)de->u.CreateProcessInfo.lpBaseOfImage; dp->hProcess = de->u.CreateProcessInfo.hProcess; dp->dwProcessId = de->dwProcessId; SymInitialize( dp->hProcess, NULL, FALSE ); SymbolPath = GetSymbolSearchPath(); SymSetSearchPath( dp->hProcess, SymbolPath ); free( SymbolPath ); } else if (de->dwDebugEventCode == LOAD_DLL_DEBUG_EVENT) { hFile = de->u.LoadDll.hFile; dwBaseOfImage = (DWORD)de->u.LoadDll.lpBaseOfDll; } if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) { return FALSE; } if (!SymLoadModule( dp->hProcess, hFile, NULL, NULL, dwBaseOfImage, 0 )) { return FALSE; } else { if (de->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) { IMAGEHLP_MODULE mi; if (SymGetModuleInfo( dp->hProcess, dwBaseOfImage, &mi )) { strcpy( szApp, mi.ImageName ); } } } return TRUE; }
static BOOL CALLBACK mod_loader_cb(PSTR mod_name, DWORD base, void* ctx) { struct mod_loader_info* mli = (struct mod_loader_info*)ctx; if (!strcmp(mod_name, "<wine-loader>")) { if (SymGetModuleInfo(mli->handle, base, mli->imh_mod)) return FALSE; /* stop enum */ } return TRUE; }
DWORD CCallStackTrace::ConvertAddress(HANDLE hProcess, DWORD address, LPSTR output_buffer) { char* current_pointer = output_buffer; IMAGEHLP_MODULE imagehlp_module; memset(&imagehlp_module, 0, sizeof(imagehlp_module)); imagehlp_module.SizeOfStruct = sizeof(imagehlp_module); if ( SymGetModuleInfo(hProcess, address, &imagehlp_module) != FALSE ) { char * image_name = strrchr(imagehlp_module.ImageName, '\\'); if ( image_name != NULL ) image_name += 1; else image_name = imagehlp_module.ImageName; current_pointer += sprintf(current_pointer, "%s : ", image_name); } else { current_pointer += sprintf(current_pointer, "<unknown module> : "); } DWORD displacement; char temp[0x11c]; IMAGEHLP_SYMBOL * imagehlp_symbol = (IMAGEHLP_SYMBOL *)temp; memset(imagehlp_symbol, 0, sizeof(temp)); imagehlp_symbol->SizeOfStruct = 24; imagehlp_symbol->Address = address; imagehlp_symbol->MaxNameLength = 0x104; if ( SymGetSymFromAddr(hProcess, address, &displacement, imagehlp_symbol) != FALSE ) { current_pointer += sprintf(current_pointer, "%s() ", imagehlp_symbol->Name); IMAGEHLP_LINE imagehlp_line; memset(&imagehlp_line, 0, sizeof(imagehlp_line)); imagehlp_line.SizeOfStruct = sizeof(IMAGEHLP_LINE); if ( SymGetLineFromAddr(hProcess, address, &displacement, &imagehlp_line) != FALSE ) { current_pointer += sprintf(current_pointer, "// %s(%i)", imagehlp_line.FileName, imagehlp_line.LineNumber); } } else { current_pointer += sprintf(current_pointer, "<unknown symbol>"); } current_pointer += sprintf(current_pointer, "\r\n"); return current_pointer - output_buffer; }
DWORD __stdcall CCallStackTrace::GetModuleBase(HANDLE hProcess, DWORD address) { IMAGEHLP_MODULE imagehlp_module; MEMORY_BASIC_INFORMATION memory_basic_information; char module_file_name[260]; DWORD module_file_name_length; HANDLE file_handle; char * image_name; imagehlp_module.SizeOfStruct = sizeof(imagehlp_module); if ( SymGetModuleInfo(hProcess, address, &imagehlp_module) == TRUE ) { return imagehlp_module.BaseOfImage; } if ( VirtualQueryEx(hProcess, (LPCVOID)address, &memory_basic_information, sizeof(memory_basic_information)) == FALSE ) { return 0; } module_file_name_length = GetModuleFileName((HMODULE)memory_basic_information.AllocationBase, module_file_name, sizeof(module_file_name)); if ( module_file_name_length ) { file_handle = CreateFile(module_file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); } else { file_handle = NULL; } image_name = NULL; if ( module_file_name_length > 0 ) { image_name = module_file_name; } else { image_name = NULL; } SymLoadModule(hProcess, file_handle, image_name, 0, (DWORD)memory_basic_information.AllocationBase, 0); return (DWORD)memory_basic_information.AllocationBase; }
static void stack_print_addr_and_args(int nf) { char buffer[sizeof(SYMBOL_INFO) + 256]; SYMBOL_INFO* si = (SYMBOL_INFO*)buffer; IMAGEHLP_STACK_FRAME ihsf; IMAGEHLP_LINE64 il; IMAGEHLP_MODULE im; DWORD64 disp64; print_bare_address(&dbg_curr_thread->frames[nf].addr_pc); stack_get_frame(nf, &ihsf); /* grab module where symbol is. If we don't have a module, we cannot print more */ im.SizeOfStruct = sizeof(im); if (!SymGetModuleInfo(dbg_curr_process->handle, ihsf.InstructionOffset, &im)) return; si->SizeOfStruct = sizeof(*si); si->MaxNameLen = 256; if (SymFromAddr(dbg_curr_process->handle, ihsf.InstructionOffset, &disp64, si)) { struct sym_enum se; DWORD disp; dbg_printf(" %s", si->Name); if (disp64) dbg_printf("+0x%lx", (DWORD_PTR)disp64); SymSetContext(dbg_curr_process->handle, &ihsf, NULL); se.first = TRUE; se.frame = ihsf.FrameOffset; dbg_printf("("); SymEnumSymbols(dbg_curr_process->handle, 0, NULL, sym_enum_cb, &se); dbg_printf(")"); il.SizeOfStruct = sizeof(il); if (SymGetLineFromAddr64(dbg_curr_process->handle, ihsf.InstructionOffset, &disp, &il)) dbg_printf(" [%s:%u]", il.FileName, il.LineNumber); dbg_printf(" in %s", im.ModuleName); } else dbg_printf(" in %s (+0x%lx)", im.ModuleName, (DWORD_PTR)(ihsf.InstructionOffset - im.BaseOfImage)); }
void StackTraceUtils::Impl::getSymbolName( StackTraceHandler &handler, void *address) { #ifdef _WIN64 typedef DWORD64 DWORDX; #else typedef DWORD DWORDX; #endif HANDLE process = ::GetCurrentProcess(); if (!process) { handler("", -1); return; } IMAGEHLP_MODULE imageModule = { sizeof(IMAGEHLP_MODULE) }; IMAGEHLP_LINE line ={ sizeof(IMAGEHLP_LINE) }; DWORDX dispSym = 0; DWORD dispLine = 0; char symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_PATH] = {0}; IMAGEHLP_SYMBOL * imageSymbol = (IMAGEHLP_SYMBOL*) symbolBuffer; imageSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); imageSymbol->MaxNameLength = MAX_PATH; const DWORDX intAddress = static_cast<DWORDX>(reinterpret_cast<uintptr_t>(address)); if(!SymGetModuleInfo(process, intAddress, &imageModule)) { util::detail::RawNumberFormatter formatter; handler(formatter(static_cast<uint64_t>(intAddress)), -1); } else if(!SymGetSymFromAddr(process, intAddress, &dispSym, imageSymbol)) { util::detail::RawNumberFormatter formatter; handler(formatter(static_cast<uint64_t>(intAddress)), -1); } else if(!SymGetLineFromAddr(process, intAddress, &dispLine, &line)) { handler(imageSymbol->Name, -1); } else { handler(imageSymbol->Name, line.LineNumber); } }
// Get the module name from a given address static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule ) { BOOL ret = FALSE; IMAGEHLP_MODULE moduleInfo; ::ZeroMemory( &moduleInfo, sizeof(moduleInfo) ); moduleInfo.SizeOfStruct = sizeof(moduleInfo); if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) ) { // Got it! PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule ); ret = TRUE; } else // Not found :( _tcscpy( lpszModule, _T("?") ); return ret; }
size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size) { if (size) *moduleName = 0; { const char* sourceName; IMAGEHLP_MODULE moduleInfo = { sizeof (moduleInfo) }; if (!SymGetModuleInfo(GetSymHandle(), CheckAddress(address), &moduleInfo)) { return 0; } sourceName = strrchr(moduleInfo.ImageName, '\\'); if (sourceName) { sourceName++; } else { sourceName = moduleInfo.ImageName; } if (size) { strncpy(moduleName, sourceName, size)[size - 1] = 0; } return strlen(sourceName); } }
static DWORD __stdcall GetModBase( HANDLE hProcess, DWORD dwAddr ) #endif { // Check in the symbol engine first. IMAGEHLP_MODULE stIHM; // This is what the MFC stack trace routines forgot to do so their // code will not get the info out of the symbol engine. stIHM.SizeOfStruct = sizeof( IMAGEHLP_MODULE ); if( SymGetModuleInfo( hProcess, dwAddr, &stIHM ) ) { return ( stIHM.BaseOfImage ); } else { // Let's go fishing. MEMORY_BASIC_INFORMATION stMBI; if( 0 != VirtualQueryEx( hProcess, (LPCVOID) dwAddr, &stMBI, sizeof( stMBI ) ) ) { // Try and load it. DWORD dwNameLen = 0; TCHAR szFile[MAX_PATH]; memset( szFile, 0, sizeof( szFile ) ); HANDLE hFile = NULL; dwNameLen = GetModuleFileName( (HINSTANCE) stMBI.AllocationBase, szFile, MAX_PATH ); if( 0 != dwNameLen ) { hFile = CreateFile( szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); SymLoadModule( hProcess, hFile, (PSTR) ( dwNameLen ? szFile : NULL ), NULL, (ULONG_PTR) stMBI.AllocationBase, 0 ); CloseHandle( hFile ); } return ( (ULONG_PTR) stMBI.AllocationBase ); } } return ( 0 ); }
BOOL CmdDisplayModules( LPSTR CmdBuf, HANDLE hProcess, HANDLE hThread, PEXCEPTION_RECORD ExceptionRecord ) { IMAGEHLP_MODULE ModuleInfo; printf( "\n" ); printf( "Address Size Name Symbol Status\n" ); printf( "------------------------------------------------------------------\n" ); for (ULONG i=0; i<MAX_DLLS; i++) { if (DllList[i].BaseAddress && !DllList[i].Unloaded) { printf( "0x%08x 0x%08x %16s\t", DllList[i].BaseAddress, DllList[i].Size, DllList[i].Name ); if (SymGetModuleInfo( hProcess, DllList[i].BaseAddress, &ModuleInfo )) { if (ModuleInfo.SymType != SymNone) { printf( "(symbols loaded)\t" ); } else { printf( "(symbols *NOT* loaded)\t" ); } printf( "%s\t", ModuleInfo.LoadedImageName ); } else { printf( "(symbols *NOT* loaded)\t" ); } printf( "\n" ); } } printf( "\n" ); return TRUE; }
void StackTrace::trace(ProfileData &data){ CaptureStackBackTrace(0, backtraceSize, backtrace, &hash); auto stk = data.stacks.find(hash); if (stk != data.stacks.end()) { idx = stk->second; return; }; HANDLE process = GetCurrentProcess(); const int MAXSYMBOLNAME = 128 - sizeof(IMAGEHLP_SYMBOL); char symbol64_buf[sizeof(IMAGEHLP_SYMBOL) + MAXSYMBOLNAME] = { 0 }; IMAGEHLP_SYMBOL *symbol = reinterpret_cast<IMAGEHLP_SYMBOL*>(symbol64_buf); symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); symbol->MaxNameLength = MAXSYMBOLNAME - 1; IMAGEHLP_MODULE module; module.SizeOfStruct = sizeof(IMAGEHLP_MODULE); for (size_t i = backtraceSize - 1; i > 0; --i){ int fileidx = 0; int linenum = 0; int symidx = 0; int modidx = 0; if (backtrace[i]){ // Output stack frame symbols if available. if (SymGetSymFromAddr(process, (DWORD64)backtrace[i], 0, symbol)){ std::string symbol_name = symbol->Name; if (strncmp("mallocHook<", symbol->Name, 11) == 0) { symbol_name = "malloc"; } if (strncmp("freeHook<", symbol->Name, 9) == 0) { symbol_name = "free"; } symidx = data.intern(symbol_name); if (SymGetModuleInfo(process, (DWORD64)backtrace[i], &module)) { modidx = data.intern(module.ModuleName); } // Output filename + line info if available. IMAGEHLP_LINE lineSymbol = { 0 }; lineSymbol.SizeOfStruct = sizeof(IMAGEHLP_LINE); DWORD displacement; if (SymGetLineFromAddr(process, (DWORD64)backtrace[i], &displacement, &lineSymbol)){ fileidx = data.intern(lineSymbol.FileName); linenum = lineSymbol.LineNumber; } } fprintf(data.output, "i %lx %lx", symbol->Address, modidx); if (symidx || fileidx) { fprintf(data.output, " %lx", symidx); if (fileidx) fprintf(data.output, " %lx %lx", fileidx, linenum); } fprintf(data.output, "\n"); } else{ continue; } } idx = data.instGraph.index((intptr_t*)backtrace, data.output); data.stacks.insert(std::make_pair(hash, idx)); }
static BOOL ResolveSymbol(HANDLE hProcess, DWORD dwAddress, SYMBOL_INFO &siSymbol) { BOOL fRetval = TRUE; siSymbol.dwAddress = dwAddress; union { CHAR rgchSymbol[sizeof(IMAGEHLP_SYMBOL) + 255]; IMAGEHLP_SYMBOL sym; }; CHAR szUndec[256]; CHAR szWithOffset[256]; LPSTR pszSymbol = NULL; IMAGEHLP_MODULE mi; memset(&siSymbol, 0, sizeof(SYMBOL_INFO)); mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE); if (!SymGetModuleInfo(hProcess, dwAddress, &mi)) lstrcpyA(siSymbol.szModule, "<no module>"); else { LPSTR pszModule = strchr(mi.ImageName, '\\'); if (pszModule == NULL) pszModule = mi.ImageName; else pszModule++; lstrcpynA(siSymbol.szModule, pszModule, _countof(siSymbol.szModule)); lstrcatA(siSymbol.szModule, "! "); } __try { sym.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); sym.Address = dwAddress; sym.MaxNameLength = 255; if (SymGetSymFromAddr(hProcess, dwAddress, &(siSymbol.dwOffset), &sym)) { pszSymbol = sym.Name; if (UnDecorateSymbolName(sym.Name, szUndec, _countof(szUndec), UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS)) { pszSymbol = szUndec; } else if (SymUnDName(&sym, szUndec, _countof(szUndec))) { pszSymbol = szUndec; } if (siSymbol.dwOffset != 0) { wsprintfA(szWithOffset, "%s + %d bytes", pszSymbol, siSymbol.dwOffset); pszSymbol = szWithOffset; } } else pszSymbol = "<no symbol>"; } __except (EXCEPTION_EXECUTE_HANDLER) { pszSymbol = "<EX: no symbol>"; siSymbol.dwOffset = dwAddress - mi.BaseOfImage; } lstrcpynA(siSymbol.szSymbol, pszSymbol, _countof(siSymbol.szSymbol)); return fRetval; }
void StackDumper::ShowStackCore( HANDLE hThread, CONTEXT& c ) { // This makes this code custom for 32-bit windows. There is a technique to find out what // machine type we are running on, but this should do us for a good while. DWORD imageType = IMAGE_FILE_MACHINE_I386; HANDLE hProcess = GetCurrentProcess(); int frameNum; // counts walked frames DWORD offsetFromSymbol; // tells us how far from the symbol we were DWORD symOptions; // symbol handler settings IMAGEHLP_SYMBOL *pSym = (IMAGEHLP_SYMBOL *) malloc( IMGSYMLEN + MAXNAMELEN ); IMAGEHLP_MODULE Module; IMAGEHLP_LINE Line; StrApp strSearchPath; // path to search for symbol tables (I think...JT) achar *tt = 0; STACKFRAME s; // in/out stackframe memset( &s, '\0', sizeof s ); tt = new achar[TTBUFLEN]; if (!tt) return; // Build symbol search path. // Add current directory if (::GetCurrentDirectory( TTBUFLEN, tt ) ) AppendToStaWithSep(strSearchPath, tt); // Add directory containing executable or DLL we are running in. if (::GetModuleFileName( 0, tt, TTBUFLEN ) ) { StrUni stuPath = tt; // convert to Unicode if necessary, allows use of wchars const OLECHAR * pchPath = stuPath.Chars(); const OLECHAR * pch; for (pch = pchPath + wcslen(pchPath) - 1; pch >= pchPath; -- pch ) { // locate the rightmost path separator if ( *pch == L'\\' || *pch == L'/' || *pch == L':' ) break; } // if we found one, p is pointing at it; if not, tt only contains // an exe name (no path), and p points before its first byte if ( pch != pchPath ) // path sep found? { if ( *pch == L':' ) // we leave colons in place ++ pch; if (strSearchPath.Length()) strSearchPath.Append(";"); strSearchPath.Append(pchPath, (pch - pchPath)); } } // environment variable _NT_SYMBOL_PATH if (::GetEnvironmentVariable( _T("_NT_SYMBOL_PATH"), tt, TTBUFLEN )) AppendToStaWithSep(strSearchPath, tt); // environment variable _NT_ALTERNATE_SYMBOL_PATH if (::GetEnvironmentVariable( _T("_NT_ALTERNATE_SYMBOL_PATH"), tt, TTBUFLEN )) AppendToStaWithSep(strSearchPath, tt); // environment variable SYSTEMROOT if (::GetEnvironmentVariable( _T("SYSTEMROOT"), tt, TTBUFLEN )) AppendToStaWithSep(strSearchPath, tt); // Why oh why does SymInitialize() want a writeable string? Surely it doesn't modify it... // The doc clearly says it is an [in] parameter. // Also, there is not a wide character version of this function! StrAnsi staT(strSearchPath); if ( !::SymInitialize( hProcess, const_cast<char *>(staT.Chars()), false ) ) goto LCleanup; // SymGetOptions() symOptions = SymGetOptions(); symOptions |= SYMOPT_LOAD_LINES; symOptions &= ~SYMOPT_UNDNAME; SymSetOptions( symOptions ); // SymSetOptions() // Enumerate modules and tell imagehlp.dll about them. // On NT, this is not necessary, but it won't hurt. EnumAndLoadModuleSymbols( hProcess, GetCurrentProcessId() ); // init STACKFRAME for first call // Notes: AddrModeFlat is just an assumption. I hate VDM debugging. // Notes: will have to be #ifdef-ed for Alphas; MIPSes are dead anyway, // and good riddance. s.AddrPC.Offset = c.Eip; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.Ebp; s.AddrFrame.Mode = AddrModeFlat; memset( pSym, '\0', IMGSYMLEN + MAXNAMELEN ); pSym->SizeOfStruct = IMGSYMLEN; pSym->MaxNameLength = MAXNAMELEN; memset( &Line, '\0', sizeof Line ); Line.SizeOfStruct = sizeof Line; memset( &Module, '\0', sizeof Module ); Module.SizeOfStruct = sizeof Module; offsetFromSymbol = 0; if (!m_pstaDump) { try { m_pstaDump = NewObj StrAnsiBufHuge; } catch (...) { goto LCleanup; } } // If the stack dump gets too big, we remove some entries from near the // middle, and insert a marker. This counts the characters up to the // end of the marker. int ichEndLowHalf; ichEndLowHalf = 0; m_pstaDump->FormatAppend( "\r\n--# FV EIP----- RetAddr- FramePtr StackPtr Symbol\r\n" ); // EberhardB: a stack of 1.000 frames should be enough in most cases; limiting it // prevents a mysterious infinite(?) loop on our build machine. for ( frameNum = 0; frameNum < 1000; ++ frameNum ) { // get next stack frame (StackWalk(), SymFunctionTableAccess(), SymGetModuleBase()) // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can // assume that either you are done, or that the stack is so hosed that the next // deeper frame could not be found. if ( ! StackWalk( imageType, hProcess, hThread, &s, &c, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL ) ) break; // display its contents m_pstaDump->FormatAppend( "%3d %c%c %08x %08x %08x %08x ", frameNum, s.Far? 'F': '.', s.Virtual? 'V': '.', s.AddrPC.Offset, s.AddrReturn.Offset, s.AddrFrame.Offset, s.AddrStack.Offset ); if ( s.AddrPC.Offset == 0 ) { m_pstaDump->Append( "(-nosymbols- PC == 0)\r\n" ); } else { // we seem to have a valid PC char undName[MAXNAMELEN]; // undecorated name //char undFullName[MAXNAMELEN]; // undecorated name with all shenanigans // show procedure info (SymGetSymFromAddr()) if ( ! SymGetSymFromAddr( hProcess, s.AddrPC.Offset, &offsetFromSymbol, pSym ) ) { if ( gle != 487 ) m_pstaDump->FormatAppend( "SymGetSymFromAddr(): gle = %u\r\n", gle ); } else { UnDecorateSymbolName( pSym->Name, undName, MAXNAMELEN, UNDNAME_NAME_ONLY ); //UnDecorateSymbolName( pSym->Name, undFullName, MAXNAMELEN, UNDNAME_COMPLETE ); m_pstaDump->Append( undName ); //if ( offsetFromSymbol != 0 ) // m_pstaDump->FormatAppend( " %+d bytes", offsetFromSymbol ); //m_pstaDump->FormatAppend( "\r\n Sig: %s\r\n", pSym->Name ); //m_pstaDump->FormatAppend( "\r\n Decl: %s\r\n", undFullName ); } // show line number info, NT5.0-method (SymGetLineFromAddr()). If we can't get this function, // or it doesn't work, leave out line number info. if (! g_pfnSymGetLineFromAddr) { StrApp staModName("IMAGEHLP.DLL"); g_pfnSymGetLineFromAddr = (PFNSYMGETLINEFROMADDR) GetProcAddress( GetModuleHandle(staModName.Chars()), "SymGetLineFromAddr"); } if (! g_pfnSymGetLineFromAddr || ! g_pfnSymGetLineFromAddr( hProcess, s.AddrPC.Offset, &offsetFromSymbol, &Line ) ) { if ( g_pfnSymGetLineFromAddr && gle != 487 ) // apparently a magic number indicating not in symbol file. m_pstaDump->FormatAppend( "SymGetLineFromAddr(): gle = %u\r\n", gle ); else m_pstaDump->FormatAppend( " (no line # avail)\r\n"); } else { m_pstaDump->FormatAppend( " %s(%u)\r\n", Line.FileName, Line.LineNumber ); } #ifdef JT_20010626_WantModuleInfo // If we want this info adapt the printf and _snprintf in the following. // show module info (SymGetModuleInfo()) if ( ! SymGetModuleInfo( hProcess, s.AddrPC.Offset, &Module ) ) { m_pstaDump->FormatAppend( "SymGetModuleInfo): gle = %u\r\n", gle ); } else { // got module info OK m_pstaDump->FormatAppend( " Mod: %s[%s], base: 0x%x\r\n Sym: type: ", Module.ModuleName, Module.ImageName, Module.BaseOfImage ); switch ( Module.SymType ) { case SymNone: m_pstaDump->FormatAppend( "-nosymbols-"); break; case SymCoff: m_pstaDump->FormatAppend( "COFF"); break; case SymCv: m_pstaDump->FormatAppend( "CV"); break; case SymPdb: m_pstaDump->FormatAppend( "PDB"); break; case SymExport: m_pstaDump->FormatAppend( "-exported-"); break; case SymDeferred: m_pstaDump->FormatAppend( "-deferred-"); break; case SymSym: m_pstaDump->FormatAppend( "SYM"); break; default: m_pstaDump->FormatAppend( "symtype=%d", (long) Module.SymType); break; } m_pstaDump->FormatAppend( ", file: %s\r\n", Module.LoadedImageName); } // got module info OK #endif // JT_20010626_WantModuleInfo // We don't want to return more than about 10K of info (enough for an email). // This also serves to make sure there's enough room in the buffer for more. // The idea is that we'd like to keep both the top and bottom of the stack. // So we delete frames from the middle until we have less than 10K. if (m_pstaDump->Length() > MAXDUMPLEN) { if (!ichEndLowHalf) { static char * pszGap = "\r\n\r\n\r\n******************Frames skipped here***************\r\n\r\n\r\n"; int cchGap = strlen(pszGap); ichEndLowHalf = FindStartOfFrame(MAXDUMPLEN / 2); // Overwrite some of what's there with the gap marker. The incomplete // frame will be part of what gets deleted. m_pstaDump->Replace(ichEndLowHalf, ichEndLowHalf + cchGap, pszGap, cchGap); ichEndLowHalf += cchGap; } int cchLeave = m_pstaDump->Length(); int ichKeep = ichEndLowHalf; while (cchLeave > MAXDUMPLEN) { int ichKeepT = FindStartOfFrame(ichKeep + 1); cchLeave -= ichKeepT - ichKeep; ichKeep = ichKeepT; } m_pstaDump->Replace(ichEndLowHalf, ichKeep, (char *)NULL, 0); } } // we seem to have a valid PC // no return address means no deeper stackframe if ( s.AddrReturn.Offset == 0 ) { // avoid misunderstandings in the printf() following the loop SetLastError( 0 ); break; } } // for ( frameNum ) if ( gle != 0 ) printf( "\r\nStackWalk(): gle = %u\r\n", gle ); LCleanup: ResumeThread( hThread ); // de-init symbol handler etc. SymCleanup( hProcess ); free( pSym ); delete [] tt; #ifdef DEBUG ::OutputDebugStringA(m_pstaDump->Chars()); #endif }
int getDebugInfo(char* fname) { HANDLE Self; DWORD moduleAddr; IMAGEHLP_MODULE moduleInfo; namesSize = 1; maxDebug = CodeSize + 10000; hasDebug = calloc(maxDebug, sizeof(int)); names = calloc(MAX_NAMES_SIZE,1); nonCode = calloc(MAX_NONCODE_SIZE,sizeof(Sym)); nonCodeCount = 0; Self = GetCurrentProcess(); SymSetOptions(SYMOPT_LOAD_LINES); if(!SymInitialize(Self,NULL,FALSE)) { printf("Failed to initialize Sym \n"); return -1; } printf("Trying to load with base = %08X\n",imageBase); // moduleAddr = SymLoadModule(Self,NULL,fname,NULL,imageBase+BASE_SHIFT,0); moduleAddr = SymLoadModule(Self,NULL,fname,NULL,0,0); if(!moduleAddr) { printf("Error: %n",GetLastError()); return -1; } moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE); if(SymGetModuleInfo(Self,moduleAddr,&moduleInfo)) { printf("ImageSize : %d \n",moduleInfo.ImageSize); printf("NumSyms : %d \n",moduleInfo.NumSyms); printf("SymType : "); switch (moduleInfo.SymType) { case SymNone : printf("No symbols are loaded \n"); break; case SymCoff : printf("COFF symbols \n"); break; case SymCv : printf("CodeView symbols \n"); break; case SymPdb : printf("pdb file \n"); break; case SymExport : printf("Symbols generated from a DLL's export table\n"); break; case SymDeferred : printf("The library has not yet attempted to load symbols.\n"); break; case SymSym : printf(".SYM file \n"); break; default: printf("Unknown value for SymType : %d\n",moduleInfo.SymType); } printf("ModuleName : %s\n",moduleInfo.ModuleName); printf("ImageName : %s\n",moduleInfo.ImageName); printf("LoadedImageName : %s\n",moduleInfo.LoadedImageName); printf("LoadedImageBase : %08X\n",moduleInfo.BaseOfImage); } SymEnumerateSymbols(Self,moduleAddr,SymbolEnumumeration,NULL); SymUnloadModule(Self,moduleAddr); SymCleanup(Self); return 0; }
BOOL CmdBreakPoint( LPSTR CmdBuf, HANDLE hProcess, HANDLE hThread, PEXCEPTION_RECORD ExceptionRecord ) { CHAR BpCmd = tolower(CmdBuf[1]); ULONG Address = 0; PBREAKPOINT_INFO bp; PPROCESS_INFO ThisProcess; ULONG Flags; LPSTR p; LPSTR SymName; ULONG i; IMAGEHLP_MODULE mi; ThisProcess = GetProcessInfo( hProcess ); if (!ThisProcess) { printf( "could not get process information\n" ); return FALSE; } PTHREAD_INFO ThisThread = GetThreadInfo( hProcess, hThread ); if (!ThisThread) { printf( "could not get thread information\n" ); return FALSE; } SKIP_NONWHITE( CmdBuf ); SKIP_WHITE( CmdBuf ); p = CmdBuf; switch ( BpCmd ) { case 'p': Flags = 0; CmdBuf = GetAddress( CmdBuf, &Address ); SymName = (LPSTR) MemAlloc( CmdBuf - p + 16 ); if (!SymName) { printf( "could not allocate memory for bp command\n" ); break; } strncpy( SymName, p, CmdBuf - p ); if (!Address) { Flags = BPF_UNINSTANCIATED; printf( "breakpoint not instanciated\n" ); } bp = SetBreakpoint( ThisProcess, Address, Flags, SymName, UserBpHandler ); MemFree( SymName ); if (!bp) { printf( "could not set breakpoint\n" ); } ThisProcess->UserBpCount += 1; bp->Number = ThisProcess->UserBpCount; SKIP_WHITE( CmdBuf ); if (CmdBuf[0]) { if (CmdBuf[0] == '/') { switch (tolower(CmdBuf[1])) { case 'c': CmdBuf += 3; if (CmdBuf[0] != '\"') { printf( "invalid syntax\n" ); return FALSE; } CmdBuf += 1; p = strchr( CmdBuf, '\"' ); if (!p) { printf( "invalid syntax\n" ); return FALSE; } p[0] = 0; bp->Command = _strdup( CmdBuf ); break; default: break; } } } break; case 'l': for (i=0; i<MAX_BREAKPOINTS; i++) { if (ThisProcess->Breakpoints[i].Number) { ULONG disp = 0; if (ThisProcess->Breakpoints[i].Flags & BPF_WATCH) { printf( "#%d %c%c\t \tWatch\n", ThisProcess->Breakpoints[i].Number, ThisProcess->Breakpoints[i].Flags & BPF_UNINSTANCIATED ? 'U' : 'I', ThisProcess->Breakpoints[i].Flags & BPF_DISABLED ? 'D' : 'E' ); } else if ((ThisProcess->Breakpoints[i].Address != 0) && (ThisProcess->Breakpoints[i].Address != 0xffffffff)) { SymGetModuleInfo( ThisProcess->hProcess, ThisProcess->Breakpoints[i].Address, &mi ); if (SymGetSymFromAddr( ThisProcess->hProcess, ThisProcess->Breakpoints[i].Address, &disp, sym )) { printf( "#%d %c%c\t0x%08x\t%s!%s\n", ThisProcess->Breakpoints[i].Number, ThisProcess->Breakpoints[i].Flags & BPF_UNINSTANCIATED ? 'U' : 'I', ThisProcess->Breakpoints[i].Flags & BPF_DISABLED ? 'D' : 'E', ThisProcess->Breakpoints[i].Address, mi.ModuleName, sym ? sym->Name : "" ); } } else { printf( "#%d %c%c\t \t%s\n", ThisProcess->Breakpoints[i].Number, ThisProcess->Breakpoints[i].Flags & BPF_UNINSTANCIATED ? 'U' : 'I', ThisProcess->Breakpoints[i].Flags & BPF_DISABLED ? 'D' : 'E', ThisProcess->Breakpoints[i].SymName ); } } } break; case 'c': if (!CmdBuf[0]) { printf( "missing breakpoint number\n" ); return FALSE; } if (CmdBuf[0] == '*') { for (i=0; i<MAX_BREAKPOINTS; i++) { if (ThisProcess->Breakpoints[i].Number) { ClearBreakpoint( ThisProcess, &ThisProcess->Breakpoints[i] ); } } return TRUE; } if (isdigit(CmdBuf[0])) { ULONG BpNum = atoi( CmdBuf ); for (i=0; i<MAX_BREAKPOINTS; i++) { if (ThisProcess->Breakpoints[i].Number == BpNum) { ClearBreakpoint( ThisProcess, &ThisProcess->Breakpoints[i] ); return TRUE; } } } printf( "invalid breakpoint number\n" ); return FALSE; case 'd': break; case 'e': break; case 'a': #if defined(_M_IX86) CmdBuf = GetAddress( CmdBuf, &Address ); bp = GetAvailBreakpoint( ThisProcess ); if (!bp) { printf( "could not set breakpoint\n" ); return FALSE; } bp->Address = Address; bp->Handler = UserBpHandler; bp->Flags = BPF_WATCH; ThisProcess->UserBpCount += 1; bp->Number = ThisProcess->UserBpCount; CurrContext.Dr0 = Address; CurrContext.Dr6 = 0x000d0002; SetRegContext( ThisThread->hThread, &CurrContext ); #else printf( "only available on x86\n" ); #endif break; default: break; } return TRUE; }
void backtrace() { static struct sym_t { HANDLE proc; sym_t() { proc = GetCurrentProcess(); SymSetOptions( SYMOPT_DEFERRED_LOADS | // シンボルを参照する必要があるときまで読み込まない SYMOPT_LOAD_LINES | // 行番号情報を読み込む SYMOPT_UNDNAME // すべてのシンボルを装飾されていない形式で表します ); if(!SymInitialize(proc, 0, true)){ throw exception("error : SymInitialize"); } // cout << "<SymInitialize>" << endl; } ~sym_t() { SymCleanup(proc); // cout << "<SymCleanup>" << endl; } } s_sym; array<void*,8> addr; int count = RtlCaptureStackBackTrace(0, addr.size(), &addr[0], 0); cout << "---- BEGIN BACKTRACE ----" << endl; for(int Li = 1; Li < count; ++Li){ auto p = reinterpret_cast<uintptr_t>(addr[Li]); IMAGEHLP_MODULE module; ::memset(&module, 0, sizeof(module)); module.SizeOfStruct = sizeof(module); if(!SymGetModuleInfo(s_sym.proc, p, &module)){ throw exception("error : SymGetModuleInfo"); } char buffer[sizeof(IMAGEHLP_SYMBOL) + MAX_PATH]; ::memset(buffer, 0, sizeof(buffer)); auto symbol = reinterpret_cast<IMAGEHLP_SYMBOL*>(buffer); symbol->SizeOfStruct = sizeof(*symbol); symbol->MaxNameLength = MAX_PATH; DWORDx disp = 0; if(!SymGetSymFromAddr(s_sym.proc, p, &disp, symbol)){ throw exception("error : SymGetSymFromAddr"); } if(!strcmp(symbol->Name, "__tmainCRTStartup")){ break; } string text = "?"; IMAGEHLP_LINE line; ::memset(&line, 0, sizeof(line)); line.SizeOfStruct = sizeof(line); DWORD disp2 = 0; if(!SymGetLineFromAddr(s_sym.proc, p, &disp2, &line)){ line.FileName = "?"; line.LineNumber = 0; text = "?"; } else { text = getline(line.FileName, line.LineNumber); } cout << Li << " : 0x" << hex << setw(sizeof(uintptr_t) * 2) << setfill('0') << p << " : " << module.ModuleName << " : " << symbol->Name << " : " << line.FileName << "(" << dec << line.LineNumber << ")" << " : " << text.c_str() << endl; } cout << "---- END BACKTRACE ----" << endl << endl; }
/* Runs a stack trace * Parameters: * e - The exception information * Returns: * The stack trace with function and line number information */ __inline char *StackTrace(EXCEPTION_POINTERS *e) { static char buffer[5000]; char curmodule[32]; DWORD symOptions, dwDisp, frame; HANDLE hProcess = GetCurrentProcess(); IMAGEHLP_SYMBOL *pSym = MyMallocEx(sizeof(IMAGEHLP_SYMBOL)+500); IMAGEHLP_LINE pLine; IMAGEHLP_MODULE pMod; STACKFRAME Stack; /* Load the stack information */ memset(&Stack, 0, sizeof(Stack)); Stack.AddrPC.Offset = e->ContextRecord->Eip; Stack.AddrPC.Mode = AddrModeFlat; Stack.AddrFrame.Offset = e->ContextRecord->Ebp; Stack.AddrFrame.Mode = AddrModeFlat; Stack.AddrStack.Offset = e->ContextRecord->Esp; Stack.AddrStack.Mode = AddrModeFlat; if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) hProcess = (HANDLE)GetCurrentProcessId(); else hProcess = GetCurrentProcess(); /* Initialize symbol retrieval system */ SymInitialize(hProcess, NULL, TRUE); SymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_UNDNAME); bzero(pSym, sizeof(IMAGEHLP_SYMBOL)+500); pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); pSym->MaxNameLength = 500; bzero(&pLine, sizeof(IMAGEHLP_LINE)); pLine.SizeOfStruct = sizeof(IMAGEHLP_LINE); bzero(&pMod, sizeof(IMAGEHLP_MODULE)); pMod.SizeOfStruct = sizeof(IMAGEHLP_MODULE); /* Retrieve the first module name */ SymGetModuleInfo(hProcess, Stack.AddrPC.Offset, &pMod); strcpy(curmodule, pMod.ModuleName); sprintf(buffer, "\tModule: %s\n", pMod.ModuleName); /* Walk through the stack */ for (frame = 0; ; frame++) { char buf[500]; if (!StackWalk(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &Stack, NULL, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL)) break; SymGetModuleInfo(hProcess, Stack.AddrPC.Offset, &pMod); if (strcmp(curmodule, pMod.ModuleName)) { strcpy(curmodule, pMod.ModuleName); sprintf(buf, "\tModule: %s\n", pMod.ModuleName); strcat(buffer, buf); } SymGetLineFromAddr(hProcess, Stack.AddrPC.Offset, &dwDisp, &pLine); SymGetSymFromAddr(hProcess, Stack.AddrPC.Offset, &dwDisp, pSym); sprintf(buf, "\t\t#%d %s:%d: %s\n", frame, pLine.FileName, pLine.LineNumber, pSym->Name); strcat(buffer, buf); } return buffer; }
PPROFBLK SetupProfiling(LPCTSTR ptchFileName) { PVOID ImageBase; PPROFBLK pProfBlk; PPROFBLK pPrevProfBlk; ULONG ulBlkOff; LPCSTR ptchImageName; TCHAR atchImageName [256]; PIMAGE_NT_HEADERS pImageNtHeader; IMAGEHLP_MODULE ModuleInfo; // Skip directory name if ( (ptchImageName = strrchr(ptchFileName, '\\')) ) ptchImageName++; else ptchImageName = (PTCHAR)ptchFileName; // Make uppercase copy _strupr (strcpy (atchImageName, ptchImageName)); // Don't profile CAP if ( !strcmp (atchImageName, CAPDLL) ) return NULL; // Search prof blk list for matching image name pPrevProfBlk = NULL; ulBlkOff = ulLocProfBlkOff; while (ulBlkOff != 0) { pPrevProfBlk = MKPPROFBLK(ulBlkOff); // If found image, no need to set up new block if (!strcmp((PCHAR)pPrevProfBlk->atchImageName, atchImageName)) return FALSE; ulBlkOff = pPrevProfBlk->ulNxtBlk; } try // Accessing new block can cause an access fault // which will extend the allocation { // Place block at next available offset pProfBlk = MKPPROFBLK(*pulProfBlkBase); // Fill in initial values pProfBlk->ImageBase =0; pProfBlk->CodeStart = 0; pProfBlk->CodeLength = 0; pProfBlk->iSymCnt = 0; pProfBlk->State = BLKSTATE_ASSIGNED; pProfBlk->ulNxtBlk = 0; strcpy ((TCHAR *) pProfBlk->atchImageName, atchImageName); // Link to previous block or initial block offset if (pPrevProfBlk) pPrevProfBlk->ulNxtBlk = *pulProfBlkBase; else ulLocProfBlkOff = *pulProfBlkBase; // Load module symbols ImageBase = GetModuleHandle(ptchImageName); SymLoadModule(hThisProcess, NULL, (LPSTR)ptchFileName, (LPSTR)ptchImageName, (DWORD)ImageBase, 0); if (ImageBase != NULL) { pProfBlk->ImageBase = ImageBase; // Get code start address if ((pImageNtHeader = ImageNtHeader(ImageBase)) != NULL) { pProfBlk->CodeStart = (PULONG)((TCHAR *)ImageBase + pImageNtHeader->OptionalHeader.BaseOfCode); } else { // If can't get code start, use imagebase as next best guess pProfBlk->CodeStart = ImageBase; } #if defined(MIPS) && !defined(MIPS_VC40_INTERFACE) // Enumerate symbols to find adress of _penter fPenterFound = FALSE; SymEnumerateSymbols(hThisProcess, (DWORD)ImageBase, FindPenterCallback, (PVOID)pProfBlk); #endif // MIPS && !MIPS_VC40_INTERFACE // Get module info for symbols count SymGetModuleInfo(hThisProcess, (DWORD)ImageBase, &ModuleInfo); pProfBlk->iSymCnt = ModuleInfo.NumSyms; // Determine location for symbols and symbol names pProfSymb = (PSYMINFO)(&pProfBlk->atchImageName[strlen(atchImageName) + 1]); pProfBlk->ulSym = (PTCHAR)pProfSymb - (PTCHAR)pulProfBlkBase; pcProfSymbName = (PTCHAR)&pProfSymb[ModuleInfo.NumSyms]; // Now enumerate symbols to build up symbol table ulMaxSymbAddr = (ULONG)pProfBlk->CodeStart; SymEnumerateSymbols(hThisProcess, (DWORD)ImageBase, SymbolEnumCallback, (PVOID)pProfBlk); // Set symbol range based on max symbol address encountered if (ulMaxSymbAddr > (ULONG)pProfBlk->CodeStart) pProfBlk->CodeLength = ulMaxSymbAddr - (ULONG)pProfBlk->CodeStart; // Update pointer to available space *pulProfBlkBase = (ULONG)(pcProfSymbName - (PTCHAR)pulProfBlkBase); // Unload the module SymUnloadModule(hThisProcess, (DWORD)ImageBase); // Do any requested import/export patching PatchDll (ptchPatchImports, ptchPatchCallers, bCallersToPatch, atchImageName, ImageBase); } else { // No symbols - Update offset to next free space *pulProfBlkBase = (ULONG)&pProfBlk->atchImageName[strlen(atchImageName) + 1] -(ULONG)pulProfBlkBase; } // ImageBase != NULL } // // + : transfer control to the handler (EXCEPTION_EXECUTE_HANDLER) // 0 : continue search (EXCEPTION_CONTINUE_SEARCH) // - : dismiss exception & continue (EXCEPTION_CONTINUE_EXECUTION) // except ( AccessXcptFilter (GetExceptionCode(), GetExceptionInformation(), COMMIT_SIZE)) { // Should never get here since filter never returns // EXCEPTION_EXECUTE_HANDLER. CapDbgPrint ("CAP: DoDllInitializations() - *LOGIC ERROR* - " "Inside the EXCEPT: (xcpt=0x%lx)\n", GetExceptionCode()); } // end of TRY/EXCEPT return pProfBlk; }
void AddImage( PSZ pszName, PVOID BaseOfDll, ULONG SizeOfImage, ULONG CheckSum, ULONG ProcessId, PSZ pszModuleName, BOOL ForceSymbolLoad ) { PIMAGE_INFO pImageNew; PIMAGE_INFO *pp; UCHAR index = 0; PSZ pszBaseName; PCHAR KernelBaseFileName; HANDLE KernelBaseFileHandle; DWORD BytesWritten; IMAGEHLP_MODULE mi; CHAR buf[256]; ULONG LoadAddress; if (pszName == NULL) { return; } if ((_stricmp( pszName, KERNEL_IMAGE_NAME ) == 0) || (_stricmp( pszName, KERNEL_IMAGE_NAME_MP ) == 0)) { // // rename the image if necessary // if (GetModnameFromImage( (ULONG)BaseOfDll, NULL, buf )) { strcpy( pszName, buf ); } pszModuleName = "NT"; } if (_stricmp( pszName, HAL_IMAGE_FILE_NAME ) == 0) { // // rename the image if necessary // if (GetModnameFromImage( (ULONG)BaseOfDll, NULL, buf )) { strcpy( pszName, buf ); } pszModuleName = "HAL"; } pszBaseName = strchr(pszName,'\0'); while (pszBaseName > pszName) { if (pszBaseName[-1] == '\\' || pszBaseName[-1] == '/' || pszBaseName[-1] == ':') { pszName = pszBaseName; break; } else { pszBaseName -= 1; } } // // search for existing image with same checksum at same base address // if found, remove symbols, but leave image structure intact // pp = &pProcessCurrent->pImageHead; while (pImageNew = *pp) { if (pImageNew->lpBaseOfImage == BaseOfDll) { if (fVerboseOutput) { dprintf("%s: force unload of %s\n", DebuggerName, pImageNew->szImagePath); } SymUnloadModule( pProcessCurrent->hProcess, (ULONG)pImageNew->lpBaseOfImage ); break; } else if (pImageNew->lpBaseOfImage > BaseOfDll) { pImageNew = NULL; break; } pp = &pImageNew->pImageNext; } // if not found, allocate and fill new image structure if (!pImageNew) { for (index=0; index<pProcessCurrent->MaxIndex; index++) { if (pProcessCurrent->pImageByIndex[ index ] == NULL) { pImageNew = calloc(sizeof(IMAGE_INFO),1); break; } } if (!pImageNew) { DWORD NewMaxIndex; PIMAGE_INFO *NewImageByIndex; NewMaxIndex = pProcessCurrent->MaxIndex + 32; if (NewMaxIndex < 0x100) { NewImageByIndex = calloc( NewMaxIndex, sizeof( *NewImageByIndex ) ); } else { NewImageByIndex = NULL; } if (NewImageByIndex == NULL) { dprintf("%s: No room for %s image record.\n", DebuggerName, pszName ); return; } if (pProcessCurrent->pImageByIndex) { memcpy( NewImageByIndex, pProcessCurrent->pImageByIndex, pProcessCurrent->MaxIndex * sizeof( *NewImageByIndex ) ); free( pProcessCurrent->pImageByIndex ); } pProcessCurrent->pImageByIndex = NewImageByIndex; index = (UCHAR) pProcessCurrent->MaxIndex; pProcessCurrent->MaxIndex = NewMaxIndex; pImageNew = calloc(sizeof(IMAGE_INFO),1); if (!pImageNew) { dprintf("%s: Unable to allocate memory for %s symbols.\n", DebuggerName, pszName); return; } } pImageNew->pImageNext = *pp; *pp = pImageNew; pImageNew->index = index; pProcessCurrent->pImageByIndex[ index ] = pImageNew; } // // pImageNew has either the unloaded structure or the newly created one // pImageNew->lpBaseOfImage = BaseOfDll; pImageNew->dwCheckSum = CheckSum; pImageNew->dwSizeOfImage = SizeOfImage; pImageNew->GoodCheckSum = TRUE; strcpy( pImageNew->szImagePath, pszName ); LoadAddress = SymLoadModule( pProcessCurrent->hProcess, NULL, pImageNew->szImagePath, pszModuleName, (ULONG)pImageNew->lpBaseOfImage, pImageNew->dwSizeOfImage ); if (!LoadAddress) { DelImage( pszName, 0, 0 ); return; } if (!pImageNew->lpBaseOfImage) { pImageNew->lpBaseOfImage = (PVOID)LoadAddress; } if (ForceSymbolLoad) { SymLoadModule( pProcessCurrent->hProcess, NULL, NULL, NULL, (ULONG)pImageNew->lpBaseOfImage, 0 ); } if (SymGetModuleInfo( pProcessCurrent->hProcess, (ULONG)pImageNew->lpBaseOfImage, &mi )) { pImageNew->dwSizeOfImage = mi.ImageSize; strcpy( pImageNew->szImagePath, mi.ImageName ); strcpy( pImageNew->szDebugPath, mi.LoadedImageName ); } else { DelImage( pszName, 0, 0 ); return; } if (pszModuleName) { strcpy( pImageNew->szModuleName, pszModuleName ); } else { CreateModuleNameFromPath( pImageNew->szImagePath, pImageNew->szModuleName ); } if (fVerboseOutput) { dprintf( "%s ModLoad: %08lx %08lx %-8s\n", DebuggerName, pImageNew->lpBaseOfImage, (ULONG)(pImageNew->lpBaseOfImage) + pImageNew->dwSizeOfImage, pImageNew->szImagePath ); } }
DWORD ConsoleDebugger( HANDLE hProcess, HANDLE hThread, PEXCEPTION_RECORD ExceptionRecord, BOOL UnexpectedException, LPSTR InitialCommand ) { PPROCESS_INFO ThisProcess; DWORD ContinueStatus = DBG_EXCEPTION_NOT_HANDLED; static CHAR CmdBuf[512]; Stepped = FALSE; if (!ConsoleCreated) { CmdBuf[0] = 0; if (!CreateDebuggerConsole()) { return ContinueStatus; } } ThisProcess = GetProcessInfo( hProcess ); if (!ThisProcess) { printf( "could not get process information\n" ); } if (UnexpectedException) { printf( "\n" ); printf( "*---------------------------------------\n" ); printf( "An unexpected error has occurred\n" ); printf( "Address: 0x%08x\n", ExceptionRecord->ExceptionAddress ); printf( "Error code: 0x%08x\n", ExceptionRecord->ExceptionCode ); printf( "*---------------------------------------\n" ); PrintRegisters(); PrintOneInstruction( hProcess, (ULONG)ExceptionRecord->ExceptionAddress ); } if (BreakInNow) { BreakInNow = FALSE; printf( "*** Initial breakpoint\n\n" ); } // // check to see if any modules need symbols loading // for (ULONG i=0; i<MAX_DLLS; i++) { if (DllList[i].BaseAddress && !DllList[i].Unloaded) { IMAGEHLP_MODULE ModuleInfo; if (!SymGetModuleInfo( hProcess, DllList[i].BaseAddress, &ModuleInfo )) { if (ThisProcess) { printf( "loading 0x%08x %s\n", DllList[i].BaseAddress, DllList[i].Name ); LoadSymbols( ThisProcess, &DllList[i], NULL ); } } } } CurrProcess = hProcess; if (InitialCommand) { strcpy( CmdBuf, InitialCommand ); } while( TRUE ) { if (!InitialCommand) { printf( "ApiMon> " ); scanf( "%[^\n]", CmdBuf ); getchar(); } LPSTR p = CmdBuf; while (p[0]) { LPSTR s = p; while (*s) { if (*s == '\"') { s += 1; while (*s && *s != '\"') { s += 1; } if (*s == '\"') { s += 1; } } if (*s == ';') { break; } s += 1; } if (*s == ';') { s[0] = 0; } else { s = NULL; } switch( tolower(p[0]) ) { case 'q': ExitProcess( 0 ); break; case 'g': ContinueStatus = DBG_CONTINUE; goto exit; case 'k': CmdStackTrace( p, hProcess, hThread, ExceptionRecord ); break; case 'd': CmdDisplayMemory( p, hProcess, hThread, ExceptionRecord ); break; case 'r': if (p[1] == 't') { PrintRegistersFlag = !PrintRegistersFlag; } CmdDisplayRegisters( p, hProcess, hThread, ExceptionRecord ); break; case 'u': CmdDisplayCode( p, hProcess, hThread, ExceptionRecord ); break; case 'b': CmdBreakPoint( p, hProcess, hThread, ExceptionRecord ); break; case 'l': if (tolower(p[1]) == 'm') { CmdDisplayModules( p, hProcess, hThread, ExceptionRecord ); } else if (tolower(p[1]) == 'n') { CmdListNear( p, hProcess, hThread, ExceptionRecord ); } else { goto invalid_command; } break; case 't': if (p[1] == 'r') { PrintRegistersFlag = !PrintRegistersFlag; } if (CmdTrace( p, hProcess, hThread, ExceptionRecord )) { ContinueStatus = DBG_CONTINUE; Stepped = TRUE; goto exit; } break; case 'p': if (p[1] == 'r') { PrintRegistersFlag = !PrintRegistersFlag; } if (CmdStep( p, hProcess, hThread, ExceptionRecord )) { ContinueStatus = DBG_CONTINUE; Stepped = TRUE; goto exit; } break; case 'h': if (tolower(p[1]) == 'e' && tolower(p[2]) == 'l' && tolower(p[3]) == 'p') { CmdDisplayHelp( p, hProcess, hThread, ExceptionRecord ); } break; case '?': { ULONG val = GetExpression( p+1 ); if (!ExprError) { printf( "Evaluate expression: %d = 0x%08x\n", val, val ); } } break; default: invalid_command: printf( "****>>> invalid command\n" ); break; } if (s) { p = s + 1; } else { p += strlen(p); } } } exit: return ContinueStatus; }
//************************************************************************* // Method: GetStackInfo // Description: Gets the call stack for the specified thread // // Parameters: // hThread - the handle to the target thread // threadContext - the context of the target thread // // Return Value: (FrameInfo *) An array containing stack trace data //************************************************************************* SiUtils::SiArray <FrameInfo *> StackWalker::GetStackInfo(HANDLE hThread, CONTEXT &threadContext) { //Clear the frame array of any previous data frameArray.Clear(); DWORD imageType = IMAGE_FILE_MACHINE_I386; HANDLE hProcess = GetCurrentProcess(); int frameNum; // counts walked frames DWORD offsetFromSymbol; // tells us how far from the symbol we were DWORD symOptions; // symbol handler settings IMAGEHLP_SYMBOL *pSym = (IMAGEHLP_SYMBOL *) malloc( IMGSYMLEN + MAXNAMELEN ); char undName[MAXNAMELEN]; // undecorated name char undFullName[MAXNAMELEN]; // undecorated name with all shenanigans IMAGEHLP_MODULE Module; IMAGEHLP_LINE Line; std::string symSearchPath; char *tt = 0, *p; STACKFRAME s; // in/out stackframe memset( &s, '\0', sizeof s ); tt = new char[TTBUFLEN]; // build symbol search path from: symSearchPath = ""; // current directory if (GetCurrentDirectory(TTBUFLEN, tt )) symSearchPath += tt + std::string( ";" ); // dir with executable if (GetModuleFileName(0, tt, TTBUFLEN)) { for ( p = tt + strlen( tt ) - 1; p >= tt; -- p ) { // locate the rightmost path separator if ( *p == '\\' || *p == '/' || *p == ':' ) break; } if ( p != tt ) { if ( *p == ':' ) // we leave colons in place ++ p; *p = '\0'; // eliminate the exe name and last path sep symSearchPath += tt + std::string( ";" ); } } // environment variable _NT_SYMBOL_PATH if ( GetEnvironmentVariable( "_NT_SYMBOL_PATH", tt, TTBUFLEN ) ) symSearchPath += tt + std::string( ";" ); // environment variable _NT_ALTERNATE_SYMBOL_PATH if ( GetEnvironmentVariable( "_NT_ALTERNATE_SYMBOL_PATH", tt, TTBUFLEN ) ) symSearchPath += tt + std::string( ";" ); // environment variable SYSTEMROOT if ( GetEnvironmentVariable( "SYSTEMROOT", tt, TTBUFLEN ) ) symSearchPath += tt + std::string( ";" ); if ( symSearchPath.size() > 0 ) // if we added anything, we have a trailing semicolon symSearchPath = symSearchPath.substr( 0, symSearchPath.size() - 1 ); strncpy( tt, symSearchPath.c_str(), TTBUFLEN ); tt[TTBUFLEN - 1] = '\0'; // if strncpy() overruns, it doesn't add the null terminator // init symbol handler stuff (SymInitialize()) if (!SymInitialize(hProcess, tt, false )) goto cleanup; // SymGetOptions() symOptions = SymGetOptions(); symOptions |= SYMOPT_LOAD_LINES; symOptions &= ~SYMOPT_UNDNAME; SymSetOptions( symOptions ); // Enumerate modules and tell imagehlp.dll about them. enumAndLoadModuleSymbols( hProcess, GetCurrentProcessId() ); // init STACKFRAME for first call // Notes: AddrModeFlat is just an assumption. I hate VDM debugging. // Notes: will have to be #ifdef-ed for Alphas; MIPSes are dead anyway, // and good riddance. s.AddrPC.Offset = threadContext.Eip; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = threadContext.Ebp; s.AddrFrame.Mode = AddrModeFlat; memset( pSym, '\0', IMGSYMLEN + MAXNAMELEN ); pSym->SizeOfStruct = IMGSYMLEN; pSym->MaxNameLength = MAXNAMELEN; memset( &Line, '\0', sizeof Line ); Line.SizeOfStruct = sizeof Line; memset( &Module, '\0', sizeof Module ); Module.SizeOfStruct = sizeof Module; offsetFromSymbol = 0; for ( frameNum = 0; ; ++ frameNum ) { FrameInfo * frameInfo = new FrameInfo(); if (!StackWalk( imageType, hProcess, hThread, &s, &threadContext, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL ) ) break; frameInfo->frameNumber = frameNum; frameInfo->IsWOWFarCall = s.Far; frameInfo->IsVirtualFrame = s.Virtual; frameInfo->Eip = s.AddrPC.Offset; //if 0, the no symbols frameInfo->ReturnAddr = s.AddrReturn.Offset; frameInfo->FramePtr = s.AddrFrame.Offset; frameInfo->StackPtr = s.AddrStack.Offset; if (s.AddrPC.Offset == 0) { //printf( "(-nosymbols- PC == 0)\n" ); } else { // we seem to have a valid PC // show procedure info (SymGetSymFromAddr()) if ( ! SymGetSymFromAddr( hProcess, s.AddrPC.Offset, &offsetFromSymbol, pSym ) ) { /*if ( GetLastError() != 487 ) printf( "SymGetSymFromAddr(): GetLastError() = %lu\n", GetLastError() );*/ } else { // UnDecorateSymbolName() UnDecorateSymbolName( pSym->Name, undName, MAXNAMELEN, UNDNAME_NAME_ONLY ); UnDecorateSymbolName( pSym->Name, undFullName, MAXNAMELEN, UNDNAME_COMPLETE ); strcpy (frameInfo->undecoratedName, undName); strcpy (frameInfo->undecoratedFullName, undFullName); strcpy (frameInfo->signature, pSym->Name ); frameInfo->offsetFromSymbol = offsetFromSymbol; } // show module info (SymGetModuleInfo()) if (SymGetModuleInfo( hProcess, s.AddrPC.Offset, &Module ) ) { strcpy (frameInfo->ModuleName, Module.ModuleName); strcpy (frameInfo->ImageName, Module.ImageName); frameInfo->BaseOfImage = Module.BaseOfImage; } } // we seem to have a valid PC // no return address means no deeper stackframe if ( s.AddrReturn.Offset == 0 ) { // avoid misunderstandings in the printf() following the loop SetLastError( 0 ); break; } this->frameArray.Add (frameInfo); } // for ( frameNum ) cleanup: // de-init symbol handler etc. (SymCleanup()) SymCleanup( hProcess ); free( pSym ); delete [] tt; return frameArray; }
void write_stack_trace(PCONTEXT pContext, TextOutputStream& outputStream) { HANDLE m_hProcess = GetCurrentProcess(); DWORD dwMachineType = 0; CONTEXT context = *pContext; // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag if ( !SymInitialize( m_hProcess, (PSTR)environment_get_app_path(), TRUE ) ) { return; } STACKFRAME sf; memset( &sf, 0, sizeof(sf) ); #ifdef _M_IX86 // Initialize the STACKFRAME structure for the first call. This is only // necessary for Intel CPUs, and isn't mentioned in the documentation. sf.AddrPC.Offset = context.Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = context.Esp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = context.Ebp; sf.AddrFrame.Mode = AddrModeFlat; dwMachineType = IMAGE_FILE_MACHINE_I386; #endif while ( 1 ) { // Get the next stack frame if ( ! StackWalk( dwMachineType, m_hProcess, GetCurrentThread(), &sf, &context, 0, SymFunctionTableAccess, SymGetModuleBase, 0 ) ) break; if ( 0 == sf.AddrFrame.Offset ) // Basic sanity check to make sure break; // the frame is OK. Bail if not. // Get the name of the function for this stack frame entry BYTE symbolBuffer[ sizeof(SYMBOL_INFO) + MAX_SYM_NAME ]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_SYM_NAME; DWORD64 symDisplacement = 0; // Displacement of the input address, // relative to the start of the symbol IMAGEHLP_MODULE module = { sizeof(IMAGEHLP_MODULE) }; if(SymGetModuleInfo(m_hProcess, sf.AddrPC.Offset, &module)) { outputStream << module.ModuleName << "!"; if ( SymFromAddr(m_hProcess, sf.AddrPC.Offset, &symDisplacement, pSymbol)) { char undecoratedName[MAX_SYM_NAME]; UnDecorateSymbolName(pSymbol->Name, undecoratedName, MAX_SYM_NAME, UNDNAME_COMPLETE); outputStream << undecoratedName; outputStream << "("; // Use SymSetContext to get just the locals/params for this frame IMAGEHLP_STACK_FRAME imagehlpStackFrame; imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset; SymSetContext( m_hProcess, &imagehlpStackFrame, 0 ); // Enumerate the locals/parameters EnumerateSymbolsContext context(sf, outputStream); SymEnumSymbols( m_hProcess, 0, 0, EnumerateSymbolsCallback, &context ); outputStream << ")"; outputStream << " + " << Offset(reinterpret_cast<void*>(symDisplacement)); // Get the source line for this stack frame entry IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) }; DWORD dwLineDisplacement; if ( SymGetLineFromAddr( m_hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo ) ) { outputStream << " " << lineInfo.FileName << " line " << Unsigned(lineInfo.LineNumber); } } else { outputStream << Address(reinterpret_cast<void*>(sf.AddrPC.Offset)); } } outputStream << "\n"; } SymCleanup(m_hProcess); return; }