bool CSymbolEngine::UnloadModuleSymbols( DWORD64 ModBase ) { // Check preconditions if( m_hProcess == NULL ) { _ASSERTE( !_T("Symbol engine is not yet initialized.") ); m_LastError = ERROR_INVALID_FUNCTION; return false; } if( ModBase == 0 ) { _ASSERTE( !_T("Module base address is null.") ); m_LastError = ERROR_INVALID_PARAMETER; return false; } // Unload symbols if( !SymUnloadModule64( m_hProcess, ModBase ) ) { m_LastError = GetLastError(); _ASSERTE( !_T("SymUnloadModule64() failed.") ); return false; } // Complete return true; }
void InitializeSymbolLookup() { static bool bIsInitialized = false; if( bIsInitialized ) { return; } bIsInitialized = true; hApplicationProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ApplicationProcessId); if( hApplicationProcess == NULL ) { DWORD error = GetLastError(); DebugLog("OpenProcess failed: error = %d", error); return; } DWORD SymOpts = 0; SymOpts |= SYMOPT_ALLOW_ABSOLUTE_SYMBOLS; // SymOpts |= SYMOPT_CASE_INSENSITIVE; SymOpts |= SYMOPT_DEBUG; SymOpts |= SYMOPT_DEFERRED_LOADS; SymOpts |= SYMOPT_EXACT_SYMBOLS; SymOpts |= SYMOPT_FAIL_CRITICAL_ERRORS; SymOpts |= SYMOPT_LOAD_LINES; SymOpts |= SYMOPT_UNDNAME; SymSetOptions(SymOpts); if( !SymInitialize(hApplicationProcess, NULL, TRUE) ) // defer the loading of process modules { DWORD error = GetLastError(); DebugLog("SymInitialize failed: error = %d", error); return; } LoadModules(); DWORD FileSize = 0; DWORD64 dwBaseAddress = 0; DWORD64 result = SymLoadModuleExW(hApplicationProcess, NULL, app_filename, NULL, dwBaseAddress, FileSize, NULL, 0); if( result == 0 ) { DWORD error = GetLastError(); DebugLog("SymLoadModuleEx failed: error = %d", error); SymUnloadModule64(hApplicationProcess, dwBaseAddress); return; } }
void Pdb::UnloadModuleSymbols() { for(int i = 0; i < module.GetCount(); i++) { ModuleInfo& f = module[i]; if(f.symbols) { SymUnloadModule64(hProcess, f.base); LLOG("Unloaded symbols for " << f.path << ' ' << Hex(module[i].base) << '/' << hProcess); } } }
//-------------------------------------------------------------------------------------- ULONGLONG GetSymbolByName(char *lpszModuleName, HMODULE hModule, char *lpszName) { ULONGLONG Ret = 0; // try to load debug symbols for module if (SymLoadModuleEx(GetCurrentProcess(), NULL, lpszModuleName, NULL, (DWORD64)hModule, 0, NULL, 0)) { ENUM_SYM_PARAM Param; Param.Address = NULL; Param.lpszName = lpszName; // get specified symbol address by name if (!SymEnumSymbols( GetCurrentProcess(), (DWORD64)hModule, NULL, EnumSymbolsProc, &Param)) { DbgMsg(__FILE__, __LINE__, "SymEnumSymbols() ERROR %d\n", GetLastError()); } if (Param.Address == NULL) { DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't locate symbol\n"); } else { Ret = Param.Address; } // unload symbols SymUnloadModule64(GetCurrentProcess(), (DWORD64)hModule); } else { DbgMsg(__FILE__, __LINE__, "SymLoadModuleEx() ERROR %d\n", GetLastError()); } return Ret; }
/** * Interface used by PDMR3LdrRelocate for telling us that a GC module has been relocated. * * @param pVM The VM handle. * @param OldImageBase The old image base. * @param NewImageBase The new image base. * @param cbImage The image size. * @param pszFilename The image filename. * @param pszName The module name. */ VMMR3DECL(void) DBGFR3ModuleRelocate(PVM pVM, RTGCUINTPTR OldImageBase, RTGCUINTPTR NewImageBase, RTGCUINTPTR cbImage, const char *pszFilename, const char *pszName) { #ifdef HAVE_DBGHELP if (pVM->dbgf.s.fSymInited) { if (!SymUnloadModule64(pVM, OldImageBase)) Log(("SymUnloadModule64(,%RGv) failed, lasterr=%d\n", OldImageBase, GetLastError())); DWORD ImageSize = (DWORD)cbImage; Assert(ImageSize == cbImage); DWORD64 LoadedImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)pszFilename, (char *)(void *)pszName, NewImageBase, ImageSize); if (!LoadedImageBase) Log(("SymLoadModule64(,,%s,,) -> lasterr=%d (relocate)\n", pszFilename, GetLastError())); else Log(("Reloaded debuginfo for %s - %s %llx\n", pszName, pszFilename, LoadedImageBase)); } #else #endif }
bool CATDbgHelper::Close( void ) { LOG_FUNC_ENTRY("CATDbgHelper::Close"); if ( ! SymUnloadModule64( GetCurrentProcess(), m_BaseAddress ) ) { LOG_STRING("Dbghelp:Module unload failed."); } CDBGHELPER_CLIENTS--; if ( CDBGHELPER_OPEN && CDBGHELPER_CLIENTS == 0) { // Cleanup dbghelper. if ( ! SymCleanup( GetCurrentProcess() ) ) { LOG_STRING("dbghelper cleanup failed."); return false; } LOG_STRING("dbghelper closed."); // Set state not opened. CDBGHELPER_OPEN = false; } return true; }
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); } }
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); } }
int main(int argc, char *argv[]) { DWORD error; HANDLE process; ULONG64 module_base; int i; char* search; char buf[256]; /* Enough to hold one hex address, I trust! */ int rv = 0; /* We may add SYMOPT_UNDNAME if --demangle is specified: */ DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES; char* filename = "a.out"; /* The default if -e isn't specified */ int print_function_name = 0; /* Set to 1 if -f is specified */ for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--functions") == 0 || strcmp(argv[i], "-f") == 0) { print_function_name = 1; } else if (strcmp(argv[i], "--demangle") == 0 || strcmp(argv[i], "-C") == 0) { symopts |= SYMOPT_UNDNAME; } else if (strcmp(argv[i], "-e") == 0) { if (i + 1 >= argc) { fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n"); return 1; } filename = argv[i+1]; i++; /* to skip over filename too */ } else if (strcmp(argv[i], "--help") == 0) { usage(); exit(0); } else { usage(); exit(1); } } process = GetCurrentProcess(); if (!SymInitialize(process, NULL, FALSE)) { error = GetLastError(); fprintf(stderr, "SymInitialize returned error : %d\n", error); return 1; } search = malloc(SEARCH_CAP); if (SymGetSearchPath(process, search, SEARCH_CAP)) { if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) { fprintf(stderr, "Search path too long\n"); SymCleanup(process); return 1; } strcat(search, ";" WEBSYM); } else { error = GetLastError(); fprintf(stderr, "SymGetSearchPath returned error : %d\n", error); rv = 1; /* An error, but not a fatal one */ strcpy(search, WEBSYM); /* Use a default value */ } if (!SymSetSearchPath(process, search)) { error = GetLastError(); fprintf(stderr, "SymSetSearchPath returned error : %d\n", error); rv = 1; /* An error, but not a fatal one */ } SymSetOptions(symopts); module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0); if (!module_base) { /* SymLoadModuleEx failed */ error = GetLastError(); fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n", error, filename); SymCleanup(process); return 1; } buf[sizeof(buf)-1] = '\0'; /* Just to be safe */ while (fgets(buf, sizeof(buf)-1, stdin)) { /* GNU addr2line seems to just do a strtol and ignore any * weird characters it gets, so we will too. */ unsigned __int64 addr = _strtoui64(buf, NULL, 16); ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; IMAGEHLP_LINE64 line; DWORD dummy; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_SYM_NAME; if (print_function_name) { if (SymFromAddr(process, (DWORD64)addr, NULL, pSymbol)) { printf("%s\n", pSymbol->Name); } else { printf("??\n"); } } line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); if (SymGetLineFromAddr64(process, (DWORD64)addr, &dummy, &line)) { printf("%s:%d\n", line.FileName, (int)line.LineNumber); } else { printf("??:0\n"); } } SymUnloadModule64(process, module_base); SymCleanup(process); return rv; }
BOOL DebugMainLoop(const DebugOptions *pOptions) { BOOL fFinished = FALSE; BOOL fBreakpointSignalled = FALSE; BOOL fWowBreakpointSignalled = FALSE; BOOL fTerminating = FALSE; while(!fFinished) { DEBUG_EVENT DebugEvent; // debugging event information DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation PPROCESS_INFO pProcessInfo; PTHREAD_INFO pThreadInfo; HANDLE hProcess; // Wait for a debugging event to occur. The second parameter indicates // that the function does not return until a debugging event occurs. if(!WaitForDebugEvent(&DebugEvent, INFINITE)) { OutputDebug("WaitForDebugEvent: 0x%08lx", GetLastError()); return FALSE; } // Process the debugging event code. switch (DebugEvent.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: { PEXCEPTION_RECORD pExceptionRecord = &DebugEvent.u.Exception.ExceptionRecord; NTSTATUS ExceptionCode = pExceptionRecord->ExceptionCode; // Process the exception code. When handling // exceptions, remember to set the continuation // status parameter (dwContinueStatus). This value // is used by the ContinueDebugEvent function. if (pOptions->verbose_flag) { lprintf("EXCEPTION PID=%lu TID=%lu ExceptionCode=0x%lx dwFirstChance=%lu\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, pExceptionRecord->ExceptionCode, DebugEvent.u.Exception.dwFirstChance ); } // Find the process in the process list pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; if (DebugEvent.u.Exception.dwFirstChance) { if (pExceptionRecord->ExceptionCode == (DWORD)STATUS_BREAKPOINT) { // Signal the aedebug event if (!fBreakpointSignalled) { fBreakpointSignalled = TRUE; if (pOptions->hEvent) { SetEvent(pOptions->hEvent); CloseHandle(pOptions->hEvent); } if (pOptions->dwThreadId) { DWORD dwThreadId = pOptions->dwThreadId; const DWORD dwFailed = (DWORD)-1; DWORD dwRet = dwFailed; pThreadInfo = &pProcessInfo->Threads[dwThreadId]; HANDLE hThread = pThreadInfo->hThread; if (hThread != NULL) { dwRet = ResumeThread(hThread); } if (dwRet == dwFailed) { lprintf("error: failed to resume thread %lu\n", dwThreadId); } } /* * We ignore first-chance breakpoints by default. * * We get one of these whenever we attach to a process. * But in some cases, we never get a second-chance, e.g., * when we're attached through MSVCRT's abort(). */ if (!pOptions->breakpoint_flag) { dwContinueStatus = DBG_CONTINUE; break; } } } if (ExceptionCode == STATUS_WX86_BREAKPOINT) { if (!fWowBreakpointSignalled) { fWowBreakpointSignalled = TRUE; dwContinueStatus = DBG_CONTINUE; break; } } /* * Ignore thread naming exception. * * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx * * TODO: Note down the thread name */ if (ExceptionCode == 0x406d1388) { dwContinueStatus = DBG_CONTINUE; break; } if (!pOptions->first_chance) { break; } } // XXX: Deferred symbols don't get loaded without this SymRefreshModuleList(pProcessInfo->hProcess); dumpException(pProcessInfo->hProcess, &DebugEvent.u.Exception.ExceptionRecord); // Find the thread in the thread list THREAD_INFO_LIST::const_iterator it; for (it = pProcessInfo->Threads.begin(); it != pProcessInfo->Threads.end(); ++it) { DWORD dwThreadId = it->first; HANDLE hThread = it->second.hThread; if (dwThreadId != DebugEvent.dwThreadId && ExceptionCode != STATUS_BREAKPOINT && ExceptionCode != STATUS_WX86_BREAKPOINT) { continue; } dumpStack(pProcessInfo->hProcess, hThread, NULL); } if (!DebugEvent.u.Exception.dwFirstChance) { /* * Terminate the process. As continuing would cause the JIT debugger * to be invoked again. */ fTerminating = TRUE; TerminateProcess(pProcessInfo->hProcess, (UINT)ExceptionCode); } break; } case CREATE_THREAD_DEBUG_EVENT: if (pOptions->verbose_flag) { lprintf("CREATE_THREAD PID=%lu TID=%lu\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId ); } // Add the thread to the thread list pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId]; pThreadInfo->hThread = DebugEvent.u.CreateThread.hThread; break; case CREATE_PROCESS_DEBUG_EVENT: { HANDLE hFile = DebugEvent.u.CreateProcessInfo.hFile; char szImageName[MAX_PATH]; char *lpImageName = NULL; if (hFile && GetFileNameFromHandle(hFile, szImageName, _countof(szImageName))) { lpImageName = szImageName; } if (pOptions->verbose_flag) { PCSTR lpModuleName = lpImageName ? getBaseName(lpImageName) : ""; lprintf("CREATE_PROCESS PID=%lu TID=%lu lpBaseOfImage=%p %s\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, DebugEvent.u.CreateProcessInfo.lpBaseOfImage, lpModuleName ); } hProcess = DebugEvent.u.CreateProcessInfo.hProcess; pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; pProcessInfo->hProcess = hProcess; pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId]; pThreadInfo->hThread = DebugEvent.u.CreateProcessInfo.hThread; if (!InitializeSym(hProcess, FALSE)) { OutputDebug("error: SymInitialize failed: 0x%08lx\n", GetLastError()); exit(EXIT_FAILURE); } SymRegisterCallback64(hProcess, &symCallback, 0); loadModule(hProcess, hFile, lpImageName, DebugEvent.u.CreateProcessInfo.lpBaseOfImage); break; } case EXIT_THREAD_DEBUG_EVENT: if (pOptions->verbose_flag) { lprintf("EXIT_THREAD PID=%lu TID=%lu dwExitCode=0x%lx\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, DebugEvent.u.ExitThread.dwExitCode ); } // Remove the thread from the thread list pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; hProcess = pProcessInfo->hProcess; // Dump the stack on abort() if (!fTerminating && isAbnormalExitCode(DebugEvent.u.ExitThread.dwExitCode)) { pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId]; refreshSymbolsAndDumpStack(hProcess, pThreadInfo->hThread); } pProcessInfo->Threads.erase(DebugEvent.dwThreadId); break; case EXIT_PROCESS_DEBUG_EVENT: { if (pOptions->verbose_flag) { lprintf("EXIT_PROCESS PID=%lu TID=%lu dwExitCode=0x%lx\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, DebugEvent.u.ExitProcess.dwExitCode ); } pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; hProcess = pProcessInfo->hProcess; // Dump the stack on abort() if (!fTerminating && isAbnormalExitCode(DebugEvent.u.ExitThread.dwExitCode)) { pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId]; refreshSymbolsAndDumpStack(hProcess, pThreadInfo->hThread); } // Remove the process from the process list g_Processes.erase(DebugEvent.dwProcessId); if (!SymCleanup(hProcess)) { OutputDebug("SymCleanup failed with 0x%08lx\n", GetLastError()); } if (g_Processes.empty()) { fFinished = TRUE; } break; } case LOAD_DLL_DEBUG_EVENT: { HANDLE hFile = DebugEvent.u.LoadDll.hFile; char szImageName[MAX_PATH]; char *lpImageName = NULL; if (hFile && GetFileNameFromHandle(hFile, szImageName, _countof(szImageName))) { lpImageName = szImageName; } if (pOptions->verbose_flag) { PCSTR lpModuleName = lpImageName ? getBaseName(lpImageName) : ""; lprintf("LOAD_DLL PID=%lu TID=%lu lpBaseOfDll=%p %s\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, DebugEvent.u.LoadDll.lpBaseOfDll, lpModuleName ); } pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; hProcess = pProcessInfo->hProcess; loadModule(hProcess, hFile, lpImageName, DebugEvent.u.LoadDll.lpBaseOfDll); break; } case UNLOAD_DLL_DEBUG_EVENT: if (pOptions->verbose_flag) { lprintf("UNLOAD_DLL PID=%lu TID=%lu lpBaseOfDll=%p\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, DebugEvent.u.UnloadDll.lpBaseOfDll ); } pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; hProcess = pProcessInfo->hProcess; SymUnloadModule64(hProcess, (UINT_PTR)DebugEvent.u.UnloadDll.lpBaseOfDll); break; case OUTPUT_DEBUG_STRING_EVENT: { if (pOptions->verbose_flag) { lprintf("OUTPUT_DEBUG_STRING PID=%lu TID=%lu\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId ); } pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; assert(!DebugEvent.u.DebugString.fUnicode); LPSTR lpDebugStringData = readProcessString(pProcessInfo->hProcess, DebugEvent.u.DebugString.lpDebugStringData, DebugEvent.u.DebugString.nDebugStringLength); lprintf("%s", lpDebugStringData); free(lpDebugStringData); break; } case RIP_EVENT: if (pOptions->verbose_flag) { lprintf("RIP PID=%lu TID=%lu\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId ); } break; default: if (pOptions->verbose_flag) { lprintf("EVENT%lu PID=%lu TID=%lu\r\n", DebugEvent.dwDebugEventCode, DebugEvent.dwProcessId, DebugEvent.dwThreadId ); } break; } // Resume executing the thread that reported the debugging event. ContinueDebugEvent( DebugEvent.dwProcessId, DebugEvent.dwThreadId, dwContinueStatus ); } return TRUE; }
int main(int argc, char *argv[]) { DWORD error; HANDLE process; ULONG64 module_base; SYM_CONTEXT ctx; int i; char* search; char* filename = NULL; int rv = 0; /* We may add SYMOPT_UNDNAME if --demangle is specified: */ DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--demangle") == 0 || strcmp(argv[i], "-C") == 0) { symopts |= SYMOPT_UNDNAME; } else if (strcmp(argv[i], "--help") == 0) { usage(); exit(0); } else { break; } } if (i != argc - 1) { usage(); exit(1); } filename = argv[i]; process = GetCurrentProcess(); if (!SymInitialize(process, NULL, FALSE)) { error = GetLastError(); fprintf(stderr, "SymInitialize returned error : %d\n", error); return 1; } search = malloc(SEARCH_CAP); if (SymGetSearchPath(process, search, SEARCH_CAP)) { if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) { fprintf(stderr, "Search path too long\n"); SymCleanup(process); return 1; } strcat(search, ";" WEBSYM); } else { error = GetLastError(); fprintf(stderr, "SymGetSearchPath returned error : %d\n", error); rv = 1; /* An error, but not a fatal one */ strcpy(search, WEBSYM); /* Use a default value */ } if (!SymSetSearchPath(process, search)) { error = GetLastError(); fprintf(stderr, "SymSetSearchPath returned error : %d\n", error); rv = 1; /* An error, but not a fatal one */ } SymSetOptions(symopts); module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0); if (!module_base) { /* SymLoadModuleEx failed */ error = GetLastError(); fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n", error, filename); SymCleanup(process); return 1; } ShowSymbolInfo(process, module_base); memset(&ctx, 0, sizeof(ctx)); ctx.module_base = module_base; if (!SymEnumSymbols(process, module_base, NULL, EnumSymProc, &ctx)) { error = GetLastError(); fprintf(stderr, "SymEnumSymbols returned error: %d\n", error); rv = 1; } else { DWORD j; qsort(ctx.syms, ctx.syms_len, sizeof(ctx.syms[0]), sym_cmp); for (j = 0; j < ctx.syms_len; j++) { printf("%016I64x X %s\n", ctx.syms[j].addr, ctx.syms[j].name); } /* In a perfect world, maybe we'd clean up ctx's memory? */ } SymUnloadModule64(process, module_base); SymCleanup(process); return rv; }
bool CATDbgHelper::AddressToLine( CATMemoryAddress* result ) { LOG_FUNC_ENTRY("CATDbgHelper::AddressToLine"); // Set state out of range result->SetAddressToLineState( CATMemoryAddress::OUT_OF_RANGE ); // check that dbghelper has been initialized successfully. if ( ! CDBGHELPER_OPEN ) return false; // Check has binary been moved, if so unload and load to new base address. if ( result->GetModuleStartAddress() + AT_VIRTUAL_OFFSET_DBGHELPER != m_BaseAddress ) { // Unload. if ( SymUnloadModule64( GetCurrentProcess(), m_BaseAddress ) ) { // Set new base address. m_BaseAddress = result->GetModuleStartAddress() + AT_VIRTUAL_OFFSET_DBGHELPER; // (Re)load. DWORD64 loading = SymLoadModule64( GetCurrentProcess(), NULL, m_pBinaryFile, NULL, m_BaseAddress, NULL ); if ( loading != m_BaseAddress && loading != 0) { LOG_STRING("Dbghelp:Module load failed " << (int) GetLastError()); return false; } } else LOG_STRING("Dbghelp:Module unload failed " << (int) GetLastError() ); } // Address to find (offset+given address). unsigned long iAddressToFind = result->GetAddress() + AT_VIRTUAL_OFFSET_DBGHELPER; // Displacements of line/symbol information. DWORD64 displacementSymbol; DWORD displacementLine; // Structure to get symbol information. CSymbolInfo symbol; // Structure to get line information. CLineInfo line; // Find Symbol for given address if( ! SymFromAddr( GetCurrentProcess(), iAddressToFind , &displacementSymbol, &symbol.si ) ) { LOG_STRING("Failed to find symbol information for given line."); return AddressToFunction( result ); } // Find line information if( ! SymGetLineFromAddr64( GetCurrentProcess(), iAddressToFind, &displacementLine, &line ) ) { // If it fails get symbol line information LOG_STRING("Dbghelp:Failed to find line information for address, trying for symbol of address."); if( ! SymGetLineFromAddr64( GetCurrentProcess(), symbol.si.Address, &displacementLine, &line ) ) { LOG_STRING("Dbghelp:Failed to find line information for symbol address."); return AddressToFunction( result ); } } // Set the results. result->SetFileName( string( line.FileName ) ); result->SetFunctionName( string( symbol.si.Name ) ); result->SetExactLineNumber( (int) line.LineNumber ); result->SetAddressToLineState( CATMemoryAddress::EXACT ); // Return. return true; }