void minidump_write(const char* file, const EXCEPTION_RECORD* rec) { HANDLE hFile; MINIDUMP_EXCEPTION_INFORMATION mei; EXCEPTION_POINTERS ep; DWORD wine_opt; hFile = CreateFile(file, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return; if (rec) { mei.ThreadId = dbg_curr_thread->tid; mei.ExceptionPointers = &ep; ep.ExceptionRecord = (EXCEPTION_RECORD*)rec; ep.ContextRecord = &dbg_context; mei.ClientPointers = FALSE; } /* this is a wine specific options to return also ELF modules in the * dumping */ SymSetOptions((wine_opt = SymGetOptions()) | 0x40000000); MiniDumpWriteDump(dbg_curr_process->handle, dbg_curr_process->pid, hFile, MiniDumpNormal/*|MiniDumpWithDataSegs*/, rec ? &mei : NULL, NULL, NULL); SymSetOptions(wine_opt); CloseHandle(hFile); }
enum dbg_start tgt_module_load(const char* name, BOOL keep) { DWORD opts = SymGetOptions(); HANDLE hDummy = (HANDLE)0x87654321; enum dbg_start ret = start_ok; WCHAR* nameW; unsigned len; SymSetOptions((opts & ~(SYMOPT_UNDNAME|SYMOPT_DEFERRED_LOADS)) | SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | 0x40000000); if (!dbg_init(hDummy, NULL, FALSE)) return start_error_init; len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0); nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); if (!nameW) { ret = start_error_init; keep = FALSE; } else { len = MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, len); if (!dbg_load_module(hDummy, NULL, nameW, 0, 0)) { ret = start_error_init; keep = FALSE; } HeapFree(GetProcessHeap(), 0, nameW); } if (keep) { dbg_printf("Non supported mode... errors may occur\n" "Use at your own risks\n"); SymSetOptions(SymGetOptions() | 0x40000000); dbg_curr_process = dbg_add_process(&be_process_module_io, 1, hDummy); dbg_curr_pid = 1; dbg_curr_thread = dbg_add_thread(dbg_curr_process, 2, NULL, NULL); /* FIXME: missing thread creation, fetching frames, restoring dbghelp's options... */ } else { SymCleanup(hDummy); SymSetOptions(opts); } return ret; }
// Initializes the symbol files BOOL CallStack::initSymInfo( TCHAR* lpszUserSymbolPath) { TCHAR lpszSymbolPath[MLD_MAX_NAME_LENGTH]; DWORD symOptions = SymGetOptions(); symOptions |= SYMOPT_LOAD_LINES; symOptions &= ~SYMOPT_UNDNAME; SymSetOptions( symOptions ); // Get the search path for the symbol files symbolPaths( lpszSymbolPath, MLD_MAX_NAME_LENGTH); // if (lpszUserSymbolPath) { _tcscat_s(lpszSymbolPath, MLD_MAX_NAME_LENGTH, _T(";")); _tcscat_s(lpszSymbolPath, MLD_MAX_NAME_LENGTH, lpszUserSymbolPath); } #ifdef UNICODE int len = _tcslen(lpszSymbolPath) + 1 ; char dest[1024] ; WideCharToMultiByte( CP_ACP, 0, lpszSymbolPath, -1, dest, len, NULL, NULL ); BOOL bret = SymInitialize( GetCurrentProcess(), dest, TRUE); #else BOOL bret = SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE) ; #endif return bret ; }
void dbg_set_option(const char* option, const char* val) { if (!strcasecmp(option, "module_load_mismatched")) { DWORD opt = SymGetOptions(); if (!val) dbg_printf("Option: module_load_mismatched %s\n", opt & SYMOPT_LOAD_ANYTHING ? "true" : "false"); else if (!strcasecmp(val, "true")) opt |= SYMOPT_LOAD_ANYTHING; else if (!strcasecmp(val, "false")) opt &= ~SYMOPT_LOAD_ANYTHING; else { dbg_printf("Syntax: module_load_mismatched [true|false]\n"); return; } SymSetOptions(opt); } else if (!strcasecmp(option, "symbol_picker")) { if (!val) dbg_printf("Option: symbol_picker %s\n", symbol_current_picker == symbol_picker_interactive ? "interactive" : "scoped"); else if (!strcasecmp(val, "interactive")) symbol_current_picker = symbol_picker_interactive; else if (!strcasecmp(val, "scoped")) symbol_current_picker = symbol_picker_scoped; else { dbg_printf("Syntax: symbol_picker [interactive|scoped]\n"); return; } } else dbg_printf("Unknown option '%s'\n", option); }
/* ================== Sym_Init ================== */ void Sym_Init( long addr ) { TCHAR moduleName[MAX_STRING_CHARS]; TCHAR modShortNameBuf[MAX_STRING_CHARS]; MEMORY_BASIC_INFORMATION mbi; if ( lastAllocationBase != -1 ) { Sym_Shutdown(); } VirtualQuery( (void*)addr, &mbi, sizeof(mbi) ); GetModuleFileName( (HMODULE)mbi.AllocationBase, moduleName, sizeof( moduleName ) ); _splitpath( moduleName, NULL, NULL, modShortNameBuf, NULL ); lastModule = modShortNameBuf; processHandle = GetCurrentProcess(); if ( !SymInitialize( processHandle, NULL, FALSE ) ) { return; } if ( !SymLoadModule( processHandle, NULL, moduleName, NULL, (DWORD)mbi.AllocationBase, 0 ) ) { SymCleanup( processHandle ); return; } SymSetOptions( SymGetOptions() & ~SYMOPT_UNDNAME ); lastAllocationBase = (DWORD) mbi.AllocationBase; }
EXTERN_C DWORD SetSymOptions(BOOL fDebug) { DWORD dwSymOptions = SymGetOptions(); // We have more control calling UnDecorateSymbolName directly Also, we // don't want DbgHelp trying to undemangle MinGW symbols (e.g., from DLL // exports) behind our back (as it will just strip the leading underscore.) if (0) { dwSymOptions |= SYMOPT_UNDNAME; } else { dwSymOptions &= ~SYMOPT_UNDNAME; } dwSymOptions |= SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST; if (TRUE) { dwSymOptions |= SYMOPT_DEFERRED_LOADS; } if (fDebug) { dwSymOptions |= SYMOPT_DEBUG; } #ifdef _WIN64 dwSymOptions |= SYMOPT_INCLUDE_32BIT_MODULES; #endif return SymSetOptions(dwSymOptions); }
bool CPEDebug::Initialize() { if (m_fIsInitialized) return true; // nur einmal initialisieren else if (m_fTriedToInitialize) return false; // schon mal versucht, jedoch fehlgeschlagen m_fTriedToInitialize = true; // Since the largest symbol that the MS code generators can handle // is 256 that is all that is needed. ATLTRY(m_pSymbol = (IMAGEHLP_SYMBOL *)new BYTE [sizeof(IMAGEHLP_SYMBOL) + 256]); if (NULL == m_pSymbol) return false; // SymbolEngine initialisieren if (m_SymEngine.SymInitialize (GetCurrentProcess(), NULL, TRUE)) { // Set the symbol engine to load line information. This must be // because the symbol engine does not load source-lines by default. // I also turn on the OMAP lookups so that the super-special OMAP // moved blocks will get looked at as well. Trust me, don't ask. SymSetOptions (SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST); m_fIsInitialized = true; return true; } return false; }
BOOL GetSymFromAddr(HANDLE hProcess, DWORD64 dwAddress, LPSTR lpSymName, DWORD nSize) { PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)malloc(sizeof(SYMBOL_INFO) + nSize * sizeof(char)); DWORD64 dwDisplacement = 0; // Displacement of the input address, relative to the start of the symbol BOOL bRet; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = nSize; DWORD dwOptions = SymGetOptions(); bRet = SymFromAddr(hProcess, dwAddress, &dwDisplacement, pSymbol); if (bRet) { // Demangle if not done already if ((dwOptions & SYMOPT_UNDNAME) || UnDecorateSymbolName(pSymbol->Name, lpSymName, nSize, UNDNAME_NAME_ONLY) == 0) { strncpy(lpSymName, pSymbol->Name, nSize); } } free(pSymbol); return bRet; }
BOOL InitDbgHelp( VOID) { static const char *pszMsSymbolServer = "srv**symbols*http://msdl.microsoft.com/download/symbols"; DWORD Options; /* Save current process ;-) */ ghProcess = GetCurrentProcess(); /* Initialize dbghelp */ if (!SymInitialize(ghProcess, 0, FALSE)) { error("SymInitialize() failed."); return FALSE; } /* Set options */ Options = SymGetOptions(); Options |= SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_DEBUG;// | SYMOPT_NO_PROMPTS; Options &= ~SYMOPT_DEFERRED_LOADS; SymSetOptions(Options); /* Test if we can reach the MS symbol server */ if (!SymSrvIsStore(ghProcess, pszMsSymbolServer)) { error("Failed to connect to symbol server."); return FALSE; } /* Set MS symbol server as symbol search path */ SymSetSearchPath(ghProcess, pszMsSymbolServer); return TRUE; }
void loadNativeDemangler() { // ensure we load line number information when we load // modules, and give us mangled names DWORD dwOpts = SymGetOptions(); dwOpts &= ~(SYMOPT_UNDNAME); dwOpts |= SYMOPT_LOAD_LINES; dwOpts &= ~(SYMOPT_DEFERRED_LOADS); SymSetOptions(dwOpts); }
// Initializes the symbol files BOOL InitSymInfo( PCSTR lpszInitialSymbolPath ) { CHAR lpszSymbolPath[BUFFERSIZE]; DWORD symOptions = SymGetOptions(); symOptions |= SYMOPT_LOAD_LINES; symOptions &= ~SYMOPT_UNDNAME; SymSetOptions( symOptions ); InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath ); return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE); }
BOOL WINAPI MgwSymFromAddr(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol) { struct find_dwarf_info info; DWORD dwOptions = SymGetOptions(); if (mgwhelp_find_symbol(hProcess, Address, &info)) { char *output_buffer = NULL; if (dwOptions & SYMOPT_UNDNAME) { output_buffer = demangle(info.functionname, UNDNAME_NAME_ONLY); } if (output_buffer) { strncpy(Symbol->Name, output_buffer, Symbol->MaxNameLen); free(output_buffer); } else { strncpy(Symbol->Name, info.functionname, Symbol->MaxNameLen); } if (Displacement) { /* TODO */ *Displacement = 0; } return TRUE; } struct mgwhelp_module *module; DWORD64 Offset; module = mgwhelp_find_module(hProcess, Address, &Offset); if (module && module->lpFileBase) { if (pe_find_symbol(module->lpFileBase, Offset, Symbol->MaxNameLen, Symbol->Name, Displacement)) { char *output_buffer = NULL; if (dwOptions & SYMOPT_UNDNAME) { output_buffer = demangle(Symbol->Name, UNDNAME_NAME_ONLY); } if (output_buffer) { strncpy(Symbol->Name, output_buffer, Symbol->MaxNameLen); free(output_buffer); } return TRUE; } } return SymFromAddr(hProcess, Address, Displacement, Symbol); }
CallStack::CallStack() { hProcess = GetCurrentProcess(); DWORD dwOptions = SymGetOptions(); dwOptions |= SYMOPT_LOAD_LINES; dwOptions |= SYMOPT_DEBUG; if (!loaded) { if (SymSetOptions(dwOptions) == 0) throw error<const char*>("SymSetOptions failed", __FILE__, __LINE__); if (SymInitialize(GetCurrentProcess(), NULL, TRUE) == FALSE) throw error<const char*>("SymInitialize failed", __FILE__, __LINE__); if (!loadAllModules()) throw error<const char*>("loadAllModules failed", __FILE__, __LINE__); loaded = true; } }
void InitSymbols(void) { if (!symbolsinit) { DWORD dwOptions = SymGetOptions(); SymSetOptions(dwOptions | SYMOPT_LOAD_LINES); BOOL blah = SymInitialize(GetCurrentProcess(), NULL, TRUE); assert(blah); symbolsinit = true; } }
static HANDLE GetSymHandle(void) { static HANDLE symHandle = NULL; if (!symHandle) { BOOL bRet = SymInitialize(symHandle = GetCurrentProcess(), NULL, FALSE); if (bRet) { DWORD dwOptions = SymGetOptions(); dwOptions &= ~SYMOPT_UNDNAME; dwOptions |= SYMOPT_LOAD_LINES; SymSetOptions(dwOptions); } } return symHandle; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // const char* USER_SYMBOL_SEARCH_PATH = "http://msdl.microsoft.com/download/symbols"; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SymEngine::Init() { if (!isInitialized) { previousOptions = SymGetOptions(); memset(previousSearchPath, 0, MAX_SEARCH_PATH_LENGTH); SymGetSearchPath(hProcess, previousSearchPath, MAX_SEARCH_PATH_LENGTH); SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_LOAD_ANYTHING); if (!SymInitialize(hProcess, NULL, TRUE)) { needRestorePreviousSettings = true; SymCleanup(hProcess); if (SymInitialize(hProcess, NULL, TRUE)) isInitialized = true; } else { isInitialized = true; } } }
void ini_symbols_lib(void) { static ContextEventListener ctx_listener = { NULL, event_context_exited, }; static MemoryMapEventListener map_listener = { event_module_loaded, NULL, event_module_unloaded }; add_context_event_listener(&ctx_listener, NULL); add_memory_map_event_listener(&map_listener, NULL); SymSetOptions(SymGetOptions() | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); context_extension_offset = context_extension(sizeof(ContextExtensionWinSym)); }
BOOL dbg_get_debuggee_info(HANDLE hProcess, IMAGEHLP_MODULE64* imh_mod) { struct mod_loader_info mli; DWORD opt; /* this will resynchronize builtin dbghelp's internal ELF module list */ SymLoadModule(hProcess, 0, 0, 0, 0, 0); mli.handle = hProcess; mli.imh_mod = imh_mod; imh_mod->SizeOfStruct = sizeof(*imh_mod); imh_mod->BaseOfImage = 0; /* this is a wine specific options to return also ELF modules in the * enumeration */ SymSetOptions((opt = SymGetOptions()) | 0x40000000); SymEnumerateModules64(hProcess, mod_loader_cb, (void*)&mli); SymSetOptions(opt); return imh_mod->BaseOfImage != 0; }
void symbol_info(const char* str) { char buffer[512]; DWORD opt; if (strlen(str) + 3 >= sizeof(buffer)) { dbg_printf("Symbol too long (%s)\n", str); return; } buffer[0] = '*'; buffer[1] = '!'; strcpy(&buffer[2], str); /* 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, symbols_info_cb, NULL); SymSetOptions(opt); }
static void loadModule(HANDLE hProcess, HANDLE hFile, PCSTR pszImageName, LPVOID lpBaseOfDll) { bool deferred = SymGetOptions() & SYMOPT_DEFERRED_LOADS; // We must pass DllSize for deferred symbols to work correctly // https://groups.google.com/forum/#!topic/comp.os.ms-windows.programmer.win32/ulkwYhM3020 DWORD DllSize = 0; if (deferred) { DllSize = getModuleSize(hProcess, lpBaseOfDll); } if (!SymLoadModuleEx(hProcess, hFile, pszImageName, NULL, (UINT_PTR)lpBaseOfDll, DllSize, NULL, 0)) { OutputDebug("warning: SymLoadModule64 failed: 0x%08lx\n", GetLastError()); } // DbgHelp keeps an copy of hFile, and closing the handle here may cause // CBA_DEFERRED_SYMBOL_LOAD_PARTIAL events. if (hFile && !deferred) { CloseHandle(hFile); } }
SEA_EXPORT const char* resolve_pointer(const char* szModulePath, uint64_t addr) { static std::string res; res.clear(); static HANDLE hCurProc = GetCurrentProcess(); DWORD dwOptions = SymSetOptions((SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS) & ~SYMOPT_DEFERRED_LOADS); static BOOL bInitialize = SymInitialize(hCurProc, NULL, TRUE); if (!bInitialize) return nullptr; static std::map<std::string, uint64_t> modules; uint64_t module = 0; if (modules.count(szModulePath)) { module = modules[szModulePath]; } else { module = SymLoadModule64(hCurProc, NULL, szModulePath, NULL, 0x800000, 0); modules[szModulePath] = module; } if (!module) return nullptr; IMAGEHLP_LINE64 line = { sizeof(IMAGEHLP_LINE64) }; DWORD dwDisplacement = 0; SymGetLineFromAddr64(hCurProc, module + addr, &dwDisplacement, &line); if (line.FileName) { res += std::string(line.FileName) + "(" + std::to_string(line.LineNumber) + ")\n"; } char buff[sizeof(SYMBOL_INFO) + 1024] = {}; SYMBOL_INFO * symbol = (SYMBOL_INFO*)buff; symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); SymFromAddr(hCurProc, module + addr, nullptr, symbol); res += symbol->Name; return res.c_str(); }
int main(int argc, char** argv) { int retv = 0; HANDLE hFile = INVALID_HANDLE_VALUE; enum dbg_start ds; #ifdef __i386__ be_cpu = &be_i386; #elif defined(__powerpc__) be_cpu = &be_ppc; #elif defined(__ALPHA__) be_cpu = &be_alpha; #elif defined(__x86_64__) be_cpu = &be_x86_64; #elif defined(__sparc__) be_cpu = &be_sparc; #elif defined(__arm__) be_cpu = &be_arm; #else # error CPU unknown #endif /* Initialize the output */ dbg_houtput = GetStdHandle(STD_OUTPUT_HANDLE); /* Initialize internal vars */ if (!dbg_load_internal_vars()) return -1; /* as we don't care about exec name */ argc--; argv++; if (argc && !strcmp(argv[0], "--help")) return dbg_winedbg_usage(TRUE); if (argc && !strcmp(argv[0], "--gdb")) { retv = gdb_main(argc, argv); if (retv == -1) dbg_winedbg_usage(FALSE); return retv; } dbg_init_console(); SymSetOptions((SymGetOptions() & ~(SYMOPT_UNDNAME)) | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_AUTO_PUBLICS); if (argc && (!strcmp(argv[0], "--auto") || !strcmp(argv[0], "--minidump"))) { /* force some internal variables */ DBG_IVAR(BreakOnDllLoad) = 0; dbg_houtput = GetStdHandle(STD_ERROR_HANDLE); switch (dbg_active_auto(argc, argv)) { case start_ok: return 0; case start_error_parse: return dbg_winedbg_usage(FALSE); case start_error_init: return -1; } } /* parse options */ while (argc > 0 && argv[0][0] == '-') { if (!strcmp(argv[0], "--command")) { argc--; argv++; hFile = parser_generate_command_file(argv[0], NULL); if (hFile == INVALID_HANDLE_VALUE) { dbg_printf("Couldn't open temp file (%u)\n", GetLastError()); return 1; } argc--; argv++; continue; } if (!strcmp(argv[0], "--file")) { argc--; argv++; hFile = CreateFileA(argv[0], GENERIC_READ|DELETE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { dbg_printf("Couldn't open file %s (%u)\n", argv[0], GetLastError()); return 1; } argc--; argv++; continue; } if (!strcmp(argv[0], "--")) { argc--; argv++; break; } return dbg_winedbg_usage(FALSE); } if (!argc) ds = start_ok; else if ((ds = dbg_active_attach(argc, argv)) == start_error_parse && (ds = minidump_reload(argc, argv)) == start_error_parse) ds = dbg_active_launch(argc, argv); switch (ds) { case start_ok: break; case start_error_parse: return dbg_winedbg_usage(FALSE); case start_error_init: return -1; } dbg_start_interactive(hFile); return 0; }
static void print_backtrace(CONTEXT *pctx) { SymGetLineFromAddrW64_func_t zbx_SymGetLineFromAddrW64 = NULL; SymFromAddr_func_t zbx_SymFromAddr = NULL; CONTEXT ctx, ctxcount; STACKFRAME64 s, scount; PSYMBOL_INFO pSym = NULL; HMODULE hModule; HANDLE hProcess, hThread; DWORD64 offset; wchar_t szProcessName[MAX_PATH]; char *process_name = NULL, *process_path = NULL, *frame = NULL; size_t frame_alloc = 0, frame_offset; int nframes = 0; ctx = *pctx; zabbix_log(LOG_LEVEL_CRIT, "=== Backtrace: ==="); memset(&s, 0, sizeof(s)); s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Mode = AddrModeFlat; s.AddrStack.Mode = AddrModeFlat; #ifdef _M_X64 s.AddrPC.Offset = ctx.Rip; s.AddrFrame.Offset = ctx.Rbp; s.AddrStack.Offset = ctx.Rsp; #else s.AddrPC.Offset = ctx.Eip; s.AddrFrame.Offset = ctx.Ebp; s.AddrStack.Offset = ctx.Esp; #endif hProcess = GetCurrentProcess(); hThread = GetCurrentThread(); if (0 != GetModuleFileNameEx(hProcess, NULL, szProcessName, ARRSIZE(szProcessName))) { char *ptr; int path_alloc = 0, path_offset = 0; process_name = zbx_unicode_to_utf8(szProcessName); if (NULL != (ptr = strstr(process_name, progname))) zbx_strncpy_alloc(&process_path, &path_alloc, &path_offset, process_name, ptr - process_name); } if (NULL != (hModule = GetModuleHandle(TEXT("DbgHelp.DLL")))) { zbx_SymGetLineFromAddrW64 = (SymGetLineFromAddrW64_func_t)GetProcAddress(hModule, "SymGetLineFromAddr64"); zbx_SymFromAddr = (SymFromAddr_func_t)GetProcAddress(hModule, "SymFromAddr"); } if (NULL != zbx_SymFromAddr || NULL != zbx_SymGetLineFromAddrW64) { SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES); if (FALSE != SymInitialize(hProcess, process_path, TRUE)) { pSym = (PSYMBOL_INFO) zbx_malloc(NULL, sizeof(SYMBOL_INFO) + MAX_SYM_NAME); memset(pSym, 0, sizeof(SYMBOL_INFO) + MAX_SYM_NAME); pSym->SizeOfStruct = sizeof(SYMBOL_INFO); pSym->MaxNameLen = MAX_SYM_NAME; } } scount = s; ctxcount = ctx; /* get number of frames, ctxcount may be modified during StackWalk64() calls */ while (TRUE == StackWalk64(ZBX_IMAGE_FILE_MACHINE, hProcess, hThread, &scount, &ctxcount, NULL, NULL, NULL, NULL)) { if (0 == scount.AddrReturn.Offset) break; nframes++; } while (TRUE == StackWalk64(ZBX_IMAGE_FILE_MACHINE, hProcess, hThread, &s, &ctx, NULL, NULL, NULL, NULL)) { frame_offset = 0; zbx_snprintf_alloc(&frame, &frame_alloc, &frame_offset, "%d: %s", nframes--, NULL == process_name ? "(unknown)" : process_name); if (NULL != pSym) { DWORD dwDisplacement; IMAGEHLP_LINE64 line = {sizeof(IMAGEHLP_LINE64)}; zbx_chrcpy_alloc(&frame, &frame_alloc, &frame_offset, '('); if (NULL != zbx_SymFromAddr && TRUE == zbx_SymFromAddr(hProcess, s.AddrPC.Offset, &offset, pSym)) { zbx_snprintf_alloc(&frame, &frame_alloc, &frame_offset, "%s+0x%lx", pSym->Name, offset); } if (NULL != zbx_SymGetLineFromAddrW64 && TRUE == zbx_SymGetLineFromAddrW64(hProcess, s.AddrPC.Offset, &dwDisplacement, &line)) { zbx_snprintf_alloc(&frame, &frame_alloc, &frame_offset, " %s:%d", line.FileName, line.LineNumber); } zbx_chrcpy_alloc(&frame, &frame_alloc, &frame_offset, ')'); } zabbix_log(LOG_LEVEL_CRIT, "%s [0x%lx]", frame, s.AddrPC.Offset); if (0 == s.AddrReturn.Offset) break; } SymCleanup(hProcess); zbx_free(frame); zbx_free(process_path); zbx_free(process_name); zbx_free(pSym); }
void *Ploopgrab(LPVOID args) { DEBUG_EVENT dbg; DWORD cont = DBG_CONTINUE, size = 0; TCHAR pszFilename[MAX_PATH+1]; DWORD64 mod; struct proc_uc *tmp = args; struct ps_prochandle *P = tmp->ps; int first_execp = 0; BOOL wow = 0; char *s; DWORD Options = SymGetOptions(); if (DebugActiveProcess(P->pid) == 0) { dprintf( "failed to debug process (%d): %d\n", P->pid, GetLastError() ); pthread_mutex_lock(&P->mutex); P->status = PS_STOP; P->flags = CREATE_FAILED; if (P->status == PS_STOP) pthread_cond_signal(&P->cond); pthread_mutex_unlock(&P->mutex); return NULL; } DebugSetProcessKillOnExit(FALSE); P->wstat = 0; P->exitcode = 0; P->event = CreateEvent(NULL,FALSE,FALSE,NULL); P->dll_load_order = 1; SymSetOptions(Options|SYMOPT_INCLUDE_32BIT_MODULES|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG); while (1) { if (WaitForDebugEvent(&dbg, INFINITE) == 0) { return NULL; } cont = DBG_CONTINUE; pthread_mutex_lock(&P->mutex); switch (dbg.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: P->thandle = dbg.u.CreateProcessInfo.hThread; P->phandle = dbg.u.CreateProcessInfo.hProcess; if ((SymInitialize(P->phandle, 0, FALSE) == FALSE)) { dprintf("SymInitialize failed (%d): %d\n", P->pid, GetLastError()); break; } s = GetFileNameFromHandle(dbg.u.CreateProcessInfo.hFile, pszFilename); addmodule(P, dbg.u.CreateProcessInfo.hFile, s, dbg.u.CreateProcessInfo.lpBaseOfImage, PE_TYPE_EXE, P->dll_load_order); size = GetFileSize(dbg.u.CreateProcessInfo.hFile, NULL); if (size == INVALID_FILE_SIZE) { size = 0; } if ((mod = SymLoadModuleEx(P->phandle, dbg.u.CreateProcessInfo.hFile, s, NULL, (ULONG_PTR) dbg.u.CreateProcessInfo.lpBaseOfImage, size, NULL, 0)) == FALSE) { dprintf("SymLoadModule64 Failed for %s: %d\n", s, GetLastError()); break; } #if __amd64__ if (Is32bitProcess(P->phandle)) { P->model = PR_MODEL_ILP32; wow = 1; } else P->model = PR_MODEL_ILP64; #else P->model = PR_MODEL_ILP32; #endif CloseHandle(dbg.u.CreateProcessInfo.hFile); P->status = PS_RUN; P->msg.type = 0; break; case CREATE_THREAD_DEBUG_EVENT: P->status = PS_RUN; P->msg.type = 0; break; case LOAD_DLL_DEBUG_EVENT: s = GetFileNameFromHandle(dbg.u.LoadDll.hFile, pszFilename); if (first_execp) { P->dll_load_order++; } addmodule(P, dbg.u.LoadDll.hFile, s, dbg.u.LoadDll.lpBaseOfDll, PE_TYPE_DLL, P->dll_load_order); size = GetFileSize(dbg.u.CreateProcessInfo.hFile, NULL); if (size == INVALID_FILE_SIZE) { size = 0; } #if __amd64__ /* Not tracing 64 bit dlls for 32 bit process */ if (P->model == PR_MODEL_ILP32 && is64bitmodule(dbg.u.LoadDll.lpBaseOfDll, s)) { CloseHandle(dbg.u.LoadDll.hFile ); break; } #endif if ((mod = SymLoadModuleEx(P->phandle, dbg.u.LoadDll.hFile, s, NULL, (ULONG_PTR) dbg.u.LoadDll.lpBaseOfDll, size, NULL, 0)) == FALSE) { dprintf("SymLoadModule64 failed for %s: %d\n", s, GetLastError()); break; } CloseHandle(dbg.u.LoadDll.hFile ); if (first_execp == 0) { P->status = PS_RUN; P->msg.type = RD_DLACTIVITY; } else { P->status = PS_STOP; P->msg.type = RD_DLACTIVITY; } break; case UNLOAD_DLL_DEBUG_EVENT: if (SymUnloadModule64(P->phandle, (ULONG_PTR) dbg.u.UnloadDll.lpBaseOfDll) == FALSE) { dprintf("SymUnloadModule64 failed-Imagebase %p: %d\n", dbg.u.UnloadDll.lpBaseOfDll, GetLastError()); break; } delmodule(P, (ULONG64) dbg.u.UnloadDll.lpBaseOfDll); P->status = PS_RUN; P->msg.type = RD_DLACTIVITY; break; case EXIT_PROCESS_DEBUG_EVENT: P->exitcode = dbg.u.ExitProcess.dwExitCode; P->status = PS_UNDEAD; P->msg.type = RD_NONE; //SymCleanup(P->phandle); break; case EXIT_THREAD_DEBUG_EVENT: P->status = PS_RUN; P->msg.type = 0; break; case EXCEPTION_DEBUG_EVENT: switch(dbg.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_BREAKPOINT: if (first_execp++ == 0) { pthread_cond_signal(&P->cond); } P->status = PS_STOP; P->msg.type = 0; break; default: if (dbg.u.Exception.dwFirstChance == 0) P->wstat = dbg.u.Exception.ExceptionRecord.ExceptionCode; P->status = PS_RUN; cont = DBG_EXCEPTION_NOT_HANDLED; break; } break; default: P->status = PS_RUN; dprintf("Debug Event not processed: %d\n", dbg.dwDebugEventCode); break; } if (P->status != PS_RUN) SetEvent(P->event); while (P->status == PS_STOP) pthread_cond_wait(&P->cond, &P->mutex); pthread_mutex_unlock(&P->mutex); ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, cont); } }
GCallStack::GCallStack(HANDLE hThread, CONTEXT& c) { if (!_bLockInit) // only init the single instance of the CRITICAL_SECTION 1 time for the many instances of GCallStack { InitializeCriticalSection(&_DbgHelpLock); _bLockInit = true; } DWORD imageType = IMAGE_FILE_MACHINE_I386; HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); int frameNum = 0; // counts walked frames int MAX_STACK_FRAMES = 7777; // in C# the maximum stack frames imposed by the language is 1000. Arbitrary limit to guarantee no condition of infinate walking in corrupted memory. DWORD offsetFromLine; // tells us line number in the source file #if defined(_LINUX64) || defined(_WIN64) || defined(_IOS) unsigned __int64 offsetFromSymbol; // tells us how far from the symbol we were #else DWORD offsetFromSymbol; // tells us how far from the symbol we were #endif DWORD symOptions; // symbol handler settings IMAGEHLP_SYMBOL *pSym = (IMAGEHLP_SYMBOL *) malloc( IMGSYMLEN + MAXNAMELEN ); GString strStackName(MAXNAMELEN + 512); // undecorated method/function name + Source file and line number IMAGEHLP_MODULE Module; IMAGEHLP_LINE Line; STACKFRAME64 s; // in/out stackframe memset( &s, '\0', sizeof s ); // note: converted code from [std::string symSearchPath] to [GString symSearchPath] so it will compile with the _UNICODE build flag - 8/18/2014 GString symSearchPath; #ifdef _UNICODE wchar_t *tt = 0, *p; tt = new wchar_t[TTBUFLEN]; #else char *tt = 0, *p; tt = new char[TTBUFLEN]; #endif // build symbol search path from: symSearchPath = ""; // current directory if (GetCurrentDirectory(TTBUFLEN, tt)) symSearchPath << tt << "; "; // dir with executable if ( GetModuleFileName( 0, tt, TTBUFLEN ) ) { #ifdef _UNICODE for (p = tt + wcslen(tt) - 1; p >= tt; --p) #else for (p = tt + strlen(tt) - 1; p >= tt; --p) // VC6 does not have a _tcsclen() and we still support VC6 #endif { // locate the rightmost path separator if ( *p == '\\' || *p == '/' || *p == ':' ) 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 ( p != tt ) // path sep found? { if ( *p == ':' ) // we leave colons in place ++ p; *p = '\0'; // eliminate the exe name and last path sep symSearchPath << tt << "; "; } } // environment variable _NT_SYMBOL_PATH GString g("_NT_SYMBOL_PATH"); if (GetEnvironmentVariable(g, tt, TTBUFLEN)) symSearchPath << tt << "; "; // environment variable _NT_ALTERNATE_SYMBOL_PATH g = "_NT_ALTERNATE_SYMBOL_PATH"; if (GetEnvironmentVariable(g, tt, TTBUFLEN)) symSearchPath << tt << "; "; // environment variable SYSTEMROOT g = "SYSTEMROOT"; if (GetEnvironmentVariable(g, tt, TTBUFLEN)) symSearchPath << tt << "; "; if ( symSearchPath.size() > 0 ) // if we added anything, we have a trailing semicolon symSearchPath = symSearchPath.substr( 0, symSearchPath.size() - 1 ); // 8/20/2014 note: In older Windows API's SymInitialize()'s 2nd argument was not defined as "const char *", it was only "char *" // Although "const" was not defined, the API call is "const" in behavior. In newer versions of the Windows API this has been fixed. // In newer versions - SymInitialize's 2nd argument may resolve to either "const char *" OR "const wchar_t *", and in those builds the // GString has a default conversion to the correct string type, however in the older build configurations, GString does not (and should not) // know how to resolve to a "char *" by default, so in that case the preprocessor directive isolates the code needed to convert to "char *" #if defined(_MSC_VER) && _MSC_VER <= 1200 if (!SymInitialize(hProcess, symSearchPath.Buf(), false)) // symSearchPath == (char *) #else if (!SymInitialize(hProcess, symSearchPath, true)) // symSearchPath == (const char *) --OR-- (const wchar_t *) depending on the _UNICODE preprocessor definition #endif { goto tagCleanUp; } symOptions = SymGetOptions(); symOptions |= SYMOPT_LOAD_LINES; symOptions &= ~SYMOPT_UNDNAME; SymSetOptions( symOptions ); enumAndLoadModuleSymbols( hProcess, GetCurrentProcessId() ); // init STACKFRAME for first call, definitions found in ImageHlp.h #ifdef _M_IX86 imageType = IMAGE_FILE_MACHINE_I386; s.AddrPC.Offset = c.Eip; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.Ebp; s.AddrFrame.Mode = AddrModeFlat; s.AddrStack.Offset = c.Esp; s.AddrStack.Mode = AddrModeFlat; #elif _M_X64 imageType = IMAGE_FILE_MACHINE_AMD64; s.AddrPC.Offset = c.Rip; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.Rsp; s.AddrFrame.Mode = AddrModeFlat; s.AddrStack.Offset = c.Rsp; s.AddrStack.Mode = AddrModeFlat; #elif _M_IA64 imageType = IMAGE_FILE_MACHINE_IA64; s.AddrPC.Offset = c.StIIP; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.IntSp; s.AddrFrame.Mode = AddrModeFlat; s.AddrBStore.Offset = c.RsBSP; s.AddrBStore.Mode = AddrModeFlat; s.AddrStack.Offset = c.IntSp; s.AddrStack.Mode = AddrModeFlat; #endif 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; // DbgHelp is single threaded, so acquire a lock. EnterCriticalSection(&_DbgHelpLock); while ( frameNum < MAX_STACK_FRAMES ) { // 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. #ifdef _WIN64 if (!StackWalk64(imageType, hProcess, hThread, &s, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) #else if (!StackWalk(imageType, hProcess, hThread, &s, &c, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL)) #endif break; // Maybe it failed, maybe we have finished walking the stack if ( s.AddrPC.Offset != 0 ) { // Most likely a valid stack rame // show procedure info if ( ! SymGetSymFromAddr64( hProcess, s.AddrPC.Offset, &offsetFromSymbol, pSym ) ) { break; } else { // UnDecorateSymbolName() to get the Class::Method or function() name in tyhe callstack strStackName.Empty(); UnDecorateSymbolName(pSym->Name, strStackName._str, MAXNAMELEN, UNDNAME_COMPLETE); strStackName.SetLength(strlen(strStackName._str)); // SymGetLineFromAddr() to get the source.cpp and the line number IMAGEHLP_LINE64 Line; if (SymGetLineFromAddr64(hProcess, s.AddrPC.Offset, &offsetFromLine, &Line) != FALSE) { GString g(Line.FileName); // Line.FileName conains the "c:\Full\Path\TO\Source.cpp" // Builds string "Foo::Bar[Source.cpp]@777" strStackName << "[" << g.StartingAt(g.ReverseFind("\\") + 1) << "]@" << Line.LineNumber; } // add the GString to the GStringList, do not add frame 0 because it will always be GException::GSeception where we divided by 0 if (frameNum > 0) _stk += strStackName; } } else { // base reached SetLastError(0); break; } ++frameNum; } LeaveCriticalSection(&_DbgHelpLock); // de-init symbol handler etc. (SymCleanup()) SymCleanup( hProcess ); free( pSym ); tagCleanUp:; delete [] tt; CloseHandle(hProcess); }
struct ps_prochandle *Pgrab(pid_t pid, int flags, int *perr) { struct ps_prochandle *ps; int id; struct proc_uc data; id = GetCurrentProcessId(); if (pid == 0 || (pid == id && !(flags & PGRAB_RDONLY))) { return NULL; } if ((ps = malloc(sizeof(struct ps_prochandle))) == NULL) { return NULL; } ZeroMemory(ps, sizeof(*ps)); ps->pid = pid; ps->flags = flags; if (flags & PGRAB_RDONLY) { DWORD Options = SymGetOptions(); HANDLE hprocess; hprocess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid ); if (hprocess == NULL) { dprintf("failed to open process %d: %d\n", pid, GetLastError()); free(ps); return NULL; } SymSetOptions(Options|SYMOPT_INCLUDE_32BIT_MODULES|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG); if ((SymInitialize(hprocess, NULL, TRUE) == FALSE)) { dprintf("SymInitialize failed %d: %d\n", pid, GetLastError()); } ps->phandle = hprocess; return ps; } data.ps = ps; pthread_mutex_init(&ps->mutex, NULL); pthread_cond_init (&ps->cond, NULL); if (pthread_create(&ps->pthr, NULL, Ploopgrab, &data)) { pthread_mutex_destroy(&ps->mutex); pthread_cond_destroy(&ps->cond); free(ps); return NULL; } pthread_mutex_lock(&ps->mutex); while (ps->status != PS_STOP) pthread_cond_wait(&ps->cond, &ps->mutex); pthread_mutex_unlock(&ps->mutex); if (ps->flags == CREATE_FAILED) { pthread_mutex_destroy(&ps->mutex); pthread_cond_destroy(&ps->cond); free(ps); return NULL; } return ps; }
static void *Ploopcreate(LPVOID args) { STARTUPINFO si; PROCESS_INFORMATION pi; DEBUG_EVENT dbg; DWORD cont; BOOL wow = 0; DWORD Options = SymGetOptions(), excep, size = 0; TCHAR pszFilename[MAX_PATH+1]; struct proc_uc *tmp = args; struct ps_prochandle *P = tmp->ps; int first_execp = 0; char *s, targs[256], *ctmp; char *const *argv = tmp->args; int len; ctmp = targs; while (*argv != NULL) { len = strlen(*argv); sprintf(ctmp, "%s ", *argv); ctmp = ctmp + len + 1; argv++; } *ctmp = '\0'; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); if(!CreateProcess( NULL, // module name targs, // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable FALSE, // Set handle inheritance to FALSE DEBUG_ONLY_THIS_PROCESS, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi ) // Pointer to PROCESS_INFORMATION structure ) { pthread_mutex_lock(&P->mutex); P->status = PS_STOP; P->flags = CREATE_FAILED; pthread_cond_signal(&P->cond); pthread_mutex_unlock(&P->mutex); return NULL; } P->pid = pi.dwProcessId; P->tid = pi.dwThreadId; P->wstat = 0; P->exitcode = 0; P->event = CreateEvent(NULL,FALSE,FALSE,NULL); P->dll_load_order = 1; #if __amd64__ /* There seems to be a bug in 64 bit version of dbghelp.dll * when SYMOPT_DEFERRED_LOADS is set, * dtrace -n "pid$target:kernel32::entry, pid$target:KernelBase::entry" -c test.exe, * when SymEnumSymbols (Psymbol_iter_by_addr) is called on this two dll, * the second call (KernelBase) will enumerate the * symbols from the previous enumurated (kernel32) dll (from the first call). * This behaviour is not present in 32 bit. */ Options &= ~SYMOPT_DEFERRED_LOADS; #endif SymSetOptions(Options|SYMOPT_INCLUDE_32BIT_MODULES|SYMOPT_DEBUG); while (1) { if (WaitForDebugEvent(&dbg, INFINITE) == 0) { return NULL; } cont = DBG_CONTINUE; pthread_mutex_lock(&P->mutex); switch (dbg.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: P->phandle = dbg.u.CreateProcessInfo.hProcess; P->thandle = dbg.u.CreateProcessInfo.hThread; if ((SymInitialize(P->phandle, 0, FALSE) == FALSE)) { dprintf("SymInitialize failed: %d\n", GetLastError()); break; } s = GetFileNameFromHandle(dbg.u.CreateProcessInfo.hFile, pszFilename); addmodule(P, dbg.u.CreateProcessInfo.hFile, s, dbg.u.CreateProcessInfo.lpBaseOfImage, PE_TYPE_EXE, P->dll_load_order); size = GetFileSize(dbg.u.CreateProcessInfo.hFile, NULL); if (size == INVALID_FILE_SIZE) { size = 0; } if (SymLoadModuleEx(P->phandle, dbg.u.CreateProcessInfo.hFile, s, NULL, (ULONG_PTR) dbg.u.CreateProcessInfo.lpBaseOfImage, size, NULL, 0) == 0) { dprintf("SymLoadModule64 failed for %s:%d\n", s, GetLastError()); break; } #if __amd64__ if (Is32bitProcess(P->phandle)) { P->model = PR_MODEL_ILP32; wow = 1; } else P->model = PR_MODEL_ILP64; #else P->model = PR_MODEL_ILP32; #endif P->status = PS_STOP; P->msg.type = 0; CloseHandle(dbg.u.CreateProcessInfo.hFile); pthread_cond_signal(&P->cond); break; case CREATE_THREAD_DEBUG_EVENT: P->status = PS_RUN; P->msg.type = 0; break; case LOAD_DLL_DEBUG_EVENT: s = GetFileNameFromHandle(dbg.u.LoadDll.hFile, pszFilename); if (first_execp == 2) { P->dll_load_order++; } addmodule(P, dbg.u.LoadDll.hFile, s, dbg.u.LoadDll.lpBaseOfDll, PE_TYPE_DLL, P->dll_load_order); size = GetFileSize(dbg.u.LoadDll.hFile, NULL); if (size == INVALID_FILE_SIZE) { size = 0; } #if __amd64__ /* Not tracing 64 bit dlls for 32 bit process */ if (P->model == PR_MODEL_ILP32 && is64bitmodule(dbg.u.LoadDll.lpBaseOfDll, s)) { CloseHandle(dbg.u.LoadDll.hFile ); break; } #endif if (SymLoadModuleEx(P->phandle, dbg.u.LoadDll.hFile, s, NULL, (ULONG_PTR) dbg.u.LoadDll.lpBaseOfDll, size, NULL, 0) == FALSE) { dprintf("SymLoadModule64 dailed for %s:%d\n", s, GetLastError()); break; } CloseHandle(dbg.u.LoadDll.hFile ); P->status = PS_STOP; P->msg.type = RD_DLACTIVITY; break; case UNLOAD_DLL_DEBUG_EVENT: if (SymUnloadModule64(P->phandle, (ULONG_PTR) dbg.u.UnloadDll.lpBaseOfDll) == FALSE) { dprintf("SymUnloadModule64 failed-Imagebase %p:%d\n", dbg.u.UnloadDll.lpBaseOfDll, GetLastError()); break; } delmodule(P, (ULONG64) dbg.u.UnloadDll.lpBaseOfDll); P->status = PS_RUN; P->msg.type = RD_DLACTIVITY; break; case EXIT_PROCESS_DEBUG_EVENT: P->exitcode = dbg.u.ExitProcess.dwExitCode; P->status = PS_UNDEAD; P->msg.type = RD_NONE; break; case EXIT_THREAD_DEBUG_EVENT: P->status = PS_RUN; P->msg.type = 0; break; case EXCEPTION_DEBUG_EVENT: switch(excep = dbg.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_BREAKPOINT: case 0x4000001F: /* WOW64 exception breakpoint */ /* NOTE: Dtrace sets a BP at main (entry point of the process), which is implemented * with Psetbkpt, Pdelbkpt & Pexecbkpt. But I have implemnted it here. */ if ((excep == EXCEPTION_BREAKPOINT && first_execp == 0 && wow == 0) || (excep == 0x4000001F && first_execp == 0 && wow == 1) ) { SYMBOL_INFO *Symbol; GElf_Sym sym; ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; Symbol = (SYMBOL_INFO *) buffer; Symbol->SizeOfStruct= sizeof(SYMBOL_INFO ); Symbol->MaxNameLen = MAX_SYM_NAME; if (Pxlookup_by_name(P, LM_ID_BASE, "a.out", "main", &sym, NULL) != 0 && Pxlookup_by_name(P, LM_ID_BASE, "a.out", "WinMain", &sym, NULL) != 0) { dprintf("failed to find entry point (main):%d\n", GetLastError()); break; } if (setbkpt(P, (uintptr_t) sym.st_value) != 0) { dprintf("failed to set breakpoint for %s at address %p\n", Symbol->Name, Symbol->Address); break; } first_execp = 1; P->status = PS_RUN; P->msg.type = 0; break; } if (dbg.u.Exception.ExceptionRecord.ExceptionAddress != (PVOID) P->addr) { dprintf("expecting execption at %p:but recived from %p\n", P->addr, dbg.u.Exception.ExceptionRecord.ExceptionAddress); P->status = PS_RUN; cont = DBG_EXCEPTION_NOT_HANDLED; break; } if (delbkpt(P, P->addr) != 0) { dprintf("failed to delete brk point at %p:(main)\n", P->addr); break; } if (adjbkpt(P, wow) != 0) { dprintf("failed to normalize brk point (main)\n"); break; } first_execp = 2; P->status = PS_STOP; P->msg.type = RD_MAININIT; break;/* if (first_execp == 0) { P->status = PS_STOP; P->msg.type = RD_MAININIT; first_execp = 2; } else { P->status = PS_RUN; cont = DBG_EXCEPTION_NOT_HANDLED; } break;*/ default: if (dbg.u.Exception.dwFirstChance == 0) P->wstat = dbg.u.Exception.ExceptionRecord.ExceptionCode; P->status = PS_RUN; cont = DBG_EXCEPTION_NOT_HANDLED; break; } break; default: P->status = PS_RUN; dprintf("Debug Event not processed: %d\n", dbg.dwDebugEventCode); break; } if (P->status != PS_RUN) SetEvent(P->event); while (P->status == PS_STOP) pthread_cond_wait(&P->cond, &P->mutex); pthread_mutex_unlock(&P->mutex); ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, cont); } }
//************************************************************************* // 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 printStackTrace( std::ostream &os ) { HANDLE process = GetCurrentProcess(); BOOL ret = SymInitialize( process, NULL, TRUE ); if ( ret == FALSE ) { DWORD dosError = GetLastError(); os << "Stack trace failed, SymInitialize failed with error " << std::dec << dosError << std::endl; return; } DWORD options = SymGetOptions(); options |= SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS; SymSetOptions( options ); CONTEXT context; memset( &context, 0, sizeof(context) ); context.ContextFlags = CONTEXT_CONTROL; RtlCaptureContext( &context ); STACKFRAME64 frame64; memset( &frame64, 0, sizeof(frame64) ); #if defined(_M_AMD64) DWORD imageType = IMAGE_FILE_MACHINE_AMD64; frame64.AddrPC.Offset = context.Rip; frame64.AddrFrame.Offset = context.Rbp; frame64.AddrStack.Offset = context.Rsp; #elif defined(_M_IX86) DWORD imageType = IMAGE_FILE_MACHINE_I386; frame64.AddrPC.Offset = context.Eip; frame64.AddrFrame.Offset = context.Ebp; frame64.AddrStack.Offset = context.Esp; #else #error Neither _M_IX86 nor _M_AMD64 were defined #endif frame64.AddrPC.Mode = AddrModeFlat; frame64.AddrFrame.Mode = AddrModeFlat; frame64.AddrStack.Mode = AddrModeFlat; const size_t nameSize = 1024; const size_t symbolRecordSize = sizeof(SYMBOL_INFO) + nameSize; boost::scoped_array<char> symbolBuffer( new char[symbolRecordSize] ); memset( symbolBuffer.get(), 0, symbolRecordSize ); SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>( symbolBuffer.get() ); symbol->SizeOfStruct = sizeof(SYMBOL_INFO); symbol->MaxNameLen = nameSize; std::vector<TraceItem> traceList; TraceItem traceItem; size_t moduleWidth = 0; size_t fileWidth = 0; size_t frameCount = 0; for ( size_t i = 0; i < maxBackTraceFrames; ++i ) { ret = StackWalk64( imageType, process, GetCurrentThread(), &frame64, &context, NULL, NULL, NULL, NULL ); if ( ret == FALSE || frame64.AddrReturn.Offset == 0 ) { frameCount = i; break; } // module (executable) name IMAGEHLP_MODULE64 module; memset ( &module, 0, sizeof(module) ); module.SizeOfStruct = sizeof(module); ret = SymGetModuleInfo64( process, frame64.AddrPC.Offset, &module ); char* moduleName = module.LoadedImageName; char* backslash = strrchr( moduleName, '\\' ); if ( backslash ) { moduleName = backslash + 1; } traceItem.module = moduleName; size_t len = traceItem.module.length(); if ( len > moduleWidth ) { moduleWidth = len; } // source code filename and line number IMAGEHLP_LINE64 line; memset( &line, 0, sizeof(line) ); line.SizeOfStruct = sizeof(line); DWORD displacement32; ret = SymGetLineFromAddr64( process, frame64.AddrPC.Offset, &displacement32, &line ); if ( ret ) { std::string filename( line.FileName ); std::string::size_type start = filename.find( "\\src\\mongo\\" ); if ( start == std::string::npos ) { start = filename.find( "\\src\\third_party\\" ); } if ( start != std::string::npos ) { std::string shorter( "..." ); shorter += filename.substr( start ); traceItem.sourceFile.swap( shorter ); } else { traceItem.sourceFile.swap( filename ); } len = traceItem.sourceFile.length() + 3; traceItem.lineNumber = line.LineNumber; if ( traceItem.lineNumber < 10 ) { len += 1; } else if ( traceItem.lineNumber < 100 ) { len += 2; } else if ( traceItem.lineNumber < 1000 ) { len += 3; } else if ( traceItem.lineNumber < 10000 ) { len += 4; } else { len += 5; } traceItem.sourceLength = len; if ( len > fileWidth ) { fileWidth = len; } } else { traceItem.sourceFile.clear(); traceItem.sourceLength = 0; } // symbol name and offset from symbol DWORD64 displacement; ret = SymFromAddr( process, frame64.AddrPC.Offset, &displacement, symbol ); if ( ret ) { traceItem.symbol = symbol->Name; traceItem.instructionOffset = displacement; } else { traceItem.symbol = "???"; traceItem.instructionOffset = 0; } // add to list traceList.push_back( traceItem ); } SymCleanup( process ); // print list ++moduleWidth; ++fileWidth; for ( size_t i = 0; i < frameCount; ++i ) { os << traceList[i].module << " "; size_t width = traceList[i].module.length(); while ( width < moduleWidth ) { os << " "; ++width; } if ( traceList[i].sourceFile.length() ) { os << traceList[i].sourceFile << "(" << std::dec << traceList[i].lineNumber << ") "; } width = traceList[i].sourceLength; while ( width < fileWidth ) { os << " "; ++width; } os << traceList[i].symbol << "+0x" << std::hex << traceList[i].instructionOffset; os << std::endl; } }
/** * Print stack trace (using a specified stack context) to "os" * * @param context CONTEXT record for stack trace * @param os ostream& to receive printed stack backtrace */ void printWindowsStackTrace( CONTEXT& context, std::ostream& os ) { SimpleMutex::scoped_lock lk(_stackTraceMutex); HANDLE process = GetCurrentProcess(); BOOL ret = SymInitialize(process, getSymbolSearchPath(process), TRUE); if ( ret == FALSE ) { DWORD dosError = GetLastError(); log() << "Stack trace failed, SymInitialize failed with error " << std::dec << dosError << std::endl; return; } DWORD options = SymGetOptions(); options |= SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS; SymSetOptions( options ); STACKFRAME64 frame64; memset( &frame64, 0, sizeof(frame64) ); #if defined(_M_AMD64) DWORD imageType = IMAGE_FILE_MACHINE_AMD64; frame64.AddrPC.Offset = context.Rip; frame64.AddrFrame.Offset = context.Rbp; frame64.AddrStack.Offset = context.Rsp; #elif defined(_M_IX86) DWORD imageType = IMAGE_FILE_MACHINE_I386; frame64.AddrPC.Offset = context.Eip; frame64.AddrFrame.Offset = context.Ebp; frame64.AddrStack.Offset = context.Esp; #else #error Neither _M_IX86 nor _M_AMD64 were defined #endif frame64.AddrPC.Mode = AddrModeFlat; frame64.AddrFrame.Mode = AddrModeFlat; frame64.AddrStack.Mode = AddrModeFlat; const size_t nameSize = 1024; const size_t symbolBufferSize = sizeof(SYMBOL_INFO) + nameSize; boost::scoped_array<char> symbolCharBuffer( new char[symbolBufferSize] ); memset( symbolCharBuffer.get(), 0, symbolBufferSize ); SYMBOL_INFO* symbolBuffer = reinterpret_cast<SYMBOL_INFO*>( symbolCharBuffer.get() ); symbolBuffer->SizeOfStruct = sizeof(SYMBOL_INFO); symbolBuffer->MaxNameLen = nameSize; // build list std::vector<TraceItem> traceList; TraceItem traceItem; size_t moduleWidth = 0; size_t sourceWidth = 0; for ( size_t i = 0; i < maxBackTraceFrames; ++i ) { ret = StackWalk64( imageType, process, GetCurrentThread(), &frame64, &context, NULL, NULL, NULL, NULL ); if ( ret == FALSE || frame64.AddrReturn.Offset == 0 ) { break; } DWORD64 address = frame64.AddrPC.Offset; getModuleName( process, address, &traceItem.moduleName ); size_t width = traceItem.moduleName.length(); if ( width > moduleWidth ) { moduleWidth = width; } getSourceFileAndLineNumber( process, address, &traceItem.sourceAndLine ); width = traceItem.sourceAndLine.length(); if ( width > sourceWidth ) { sourceWidth = width; } getsymbolAndOffset( process, address, symbolBuffer, &traceItem.symbolAndOffset ); traceList.push_back( traceItem ); } SymCleanup( process ); // print list ++moduleWidth; ++sourceWidth; size_t frameCount = traceList.size(); for ( size_t i = 0; i < frameCount; ++i ) { std::stringstream ss; ss << traceList[i].moduleName << " "; size_t width = traceList[i].moduleName.length(); while ( width < moduleWidth ) { ss << " "; ++width; } ss << traceList[i].sourceAndLine << " "; width = traceList[i].sourceAndLine.length(); while ( width < sourceWidth ) { ss << " "; ++width; } ss << traceList[i].symbolAndOffset; log() << ss.str() << std::endl; } }