std::string win_stacktrace() { void *stack[100]; unsigned short frames = CaptureStackBackTrace(0, 100, stack, NULL); SYMBOL_INFO *symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1); symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); HANDLE process = GetCurrentProcess(); std::string result; result.reserve(128); { muduo::MutexLockGuard guard( muduo::Singleton<win::SymManager>::instance().getMutex()); SymRefreshModuleList(process); char buf[512]; int count = 0; for(unsigned int i = 0; i < frames; i++) { SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol); count = snprintf(buf, sizeof(buf)-1, "%i: %s - 0x%0X\n", frames-i-1, symbol->Name, symbol->Address); if (count != -1) result.append(buf); } } free(symbol); return result; }
static void refreshSymbolsAndDumpStack(HANDLE hProcess, HANDLE hThread) { assert(hProcess); assert(hThread); // XXX: Deferred symbols don't get loaded without this SymRefreshModuleList(hProcess); dumpStack(hProcess, hThread, NULL); }
void print_stack_trace(out_stream_t *out, int signum) { handle_t process = GetCurrentProcess(); if (!SymRefreshModuleList(process)) { out_stream_printf(out, "Error refreshing module list: %i", GetLastError()); return; } out_stream_printf(out, "# Received condition %i\n", signum); // Capture the stack trace. static const size_t kMaxStackSize = 32; void *backtrace[kMaxStackSize]; size_t frame_count = CaptureStackBackTrace(0, kMaxStackSize, backtrace, NULL); // Scan through the trace one frame at a time, resolving symbols as we go. static const size_t kMaxNameLength = 128; static const size_t kSymbolInfoSize = sizeof(SYMBOL_INFO) + (kMaxNameLength * sizeof(char_t)); // A SYMBOL_INFO is variable size so we stack allocate a blob of memory and // cast it rather than stack allocate the info directly. uint8_t symbol_info_bytes[kSymbolInfoSize]; ZeroMemory(symbol_info_bytes, kSymbolInfoSize); SYMBOL_INFO *info = reinterpret_cast<SYMBOL_INFO*>(symbol_info_bytes); // This isn't strictly true, it's symbol_info_bytes, but SymFromAddr requires // it to have this value. info->SizeOfStruct = sizeof(SYMBOL_INFO); info->MaxNameLen = kMaxNameLength; for (size_t i = 0; i < frame_count; i++) { void *addr = backtrace[i]; DWORD64 addr64 = reinterpret_cast<DWORD64>(addr); if (SymFromAddr(process, addr64, 0, info)) { out_stream_printf(out, "# - 0x%p: %s\n", addr, info->Name); } else { out_stream_printf(out, "# - 0x%p\n", addr); } } }
/* ================ Sys_PrintStackTrace Occurs when we encounter a fatal error. Prints the stack trace as well as some other data. ================ */ LONG WINAPI Sys_PrintStackTrace(EXCEPTION_POINTERS* exception) { STACKFRAME frame = {}; #ifdef WIN32 DWORD machine = IMAGE_FILE_MACHINE_I386; #else DWORD machine = IMAGE_FILE_MACHINE_AMD64; #endif HANDLE process = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); int i = 0; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Mode = AddrModeFlat; #ifdef WIN32 frame.AddrPC.Offset = exception->ContextRecord->Eip; frame.AddrFrame.Offset = exception->ContextRecord->Ebp; frame.AddrStack.Offset = exception->ContextRecord->Esp; #else frame.AddrPC.Offset = exception->ContextRecord->Rip; frame.AddrFrame.Offset = exception->ContextRecord->Rbp; frame.AddrStack.Offset = exception->ContextRecord->Rsp; #endif Com_Printf("------------------------\n"); Com_Printf("Enumerate Modules:\n"); Com_Printf("------------------------\n"); SymRefreshModuleList(process); SymEnumerateModules(process, Sys_PrintModule, nullptr); Com_Printf("\n\n"); Com_Printf("------------------------\n"); Com_Printf("Stack trace : \n"); Com_Printf("------------------------\n"); while (StackWalk(machine, process, thread, &frame, exception->ContextRecord, nullptr, SymFunctionTableAccess, SymGetModuleBase, nullptr)) { DWORD moduleBase = SymGetModuleBase(process, frame.AddrPC.Offset); char moduleName[MAX_PATH]; char funcName[MAX_PATH]; char fileName[MAX_PATH]; DWORD address = frame.AddrPC.Offset; char symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 255]; PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL)symbolBuffer; IMAGEHLP_LINE line; DWORD offset = 0; line.SizeOfStruct = sizeof(IMAGEHLP_LINE); symbol->SizeOfStruct = (sizeof IMAGEHLP_SYMBOL) + 255; symbol->MaxNameLength = 254; if (moduleBase && GetModuleFileNameA((HINSTANCE)moduleBase, moduleName, MAX_PATH)) { Sys_CleanModuleName(moduleName, MAX_PATH); } else { moduleName[0] = '\0'; } if (SymGetSymFromAddr(process, frame.AddrPC.Offset, &offset, symbol)) { Q_strncpyz(funcName, symbol->Name, MAX_PATH); } else { funcName[0] = '\0'; } if (SymGetLineFromAddr(process, frame.AddrPC.Offset, &offset, &line)) { Q_strncpyz(fileName, line.FileName, MAX_PATH); Sys_CleanModuleName(fileName, MAX_PATH); Com_sprintf(fileName, MAX_PATH, "%s:%i", fileName, line.LineNumber); } else { fileName[0] = '\0'; } Com_Printf("%03i %20s 0x%08X | %s (%s)\n", i, moduleName, address, funcName, fileName); i++; } Sys_Error("Unhanded Exception: 0x%08X", exception->ExceptionRecord->ExceptionCode); #ifdef _DEBUG return EXCEPTION_CONTINUE_SEARCH; #else return EXCEPTION_EXECUTE_HANDLER; #endif }
/** * Initializes the symbol engine if needed. */ bool FWindowsPlatformStackWalk::InitStackWalking() { // DbgHelp functions are not thread safe, but this function can potentially be called from different // threads in our engine, so we take a critical section static FCriticalSection CriticalSection; FScopeLock Lock( &CriticalSection ); // Only initialize once. if( !GStackWalkingInitialized ) { void* DllHandle = FPlatformProcess::GetDllHandle( TEXT("PSAPI.DLL") ); if( DllHandle == NULL ) { return false; } // Load dynamically linked PSAPI routines. FEnumProcesses = (TFEnumProcesses) FPlatformProcess::GetDllExport( DllHandle,TEXT("EnumProcesses")); FEnumProcessModules = (TFEnumProcessModules) FPlatformProcess::GetDllExport( DllHandle,TEXT("EnumProcessModules")); #if WINVER > 0x502 FGetModuleFileNameEx = (TFGetModuleFileNameEx) FPlatformProcess::GetDllExport( DllHandle,TEXT("GetModuleFileNameExW")); FGetModuleBaseName = (TFGetModuleBaseName) FPlatformProcess::GetDllExport( DllHandle,TEXT("GetModuleBaseNameW")); #else FGetModuleFileNameEx = (TFGetModuleFileNameEx) FPlatformProcess::GetDllExport( DllHandle,TEXT("GetModuleFileNameExA")); FGetModuleBaseName = (TFGetModuleBaseName) FPlatformProcess::GetDllExport( DllHandle,TEXT("GetModuleBaseNameA")); #endif FGetModuleInformation = (TFGetModuleInformation) FPlatformProcess::GetDllExport( DllHandle,TEXT("GetModuleInformation")); // Abort if we can't look up the functions. if( !FEnumProcesses || !FEnumProcessModules || !FGetModuleFileNameEx || !FGetModuleBaseName || !FGetModuleInformation ) { return false; } // Set up the symbol engine. uint32 SymOpts = SymGetOptions(); SymOpts |= SYMOPT_LOAD_LINES; SymOpts |= SYMOPT_FAIL_CRITICAL_ERRORS; SymOpts |= SYMOPT_DEFERRED_LOADS; SymOpts |= SYMOPT_EXACT_SYMBOLS; // This option allows for undecorated names to be handled by the symbol engine. SymOpts |= SYMOPT_UNDNAME; // Disable by default as it can be very spammy/slow. Turn it on if you are debugging symbol look-up! // SymOpts |= SYMOPT_DEBUG; // Not sure these are important or desirable // SymOpts |= SYMOPT_ALLOW_ABSOLUTE_SYMBOLS; // SymOpts |= SYMOPT_CASE_INSENSITIVE; SymSetOptions( SymOpts ); // Initialize the symbol engine. const FString RemoteStorage = GetRemoteStorage(GetDownstreamStorage()); #if WINVER > 0x502 SymInitializeW( GetCurrentProcess(), RemoteStorage.IsEmpty() ? nullptr : *RemoteStorage, true ); #else SymInitialize( GetCurrentProcess(), nullptr, true ); #endif GNeedToRefreshSymbols = false; GStackWalkingInitialized = true; if (!FPlatformProperties::IsMonolithicBuild() && FPlatformStackWalk::WantsDetailedCallstacksInNonMonolithicBuilds()) { LoadProcessModules( RemoteStorage ); } } #if WINVER > 0x502 else if (GNeedToRefreshSymbols) { // Refresh and reload symbols SymRefreshModuleList( GetCurrentProcess() ); if (!FPlatformProperties::IsMonolithicBuild() && FPlatformStackWalk::WantsDetailedCallstacksInNonMonolithicBuilds()) { const FString RemoteStorage = GetRemoteStorage( GetDownstreamStorage() ); LoadProcessModules( RemoteStorage ); } GNeedToRefreshSymbols = false; } #endif return GStackWalkingInitialized; }
bool DebuggingLoop() { DEBUG_EVENT DebugEvent; CONTEXT ctxThreadContext; DWORD dwDebugState = NULL; PTCHAR sTemp = (PTCHAR)malloc(255 * sizeof(TCHAR)); szTempSym = (PCHAR)malloc(MAX_SYM_NAME); ctxThreadContext.ContextFlags = CONTEXT_FULL; while(bDebugging) { if(!WaitForDebugEvent(&DebugEvent,INFINITE)) { free(sTemp); free(szTempSym); return false; } switch(DebugEvent.dwDebugEventCode) { case LOAD_DLL_DEBUG_EVENT: { SymRefreshModuleList(piProcInfo.hProcess); dwDebugState = DBG_CONTINUE; break; } case CREATE_PROCESS_DEBUG_EVENT: { if(!bSymInit) bSymInit = SymInitialize(piProcInfo.hProcess,NULL,FALSE); dwDebugState = DBG_CONTINUE; break; } case CREATE_THREAD_DEBUG_EVENT: { HANDLE hThread = OpenThread(THREAD_ALL_ACCESS,false,DebugEvent.dwThreadId); GetThreadContext(hThread,&ctxThreadContext); ctxThreadContext.EFlags |= 0x100; SetThreadContext(hThread,&ctxThreadContext); dwDebugState = DBG_CONTINUE; break; } case EXIT_PROCESS_DEBUG_EVENT: { bDebugging = false; dwDebugState = DBG_CONTINUE; break; } case EXCEPTION_DEBUG_EVENT: { switch(DebugEvent.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_BREAKPOINT: { dwDebugState = DBG_CONTINUE; break; } case EXCEPTION_SINGLE_STEP: { HANDLE hThread = OpenThread(THREAD_ALL_ACCESS,false,DebugEvent.dwThreadId); GetThreadContext(hThread,&ctxThreadContext); InsertInfo((DWORD)DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress,DebugEvent.dwThreadId,sTemp); ctxThreadContext.EFlags |= 0x100; SetThreadContext(hThread,&ctxThreadContext); dwDebugState = DBG_CONTINUE; break; } default: dwDebugState = DBG_EXCEPTION_NOT_HANDLED; } break; } default: dwDebugState = DBG_EXCEPTION_NOT_HANDLED; } ContinueDebugEvent(DebugEvent.dwProcessId,DebugEvent.dwThreadId,dwDebugState); } free(sTemp); free(szTempSym); return false; }
TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth , void* ctx) { CONTEXT context_record; if (ctx) { context_record = *static_cast<CONTEXT*>(ctx); } else { // use the current thread's context RtlCaptureContext(&context_record); } int size = 0; std::array<void*, 50> stack; STACKFRAME64 stack_frame; memset(&stack_frame, 0, sizeof(stack_frame)); #if defined(_WIN64) int const machine_type = IMAGE_FILE_MACHINE_AMD64; stack_frame.AddrPC.Offset = context_record.Rip; stack_frame.AddrFrame.Offset = context_record.Rbp; stack_frame.AddrStack.Offset = context_record.Rsp; #else int const machine_type = IMAGE_FILE_MACHINE_I386; stack_frame.AddrPC.Offset = context_record.Eip; stack_frame.AddrFrame.Offset = context_record.Ebp; stack_frame.AddrStack.Offset = context_record.Esp; #endif stack_frame.AddrPC.Mode = AddrModeFlat; stack_frame.AddrFrame.Mode = AddrModeFlat; stack_frame.AddrStack.Mode = AddrModeFlat; while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), &stack_frame, &context_record, nullptr, &SymFunctionTableAccess64, &SymGetModuleBase64, nullptr) && size < stack.size()) { stack[size++] = reinterpret_cast<void*>(stack_frame.AddrPC.Offset); } struct symbol_bundle : SYMBOL_INFO { wchar_t name[MAX_SYM_NAME]; }; HANDLE p = GetCurrentProcess(); static bool sym_initialized = false; if (!sym_initialized) { sym_initialized = true; SymInitialize(p, NULL, true); } SymRefreshModuleList(p); for (int i = 0; i < size && len > 0; ++i) { DWORD_PTR frame_ptr = reinterpret_cast<DWORD_PTR>(stack[i]); DWORD64 displacement = 0; symbol_bundle symbol; symbol.MaxNameLen = MAX_SYM_NAME; symbol.SizeOfStruct = sizeof(SYMBOL_INFO); BOOL const has_symbol = SymFromAddr(p, frame_ptr, &displacement, &symbol); DWORD line_displacement = 0; IMAGEHLP_LINE64 line = {}; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); BOOL const has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame_ptr, &line_displacement, &line); int ret = std::snprintf(out, len, "%2d: %p", i, stack[i]); out += ret; len -= ret; if (len <= 0) break; if (has_symbol) { ret = std::snprintf(out, len, " %s +%-4" PRId64 , demangle(symbol.Name).c_str(), displacement); out += ret; len -= ret; if (len <= 0) break; } if (has_line) { ret = std::snprintf(out, len, " %s:%d" , line.FileName, line.LineNumber); out += ret; len -= ret; if (len <= 0) break; } ret = std::snprintf(out, len, "\n"); out += ret; len -= ret; if (i == max_depth && max_depth > 0) break; } }
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; }
void StackTree::refreshModuleList() { ASSERT(s_instances > 0); SymRefreshModuleList(GetCurrentProcess()); }