static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp) { // Might be called from unmanaged thread. #ifndef _CPU_X86_64_ *ip = (uintptr_t)cursor->stackframe.AddrPC.Offset; *sp = (uintptr_t)cursor->stackframe.AddrStack.Offset; if (*ip == 0 || *ip == ((uintptr_t)0)-1) { if (!readable_pointer((LPCVOID)*sp)) return 0; cursor->stackframe.AddrPC.Offset = *(DWORD32*)*sp; // POP EIP (aka RET) cursor->stackframe.AddrStack.Offset += sizeof(void*); return cursor->stackframe.AddrPC.Offset != 0; } BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread, &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, JuliaGetModuleBase64, NULL); return result; #else *ip = (uintptr_t)cursor->Rip; *sp = (uintptr_t)cursor->Rsp; if (*ip == 0 || *ip == ((uintptr_t)0)-1) { if (!readable_pointer((LPCVOID)*sp)) return 0; cursor->Rip = *(DWORD64*)*sp; // POP RIP (aka RET) cursor->Rsp += sizeof(void*); return cursor->Rip != 0; } DWORD64 ImageBase = JuliaGetModuleBase64(GetCurrentProcess(), cursor->Rip); if (!ImageBase) return 0; PRUNTIME_FUNCTION FunctionEntry = (PRUNTIME_FUNCTION)JuliaFunctionTableAccess64(GetCurrentProcess(), cursor->Rip); if (!FunctionEntry) { // assume this is a NO_FPO RBP-based function cursor->Rsp = cursor->Rbp; // MOV RSP, RBP if (!readable_pointer((LPCVOID)cursor->Rsp)) return 0; cursor->Rbp = *(DWORD64*)cursor->Rsp; // POP RBP cursor->Rsp += sizeof(void*); cursor->Rip = *(DWORD64*)cursor->Rsp; // POP RIP (aka RET) cursor->Rsp += sizeof(void*); } else { PVOID HandlerData; DWORD64 EstablisherFrame; (void)RtlVirtualUnwind( 0 /*UNW_FLAG_NHANDLER*/, ImageBase, cursor->Rip, FunctionEntry, cursor, &HandlerData, &EstablisherFrame, NULL); } return cursor->Rip != 0; #endif }
StackTrace::StackTrace(_EXCEPTION_POINTERS* exception_pointers) { // 使用StackWalk64()获得异常堆栈信息. count_ = 0; // 初始化堆栈查核行程. STACKFRAME64 stack_frame; memset(&stack_frame, 0, sizeof(stack_frame)); #if defined(_WIN64) int machine_type = IMAGE_FILE_MACHINE_AMD64; stack_frame.AddrPC.Offset = exception_pointers->ContextRecord->Rip; stack_frame.AddrFrame.Offset = exception_pointers->ContextRecord->Rbp; stack_frame.AddrStack.Offset = exception_pointers->ContextRecord->Rsp; #else int machine_type = IMAGE_FILE_MACHINE_I386; stack_frame.AddrPC.Offset = exception_pointers->ContextRecord->Eip; stack_frame.AddrFrame.Offset = exception_pointers->ContextRecord->Ebp; stack_frame.AddrStack.Offset = exception_pointers->ContextRecord->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, exception_pointers->ContextRecord, NULL, &SymFunctionTableAccess64, &SymGetModuleBase64, NULL) && count_<arraysize(trace_)) { trace_[count_++] = reinterpret_cast<void*>(stack_frame.AddrPC.Offset); } }
static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *Context) { // Might be called from unmanaged thread. if (needsSymRefreshModuleList && hSymRefreshModuleList != 0 && !jl_in_stackwalk) { jl_in_stackwalk = 1; hSymRefreshModuleList(GetCurrentProcess()); jl_in_stackwalk = 0; needsSymRefreshModuleList = 0; } #if !defined(_CPU_X86_64_) if (jl_in_stackwalk) { return 0; } jl_in_stackwalk = 1; memset(&cursor->stackframe, 0, sizeof(cursor->stackframe)); cursor->stackframe.AddrPC.Offset = Context->Eip; cursor->stackframe.AddrStack.Offset = Context->Esp; cursor->stackframe.AddrFrame.Offset = Context->Ebp; cursor->stackframe.AddrPC.Mode = AddrModeFlat; cursor->stackframe.AddrStack.Mode = AddrModeFlat; cursor->stackframe.AddrFrame.Mode = AddrModeFlat; cursor->context = *Context; BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread, &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, JuliaGetModuleBase64, NULL); jl_in_stackwalk = 0; return result; #else *cursor = *Context; return 1; #endif }
static void getStack(CONTEXT& context, char* out, int max_size) { BOOL result; HANDLE process; HANDLE thread; STACKFRAME64 stack; char symbol_mem[sizeof(IMAGEHLP_SYMBOL64) + 256]; IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)symbol_mem; DWORD64 displacement; char name[256]; copyString(out, max_size, "Crash callstack:\n"); memset(&stack, 0, sizeof(STACKFRAME64)); process = GetCurrentProcess(); thread = GetCurrentThread(); displacement = 0; DWORD machineType; #ifdef _WIN64 machineType = IMAGE_FILE_MACHINE_IA64; stack.AddrPC.Offset = context.Rip; stack.AddrPC.Mode = AddrModeFlat; stack.AddrStack.Offset = context.Rsp; stack.AddrStack.Mode = AddrModeFlat; stack.AddrFrame.Offset = context.Rbp; stack.AddrFrame.Mode = AddrModeFlat; #else machineType = IMAGE_FILE_MACHINE_I386; stack.AddrPC.Offset = context.Eip; stack.AddrPC.Mode = AddrModeFlat; stack.AddrStack.Offset = context.Esp; stack.AddrStack.Mode = AddrModeFlat; stack.AddrFrame.Offset = context.Ebp; stack.AddrFrame.Mode = AddrModeFlat; #endif do { result = StackWalk64(machineType, process, thread, &stack, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); symbol->MaxNameLength = 255; SymGetSymFromAddr64(process, (ULONG64)stack.AddrPC.Offset, &displacement, symbol); UnDecorateSymbolName(symbol->Name, (PSTR)name, 256, UNDNAME_COMPLETE); catString(out, max_size, symbol->Name); catString(out, max_size, "\n"); } while (result); }
// getStackTrace - Traces the stack as far back as possible, or until 'maxdepth' // frames have been traced. Populates the CallStack with one entry for each // stack frame traced. // // Note: This function uses a documented Windows API to walk the stack. This // API is supposed to be the most reliable way to walk the stack. It claims // to be able to walk stack frames that do not follow the conventional stack // frame layout. However, this robustness comes at a cost: it is *extremely* // slow compared to walking frames by following frame (base) pointers. // // - maxdepth (IN): Maximum number of frames to trace back. // // - framepointer (IN): Frame (base) pointer at which to begin the stack trace. // If NULL, then the stack trace will begin at this function. // // Return Value: // // None. // VOID SafeCallStack::getStackTrace (UINT32 maxdepth, const context_t& context) { UINT_PTR* framePointer = context.fp; DWORD architecture = X86X64ARCHITECTURE; CONTEXT currentContext; memset(¤tContext, 0, sizeof(currentContext)); // Get the required values for initialization of the STACKFRAME64 structure // to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame. #if defined(_M_IX86) UINT_PTR programcounter = *(framePointer + 1); UINT_PTR stackpointer = (*framePointer) - maxdepth * 10 * sizeof(void*); // An approximation. currentContext.SPREG = stackpointer; currentContext.BPREG = (DWORD64)framePointer; currentContext.IPREG = programcounter; #elif defined(_M_X64) currentContext.SPREG = context.Rsp; currentContext.BPREG = (DWORD64)framePointer; currentContext.IPREG = context.Rip; #else // If you want to retarget Visual Leak Detector to another processor // architecture then you'll need to provide architecture-specific code to // obtain the program counter and stack pointer from the given frame pointer. #error "Visual Leak Detector is not supported on this architecture." #endif // _M_IX86 || _M_X64 // Initialize the STACKFRAME64 structure. STACKFRAME64 frame; memset(&frame, 0x0, sizeof(frame)); frame.AddrPC.Offset = currentContext.IPREG; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Offset = currentContext.SPREG; frame.AddrStack.Mode = AddrModeFlat; frame.AddrFrame.Offset = currentContext.BPREG; frame.AddrFrame.Mode = AddrModeFlat; frame.Virtual = TRUE; // Walk the stack. CriticalSectionLocker cs(g_stackWalkLock); UINT32 count = 0; while (count < maxdepth) { count++; DbgTrace(L"dbghelp32.dll %i: StackWalk64\n", GetCurrentThreadId()); if (!StackWalk64(architecture, g_currentProcess, g_currentThread, &frame, ¤tContext, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { // Couldn't trace back through any more frames. break; } if (frame.AddrFrame.Offset == 0) { // End of stack. break; } // Push this frame's program counter onto the CallStack. push_back((UINT_PTR)frame.AddrPC.Offset); } }
/****************************************************************** * stack_fetch_frames * * Do a backtrace on the current thread */ unsigned stack_fetch_frames(const CONTEXT* _ctx) { STACKFRAME64 sf; unsigned nf = 0; /* as native stackwalk can modify the context passed to it, simply copy * it to avoid any damage */ CONTEXT ctx = *_ctx, prevctx = ctx; HeapFree(GetProcessHeap(), 0, dbg_curr_thread->frames); dbg_curr_thread->frames = NULL; memset(&sf, 0, sizeof(sf)); be_cpu->get_addr(dbg_curr_thread->handle, &ctx, be_cpu_addr_frame, &sf.AddrFrame); be_cpu->get_addr(dbg_curr_thread->handle, &ctx, be_cpu_addr_pc, &sf.AddrPC); be_cpu->get_addr(dbg_curr_thread->handle, &ctx, be_cpu_addr_stack, &sf.AddrStack); /* don't confuse StackWalk by passing in inconsistent addresses */ if ((sf.AddrPC.Mode == AddrModeFlat) && (sf.AddrFrame.Mode != AddrModeFlat)) { sf.AddrFrame.Offset = (ULONG_PTR)memory_to_linear_addr(&sf.AddrFrame); sf.AddrFrame.Mode = AddrModeFlat; } while (StackWalk64(be_cpu->machine, dbg_curr_process->handle, dbg_curr_thread->handle, &sf, &ctx, stack_read_mem, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { dbg_curr_thread->frames = dbg_heap_realloc(dbg_curr_thread->frames, (nf + 1) * sizeof(dbg_curr_thread->frames[0])); dbg_curr_thread->frames[nf].addr_pc = sf.AddrPC; dbg_curr_thread->frames[nf].linear_pc = (DWORD_PTR)memory_to_linear_addr(&sf.AddrPC); dbg_curr_thread->frames[nf].addr_frame = sf.AddrFrame; dbg_curr_thread->frames[nf].linear_frame = (DWORD_PTR)memory_to_linear_addr(&sf.AddrFrame); dbg_curr_thread->frames[nf].addr_stack = sf.AddrStack; dbg_curr_thread->frames[nf].linear_stack = (DWORD_PTR)memory_to_linear_addr(&sf.AddrStack); dbg_curr_thread->frames[nf].context = prevctx; /* FIXME: can this heuristic be improved: we declare first context always valid, and next ones * if it has been modified by the call to StackWalk... */ dbg_curr_thread->frames[nf].is_ctx_valid = (nf == 0 || (dbg_curr_thread->frames[nf - 1].is_ctx_valid && memcmp(&dbg_curr_thread->frames[nf - 1].context, &ctx, sizeof(ctx)))); prevctx = ctx; nf++; /* we've probably gotten ourselves into an infinite loop so bail */ if (nf > 200) break; } dbg_curr_thread->curr_frame = -1; dbg_curr_thread->num_frames = nf; stack_set_frame_internal(0); return nf; }
void stack_walk(CString& strStack, PCONTEXT p_context) { CONTEXT * pContext = p_context; HANDLE hCurrentProcess = ::GetCurrentProcess(); HANDLE hCurrentThread = ::GetCurrentThread(); STACKFRAME64 sStackFrame; memset(&sStackFrame,0,sizeof(STACKFRAME64)); sStackFrame.AddrPC.Offset = pContext->Eip; sStackFrame.AddrPC.Mode = AddrModeFlat; sStackFrame.AddrStack.Offset= pContext->Esp; sStackFrame.AddrStack.Mode = AddrModeFlat; sStackFrame.AddrFrame.Offset= pContext->Ebp; sStackFrame.AddrFrame.Mode = AddrModeFlat; USES_CONVERSION; //TCHAR atszCallbackBuffer[1024]; //DWORD dwLen = 0; SymInitialize(GetCurrentProcess(),NULL,TRUE); while(StackWalk64(IMAGE_FILE_MACHINE_I386,hCurrentProcess,hCurrentThread,&sStackFrame,pContext,0,0,0,0)) { if( sStackFrame.AddrFrame.Offset == 0 ) { break; } strStack.Format(L"%s[%08X]", strStack,sStackFrame.AddrPC.Offset); BYTE sym_buffer[sizeof(IMAGEHLP_SYMBOL) + 512]; PIMAGEHLP_SYMBOL p_symbol = (PIMAGEHLP_SYMBOL)sym_buffer; p_symbol->SizeOfStruct = sizeof(sym_buffer); p_symbol->MaxNameLength = 512; // Displacement of the input address, relative to the start of the symbol DWORD sym_displacement = 0; if (!SymGetSymFromAddr(::GetCurrentProcess(), sStackFrame.AddrPC.Offset, &sym_displacement, p_symbol)) { p_symbol->Name[0] = 0; } TCHAR sz_module[MAX_PATH] = {0}; UINT_PTR section = 0, offset = 0; get_logical_address((PVOID)(UINT_PTR)sStackFrame.AddrPC.Offset, sz_module, sizeof(sz_module)); strStack.Format(L"%s\t%s\t%s\r\n",strStack,A2T(p_symbol->Name),sz_module); } SymCleanup(GetCurrentProcess()); }
uint SymEngine::GetCallstack(HANDLE hThread, CONTEXT& context, CallStackBuffer& callstack) { // We can't initialize dbghelp.dll here => http://microsoft.public.windbg.narkive.com/G2WkSt2k/stackwalk64-performance-problems // Otherwise it will be 5x times slower // Init(); STACKFRAME64 stackFrame; memset(&stackFrame, 0, sizeof(STACKFRAME64)); DWORD machineType; stackFrame.AddrPC.Mode = AddrModeFlat; stackFrame.AddrFrame.Mode = AddrModeFlat; stackFrame.AddrStack.Mode = AddrModeFlat; #ifdef _M_IX86 machineType = IMAGE_FILE_MACHINE_I386; stackFrame.AddrPC.Offset = context.Eip; stackFrame.AddrFrame.Offset = context.Ebp; stackFrame.AddrStack.Offset = context.Esp; #elif _M_X64 machineType = IMAGE_FILE_MACHINE_AMD64; stackFrame.AddrPC.Offset = context.Rip; stackFrame.AddrFrame.Offset = context.Rsp; stackFrame.AddrStack.Offset = context.Rsp; #elif _M_IA64 machineType = IMAGE_FILE_MACHINE_IA64; stackFrame.AddrPC.Offset = context.StIIP; stackFrame.AddrFrame.Offset = context.IntSp; stackFrame.AddrStack.Offset = context.IntSp; stackFrame.AddrBStore.Offset = context.RsBSP; stackFrame.AddrBStore.Mode = AddrModeFlat; #else #error "Platform not supported!" #endif uint index = 0; while ( StackWalk64(machineType, GetCurrentProcess(), hThread, &stackFrame, &context, nullptr, &SymFunctionTableAccess64, &SymGetModuleBase64, nullptr) ) { DWORD64 dwAddress = stackFrame.AddrPC.Offset; if (!dwAddress) break; if (index == callstack.size()) return 0; // Too long callstack - possible error, let's skip it if (index > 0 && callstack[index - 1] == dwAddress) continue; callstack[index] = dwAddress; ++index; } return index; }
size_t backtrace_from_exception( LPEXCEPTION_POINTERS exception, void** frames, size_t n_frames) { std::call_once(sym_init_once, sym_init); auto context = exception->ContextRecord; auto thread = GetCurrentThread(); STACKFRAME64 frame; DWORD image; size_t i = 0; #ifdef _M_IX86 image = IMAGE_FILE_MACHINE_I386; frame.AddrPC.Offset = context->Eip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context->Ebp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = context->Esp; frame.AddrStack.Mode = AddrModeFlat; #elif _M_X64 image = IMAGE_FILE_MACHINE_AMD64; frame.AddrPC.Offset = context->Rip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context->Rsp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = context->Rsp; frame.AddrStack.Mode = AddrModeFlat; #elif _M_IA64 image = IMAGE_FILE_MACHINE_IA64; frame.AddrPC.Offset = context->StIIP; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context->IntSp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrBStore.Offset = context->RsBSP; frame.AddrBStore.Mode = AddrModeFlat; frame.AddrStack.Offset = context->IntSp; frame.AddrStack.Mode = AddrModeFlat; #else return 0; // No stack trace for you! #endif while (i < n_frames && StackWalk64( image, proc, thread, &frame, context, nullptr, nullptr, nullptr, nullptr)) { frames[i++] = (void*)frame.AddrPC.Offset; } return i; }
void MemoryManager::RecordStackTrace(AllocHeader* pAllocation) { #ifdef USE_STACKTRACE LPRtlCaptureContext pfnRtlCaptureContext=(LPRtlCaptureContext)GetProcAddress(GetModuleHandleW(L"kernel32.dll"),"RtlCaptureContext"); if(!pfnRtlCaptureContext) { return; } CONTEXT ctx; pfnRtlCaptureContext(&ctx); STACKFRAME64 theStackFrame; memset(&theStackFrame,0,sizeof(theStackFrame)); #ifdef _M_IX86 DWORD dwMachineType=IMAGE_FILE_MACHINE_I386; theStackFrame.AddrPC.Offset=ctx.Eip; theStackFrame.AddrPC.Mode=AddrModeFlat; theStackFrame.AddrFrame.Offset=ctx.Ebp; theStackFrame.AddrFrame.Mode=AddrModeFlat; theStackFrame.AddrStack.Offset=ctx.Esp; theStackFrame.AddrStack.Mode=AddrModeFlat; #elif _M_X64 DWORD dwMachineType=IMAGE_FILE_MACHINE_AMD64; theStackFrame.AddrPC.Offset=ctx.Rip; theStackFrame.AddrPC.Mode=AddrModeFlat; theStackFrame.AddrFrame.Offset=ctx.Rsp; theStackFrame.AddrFrame.Mode=AddrModeFlat; theStackFrame.AddrStack.Offset=ctx.Rsp; theStackFrame.AddrStack.Mode=AddrModeFlat; #elif _M_IA64 DWORD dwMachineType=IMAGE_FILE_MACHINE_IA64; theStackFrame.AddrPC.Offset=ctx.StIIP; theStackFrame.AddrPC.Mode=AddrModeFlat; theStackFrame.AddrFrame.Offset=ctx.IntSp; theStackFrame.AddrFrame.Mode=AddrModeFlat; theStackFrame.AddrBStore.Offset=ctx.RsBSP; theStackFrame.AddrBStore.Mode=AddrModeFlat; theStackFrame.AddrStack.Offset=ctx.IntSp; theStackFrame.AddrStack.Mode=AddrModeFlat; #else # error "Platform not supported!" #endif memset(pAllocation->nPC,0,sizeof(pAllocation->nPC)); for(int i=0;i<AllocHeader::cnMaxStackFrames;++i) { pAllocation->nPC[i]=theStackFrame.AddrPC.Offset; if(!StackWalk64(dwMachineType,GetCurrentProcess(),GetCurrentThread(),&theStackFrame,&ctx,NULL,SymFunctionTableAccess64,SymGetModuleBase64,NULL)) { break; } } #endif UNREFERENCED_PARAMETER(pAllocation); }
static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp) { // Might be called from unmanaged thread. #ifndef _CPU_X86_64_ *ip = (uintptr_t)cursor->stackframe.AddrPC.Offset; *sp = (uintptr_t)cursor->stackframe.AddrStack.Offset; BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread, &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, JuliaGetModuleBase64, NULL); return result; #else *ip = (uintptr_t)cursor->Rip; *sp = (uintptr_t)cursor->Rsp; DWORD64 ImageBase = JuliaGetModuleBase64(GetCurrentProcess(), cursor->Rip); if (!ImageBase) return 0; PRUNTIME_FUNCTION FunctionEntry = (PRUNTIME_FUNCTION)JuliaFunctionTableAccess64(GetCurrentProcess(), cursor->Rip); if (!FunctionEntry) { // assume this is a NO_FPO RBP-based function MEMORY_BASIC_INFORMATION mInfo; cursor->Rsp = cursor->Rbp; // MOV RSP, RBP // Check whether the pointer is valid and executable before dereferencing // to avoid segfault while recording. See #10638. if (VirtualQuery((LPCVOID)cursor->Rsp, &mInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) return 0; DWORD X = mInfo.AllocationProtect; if (!((X&PAGE_READONLY) || (X&PAGE_READWRITE) || (X&PAGE_WRITECOPY) || (X&PAGE_EXECUTE_READ)) || (X&PAGE_GUARD) || (X&PAGE_NOACCESS)) return 0; cursor->Rbp = *(DWORD64*)cursor->Rsp; // POP RBP cursor->Rsp = cursor->Rsp + sizeof(void*); cursor->Rip = *(DWORD64*)cursor->Rsp; // POP RIP (aka RET) cursor->Rsp = cursor->Rsp + sizeof(void*); } else { PVOID HandlerData; DWORD64 EstablisherFrame; (void)RtlVirtualUnwind( 0 /*UNW_FLAG_NHANDLER*/, ImageBase, cursor->Rip, FunctionEntry, cursor, &HandlerData, &EstablisherFrame, NULL); } return cursor->Rip != 0; #endif }
void CDebugger::PrintCallStack(DWORD dwThreadId, DWORD dwProcessId) { STACKFRAME64 stackFrame = { 0 }; const DWORD_PTR dwMaxFrames = 50; UpdateContext(dwThreadId); stackFrame.AddrPC.Mode = AddrModeFlat; stackFrame.AddrFrame.Mode = AddrModeFlat; stackFrame.AddrStack.Mode = AddrModeFlat; DWORD dwMachineType = IMAGE_FILE_MACHINE_I386; stackFrame.AddrPC.Offset = m_context.Eip; stackFrame.AddrFrame.Offset = m_context.Ebp; stackFrame.AddrStack.Offset = m_context.Esp; HANDLE hThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, dwThreadId); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); m_pSymbols->RefreshSymbols(hProcess); // Print call stack stringstream ssCallStack; for (int i = 0; i < dwMaxFrames; ++i) { bool bSuccess = StackWalk64(dwMachineType, hProcess, hThread, &stackFrame, (dwMachineType == IMAGE_FILE_MACHINE_I386 ? nullptr : &m_context), nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr); if (!bSuccess || stackFrame.AddrPC.Offset == 0) { cout << "StackWalk64 finished." << endl; break; } IMAGEHLP_MODULE64 module = {0}; module.SizeOfStruct = sizeof(module); SymGetModuleInfo64(hProcess, (DWORD64)stackFrame.AddrPC.Offset, &module); //SymLoadModuleEx(hProcess, NULL, module.LoadedImageName, NULL, module.BaseOfImage, 0, NULL, 0); //cout << "modulePath: " << module.LoadedImageName << ", baseofdll: " << module.BaseOfImage << ", symbol: " << module.LoadedPdbName << endl; PSYMBOL_INFO pSymInfo = m_pSymbols->SymbolFromAddress(stackFrame.AddrPC.Offset); if (pSymInfo) { ssCallStack << "#" << dec << i << " " << module.ModuleName << "!" << pSymInfo->Name << endl; } else { ssCallStack << "#" << dec << i << " " << module.ModuleName << "!" << "unknown" << endl; } delete pSymInfo; } m_pCrash->GetHash(ssCallStack.str()); m_pCrash->AddLog("\nCall Stack\n" + ssCallStack.str()); }
/* * StackTracer::Walk * Walks on the stack, each walk is one frame of backtrace * Returns a frame or null if the walk on the park is not possible anymore */ StackTracer::Trace* StackTracer::Walk() { if (StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &frame, &context, NULL, NULL, NULL, NULL)) { trace.module = GetModuleFromAddress((void*)frame.AddrPC.Offset); trace.frame = (void*)frame.AddrFrame.Offset; trace.stack = (void*)frame.AddrStack.Offset; trace.pc = (void*)frame.AddrPC.Offset; trace.ret = (void*)frame.AddrReturn.Offset; return &trace; } return nullptr; }
void generate_stack_walk(std::ostream & os, CONTEXT ctx, int skip) { STACKFRAME64 sf = {}; #ifdef _M_IX86 DWORD machine_type = IMAGE_FILE_MACHINE_I386; sf.AddrPC.Offset = ctx.Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = ctx.Esp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = ctx.Ebp; sf.AddrFrame.Mode = AddrModeFlat; #elif defined(_M_X64) DWORD machine_type = IMAGE_FILE_MACHINE_AMD64; sf.AddrPC.Offset = ctx.Rip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = ctx.Rsp; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrStack.Offset = ctx.Rsp; sf.AddrStack.Mode = AddrModeFlat; #else #error Unsupported platform #endif HANDLE process = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); os << std::uppercase; for (;;) { SetLastError(0); BOOL stack_walk_ok = StackWalk64(machine_type, process, thread, &sf, &ctx, 0, &SymFunctionTableAccess64, &SymGetModuleBase64, 0); if (!stack_walk_ok || !sf.AddrFrame.Offset) return; if (skip) { --skip; } else { // write the address os << std::hex << reinterpret_cast<void *>(sf.AddrPC.Offset) << "|" << std::dec; write_module_name(os, process, sf.AddrPC.Offset); write_function_name(os, process, sf.AddrPC.Offset); write_file_and_line(os, process, sf.AddrPC.Offset); os << "\n"; } } }
static LONG WINAPI TopLevelExceptionFilter(_EXCEPTION_POINTERS* exceptionInfo) { static struct { LONG used; CONTEXT contextRecord; STACKFRAME64 stackFrame; PVOID addrOffsets[32]; } work; if( InterlockedExchange(&work.used, 1) == 0 ){ SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); if( SymInitialize(GetCurrentProcess(), NULL, TRUE) ){ work.addrOffsets[0] = exceptionInfo->ExceptionRecord->ExceptionAddress; work.contextRecord = *exceptionInfo->ContextRecord; work.stackFrame.AddrPC.Mode = AddrModeFlat; work.stackFrame.AddrFrame.Mode = AddrModeFlat; work.stackFrame.AddrStack.Mode = AddrModeFlat; #if defined(_M_IX86) || defined(_M_X64) #ifdef _M_X64 work.stackFrame.AddrPC.Offset = work.contextRecord.Rip; work.stackFrame.AddrFrame.Offset = work.contextRecord.Rbp; work.stackFrame.AddrStack.Offset = work.contextRecord.Rsp; #else work.stackFrame.AddrPC.Offset = work.contextRecord.Eip; work.stackFrame.AddrFrame.Offset = work.contextRecord.Ebp; work.stackFrame.AddrStack.Offset = work.contextRecord.Esp; #endif for( int i = 1; i < _countof(work.addrOffsets) - 1 && StackWalk64( #ifdef _M_X64 IMAGE_FILE_MACHINE_AMD64, #else IMAGE_FILE_MACHINE_I386, #endif GetCurrentProcess(), GetCurrentThread(), &work.stackFrame, &work.contextRecord, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); i++ ){ work.addrOffsets[i] = (PVOID)work.stackFrame.AddrPC.Offset; } #endif OutputStackTrace(exceptionInfo->ExceptionRecord->ExceptionCode, work.addrOffsets); SymCleanup(GetCurrentProcess()); } } return EXCEPTION_CONTINUE_SEARCH; }
void StackWalker::GenerateStackTrace(std::ostream& os, CONTEXT ctx, int skip) { STACKFRAME64 sf = {}; sf.AddrPC.Offset = ctx.Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = ctx.Esp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = ctx.Ebp; sf.AddrFrame.Mode = AddrModeFlat; HANDLE process = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); os << std::uppercase; for (;;) { SetLastError(0); BOOL stack_walk_ok = StackWalk64( IMAGE_FILE_MACHINE_I386, process, thread, &sf, &ctx, 0, &SymFunctionTableAccess64, &SymGetModuleBase64, 0); if (!stack_walk_ok || !sf.AddrFrame.Offset) return; if (skip) { --skip; } else { // write the address os << std::hex << reinterpret_cast<void *>(sf.AddrPC.Offset) << " | " << std::dec; WriteModuleName(os, process, sf.AddrPC.Offset); WriteFunctionName(os, process, sf.AddrPC.Offset); WriteFileAndLine(os, process, sf.AddrPC.Offset); os << "\n"; } } }
void CExceptionParser::ParseCallStack(PCONTEXT pContextRecord,UINT MaxLoopCount) { if(m_hProcess==NULL) return; static HINSTANCE LastInstance=NULL; static ADDRESS_INFO AddressInfo; static STACKFRAME64 StackFrame; ZeroMemory(&StackFrame,sizeof(StackFrame)); StackFrame.AddrPC.Offset=pContextRecord->Eip; StackFrame.AddrPC.Mode=AddrModeFlat; StackFrame.AddrStack.Offset=pContextRecord->Esp; StackFrame.AddrStack.Mode=AddrModeFlat; StackFrame.AddrFrame.Offset=pContextRecord->Ebp; StackFrame.AddrFrame.Mode=AddrModeFlat; while(MaxLoopCount&&StackWalk64(IMAGE_FILE_MACHINE_I386,m_hProcess,GetCurrentThread(), &StackFrame,pContextRecord,0,SymFunctionTableAccess64,SymGetModuleBase64,0)) { if(StackFrame.AddrFrame.Offset==0) break; if(GetAddressInfo(StackFrame.AddrPC.Offset,&AddressInfo)) { if(LastInstance!=AddressInfo.hInstance) { LastInstance=AddressInfo.hInstance; PrintLog("调用模块:%s",AddressInfo.ModuleName); } PrintLog("调用地址:0x%X",(DWORD)StackFrame.AddrPC.Offset); PrintLog("地址描述:函数(%s),文件(%s)(%d)",AddressInfo.SymbolInfo.Name,AddressInfo.CppFileName,AddressInfo.LineNumber); } MaxLoopCount--; } }
int KDumpModuleAnalyzer::MoveStack() { int nResult = false; int nRetCode = false; nRetCode = StackWalk64( IMAGE_FILE_MACHINE_I386, m_hProcess, m_hThread, &m_Stackframe, &m_Context, NULL,//ReadProcessMemory, SymFunctionTableAccess64, SymGetModuleBase64, NULL ); KG_PROCESS_ERROR(nRetCode); if (m_Stackframe.AddrPC.Offset != m_Stackframe.AddrReturn.Offset) { m_nCurRecursionCount = 0; } else { m_nCurRecursionCount++; KG_PROCESS_ERROR(m_nCurRecursionCount < MAX_RECURSION_COUNT); } m_dwStackAddress = m_Stackframe.AddrPC.Offset; nResult = true; Exit0: #ifdef OPEN_LOG_AND_BREAK KLogPrintf("MoveStack:%s", nResult ? "Success" : "Fail"); #endif return nResult; }
int ZCE_LIB::backtrace_stack(ZCE_LOG_PRIORITY dbg_lvl, const char *dbg_info) { //跟踪函数的层数 const size_t SIZE_OF_BACKTRACE_FUNC = 100; #if defined(ZCE_OS_LINUX) ZCE_LOG(dbg_lvl, "[BACKTRACE]This program compiled by Linux GCC. %s", dbg_info); //Windows 下必须是2008或者VISTA之后的SDK才支持, #elif defined(ZCE_OS_WINDOWS) && ZCE_SUPPORT_WINSVR2008 == 1 ZCE_LOG(dbg_lvl, "[BACKTRACE]This program compiled by Windows Visual studio .%s", dbg_info); #else ZCE_UNUSED_ARG(SIZE_OF_BACKTRACE_FUNC); ZCE_LOG(dbg_lvl, "[BACKTRACE]back_trace_stack don't support this system.%s", dbg_info); #endif //这个方法是提供给Linux 下的GCC使用的 #if defined(ZCE_OS_LINUX) void *backtrace_buffer[SIZE_OF_BACKTRACE_FUNC]; char **symbols_strings; int sz_of_stack = ::backtrace(backtrace_buffer, SIZE_OF_BACKTRACE_FUNC); // symbols_strings = ::backtrace_symbols(backtrace_buffer, sz_of_stack); if (symbols_strings == NULL) { ZCE_LOG(dbg_lvl, "%s", "[BACKTRACE] backtrace_symbols return fail."); } //打印所有的堆栈信息,有些时候信息无法显示符号表,建议使用 for (int j = 0; j < sz_of_stack; j++) { ZCE_LOG(dbg_lvl, "[BACKTRACE] %u, %s.", j + 1, symbols_strings[j]); } //释放空间 ::free(symbols_strings); #elif defined(ZCE_OS_WINDOWS) && ZCE_SUPPORT_WINSVR2008 == 1 //我还没有时间看完dbghelp所有的东西,目前的代码参考后一个版本居多,目前这个东东必须有pdb文件, //http://blog.csdn.net/skies457/article/details/7201185 // Max length of symbols' name. const size_t MAX_NAME_LENGTH = 256; // Store register addresses. CONTEXT context; // Call stack. STACKFRAME64 stackframe; // Handle to current process & thread. HANDLE process, cur_thread; // Generally it can be subsitituted with 0xFFFFFFFF & 0xFFFFFFFE. // Debugging symbol's information. PSYMBOL_INFO symbol; // Source information (file name & line number) IMAGEHLP_LINE64 source_info; // Source line displacement. DWORD displacement; // Initialize PSYMBOL_INFO structure. // Allocate a properly-sized block. symbol = (PSYMBOL_INFO)malloc(sizeof(SYMBOL_INFO) + (MAX_NAME_LENGTH) * sizeof(char)); memset(symbol, 0, sizeof(SYMBOL_INFO) + (MAX_NAME_LENGTH) * sizeof(TCHAR)); symbol->SizeOfStruct = sizeof(SYMBOL_INFO); // SizeOfStruct *MUST BE* set to sizeof(SYMBOL_INFO). symbol->MaxNameLen = MAX_NAME_LENGTH; // Initialize IMAGEHLP_LINE64 structure. memset(&source_info, 0, sizeof(IMAGEHLP_LINE64)); source_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); // Initialize STACKFRAME64 structure. RtlCaptureContext(&context); // Get context. memset(&stackframe, 0, sizeof(STACKFRAME64)); // Fill in register addresses (EIP, ESP, EBP). stackframe.AddrPC.Mode = AddrModeFlat; stackframe.AddrStack.Mode = AddrModeFlat; stackframe.AddrFrame.Mode = AddrModeFlat; #if defined ZCE_WIN32 stackframe.AddrPC.Offset = context.Eip; stackframe.AddrStack.Offset = context.Esp; stackframe.AddrFrame.Offset = context.Ebp; #elif defined ZCE_WIN64 stackframe.AddrPC.Offset = context.Rip; stackframe.AddrStack.Offset = context.Rsp; stackframe.AddrFrame.Offset = context.Rbp; #else #endif // Get current process & thread. process = GetCurrentProcess(); cur_thread = GetCurrentThread(); // Initialize dbghelp library. if (!SymInitialize(process, NULL, TRUE)) { return -1; } //这些空间是绝对足够的,我也不做详细的检查了 const size_t LINE_OUTLEN = 1024; char line_out[LINE_OUTLEN]; int use_len = 0; uint32_t k = 0; // Enumerate call stack frame. while (StackWalk64(IMAGE_FILE_MACHINE_I386, process, cur_thread, &stackframe, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { use_len = 0; // End reaches. if (stackframe.AddrFrame.Offset == 0 || k > SIZE_OF_BACKTRACE_FUNC) { break; } // Get symbol. if (SymFromAddr(process, stackframe.AddrPC.Offset, NULL, symbol)) { use_len += snprintf(line_out + use_len, LINE_OUTLEN - use_len, " %s", symbol->Name); } if (SymGetLineFromAddr64(process, stackframe.AddrPC.Offset, &displacement, &source_info)) { // Get source information. use_len += snprintf(line_out + use_len, LINE_OUTLEN - use_len, "\t[ %s: %d] at addr 0x % 08LX", source_info.FileName, source_info.LineNumber, stackframe.AddrPC.Offset); } else { // If err_code == 0x1e7, no symbol was found. if (GetLastError() == 0x1E7) { use_len += snprintf(line_out + use_len, LINE_OUTLEN - use_len, "%s", "\tNo debug symbol loaded for this function."); } } ZCE_LOG(dbg_lvl, "[BACKTRACE] %u, %s.", k + 1, line_out); ++k; } SymCleanup(process); // Clean up and exit. free(symbol); #endif // return 0; }
/** * 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; } }
bool DebugInfo::SendStackTrace() #endif { const unsigned int maxTrace = 256; void* stacktrace[maxTrace]; #ifdef _WIN32 #ifndef _MSC_VER CONTEXT context; LPCONTEXT ctx = NULL; HMODULE kernel32 = LoadLibrary("kernel32.dll"); HMODULE dbghelp = LoadLibrary("dbghelp.dll"); if ((!kernel32) || (!dbghelp)) { return(false); } RtlCaptureContextType RtlCaptureContext = (RtlCaptureContextType)(GetProcAddress(kernel32, "RtlCaptureContext")); SymInitializeType SymInitialize = (SymInitializeType)(GetProcAddress(dbghelp, "SymInitialize")); SymCleanupType SymCleanup = (SymCleanupType)(GetProcAddress(dbghelp, "SymCleanup")); StackWalkType StackWalk64 = (StackWalkType)(GetProcAddress(dbghelp, "StackWalk64")); PFUNCTION_TABLE_ACCESS_ROUTINE64 SymFunctionTableAccess64 = (PFUNCTION_TABLE_ACCESS_ROUTINE64)(GetProcAddress(dbghelp, "SymFunctionTableAccess64")); PGET_MODULE_BASE_ROUTINE64 SymGetModuleBase64 = (PGET_MODULE_BASE_ROUTINE64)(GetProcAddress(dbghelp, "SymGetModuleBase64")); if ((!SymInitialize) || (!StackWalk64) || (!SymFunctionTableAccess64) || (!SymGetModuleBase64) || (!RtlCaptureContext)) { return(false); } #endif if (!SymInitialize(GetCurrentProcess(), NULL, true)) { return(false); } #ifndef _MSC_VER if (!ctx) { context.ContextFlags = CONTEXT_FULL; RtlCaptureContext(&context); ctx = &context; } #endif STACKFRAME64 frame; memset(&frame, 0, sizeof(frame)); #ifdef _WIN64 frame.AddrPC.Offset = ctx->Rip; frame.AddrStack.Offset = ctx->Rsp; frame.AddrFrame.Offset = ctx->Rbp; #else frame.AddrPC.Offset = ctx->Eip; frame.AddrStack.Offset = ctx->Esp; frame.AddrFrame.Offset = ctx->Ebp; #endif frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Mode = AddrModeFlat; frame.AddrFrame.Mode = AddrModeFlat; HANDLE process = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); unsigned num_frames = 0; while (StackWalk64( #ifdef _WIN64 IMAGE_FILE_MACHINE_AMD64, #else IMAGE_FILE_MACHINE_I386, #endif process, thread, &frame, ctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL) && (num_frames < maxTrace)) { LOG.lprintf("Reading stack frame %d\n", num_frames); stacktrace[num_frames++] = (void*) frame.AddrPC.Offset; } SymCleanup(GetCurrentProcess()); /*CaptureStackBackTraceType CaptureStackBackTrace = (CaptureStackBackTraceType)(GetProcAddress(LoadLibraryA("kernel32.dll"), "RtlCaptureStackBackTrace")); if (!CaptureStackBackTrace) { return(false); } unsigned num_frames = CaptureStackBackTrace(0, maxTrace, stacktrace, NULL); LOG.lprintf("Read Frames %d\n", num_frames); */ #else unsigned num_frames = backtrace(stacktrace, maxTrace); #endif LOG.lprintf("Will now send %d stack frames\n", num_frames); if (!SendString("StackTrace")) return(false); num_frames *= sizeof(void*); return(SendString((char*) &stacktrace, num_frames)); }
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; } }
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); }
void DoStackWalk (LPCONTEXT lpContextRecord) { STACKFRAME64 stackFrame = {0}; CONTEXT context; HANDLE hProcess, hThread; ////CallstackEntry csEntry; ////IMAGEHLP_SYMBOL64 *pSym = NULL; ////IMAGEHLP_MODULE64_V2 Module; ////IMAGEHLP_LINE64 Line; LPBYTE caller; // Ptr to caller in stack trace APLU3264 nearAddress, // Offset from closest address nearIndex, // Index into StartAddresses nearAddress0, // Offset from closest address nearIndex0, // Index into StartAddresses nearAddress1, // Offset from closest address nearIndex1; // Index into StartAddresses WCHAR wszTemp[1024]; // Temp output save area ////char szAppDPFE[_MAX_PATH], //// szDir [_MAX_DIR], //// szDrive[_MAX_DRIVE], //// szSymPath[_MAX_PATH]; ////PSYMBOL_INFO lpSymInfo; // Ptr to ... // Initialize the handles hProcess = GetCurrentProcess (); hThread = GetCurrentThread (); ////// Allocate space for the symbol name struc ////pSym = (IMAGEHLP_SYMBOL64 *) malloc (sizeof (IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); ////if (!pSym) //// goto CLEANUP; // Not enough memory... ////memset (pSym, 0, sizeof (IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); ////pSym->SizeOfStruct = sizeof (IMAGEHLP_SYMBOL64); ////pSym->MaxNameLength = STACKWALK_MAX_NAMELEN; ////// Allocate space for the symbol info struc ////lpSymInfo = (PSYMBOL_INFO) malloc (sizeof (SYMBOL_INFO) + STACKWALK_MAX_NAMELEN); ////if (lpSymInfo EQ NULL) //// goto CLEANUP; // Not enough memory... ////memset (lpSymInfo, 0, sizeof (SYMBOL_INFO) + STACKWALK_MAX_NAMELEN); ////lpSymInfo->SizeOfStruct = sizeof (SYMBOL_INFO); ////lpSymInfo->MaxNameLen = STACKWALK_MAX_NAMELEN; ////memset (&Line, 0, sizeof (Line)); ////Line.SizeOfStruct = sizeof (Line); ////memset (&Module, 0, sizeof (Module)); ////Module.SizeOfStruct = sizeof (Module); ////if (GetModuleFileNameA (_hInstance, szAppDPFE, sizeof (szSymPath))) ////{ //// // Split out the drive and path from the module filename //// _splitpath (szAppDPFE, szDrive, szDir, NULL, NULL); //// //// // Create the .HLP file name //// _makepath (szSymPath, szDrive, szDir, NULL, NULL); ////} else //// szSymPath[0] = '\0'; //// ////// Set the symbol options ////SymSetOptions (SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); //// ////// Initialize the symbols ////SymInitialize (hProcess, szSymPath, TRUE); // Copy the outer ContextRecord context = *lpContextRecord; // Initialize these fields before the first call to StackWalk64 #ifdef _WIN64 stackFrame.AddrPC.Offset = lpContextRecord->Rip; // Starting instruction address stackFrame.AddrFrame.Offset = lpContextRecord->Rbp; // Starting frame address stackFrame.AddrStack.Offset = lpContextRecord->Rsp; // Starting stack address #elif defined (_WIN32) stackFrame.AddrPC.Offset = lpContextRecord->Eip; // Starting instruction address stackFrame.AddrFrame.Offset = lpContextRecord->Ebp; // Starting frame address stackFrame.AddrStack.Offset = lpContextRecord->Esp; // Starting stack address #else #error Need code for this architecture. #endif stackFrame.AddrPC.Segment = 0; // Used for 16-bit addressing only stackFrame.AddrPC.Mode = AddrModeFlat; // Use flat mode addressing stackFrame.AddrFrame.Segment = 0; // Used for 16-bit addressing only stackFrame.AddrFrame.Mode = AddrModeFlat; // Use flat mode addressing stackFrame.AddrStack.Segment = 0; // Used for 16-bit addressing only stackFrame.AddrStack.Mode = AddrModeFlat; // Use flat mode addressing // Walk the stack while (StackWalk64 ( #ifdef _WIN64 IMAGE_FILE_MACHINE_AMD64, // Machine architecture type #elif defined (_WIN32) IMAGE_FILE_MACHINE_I386, // Machine architecture type #else #error Need code for this architecture. #endif hProcess, // Process handle hThread, // Thread handle &stackFrame, // Ptr to stack frame (input/output) &context, // Ptr to context struc (output) NULL, // Ptr to ReadMemoryRoutine (may be NULL) &SymFunctionTableAccess64, // Ptr to function table access routine &SymGetModuleBase64, // Ptr to get module base routine NULL)) // Ptr to translate address routine for 16-bit addresses { // Check for infinite loop if (stackFrame.AddrPC.Offset EQ stackFrame.AddrReturn.Offset) break; // Check for valid instruction offset if (stackFrame.AddrPC.Offset EQ 0) break; //// // Initialize the CallstackEntry struc //// csEntry.offset = stackFrame.AddrPC.Offset; //// csEntry.name[0] = 0; //// csEntry.undName[0] = 0; //// csEntry.undFullName[0] = 0; //// csEntry.offsetFromSmybol = 0; //// csEntry.offsetFromLine = 0; //// csEntry.lineFileName[0] = 0; //// csEntry.lineNumber = 0; //// csEntry.loadedImageName[0] = 0; //// csEntry.moduleName[0] = 0; //// DbgBrk (); //// // Get the symbol name //// if (SymFromAddr (hProcess, stackFrame.AddrPC.Offset, &csEntry.offsetFromSmybol, lpSymInfo)) //// { //// DbgBrk (); //// //// //// //// } // End IF //// // Get the symbol name //// if (SymGetSymFromAddr64 (hProcess, stackFrame.AddrPC.Offset, &csEntry.offsetFromSmybol, pSym)) //// { //// DbgBrk (); //// //// // Copy to temporary storage //// strcpy (csEntry.name, pSym->Name); //// //// // Undecorate the symbol name //// UnDecorateSymbolName (pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY); //// UnDecorateSymbolName (pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE); //// } // End IF //// GetLastError (); caller = (LPBYTE) stackFrame.AddrPC.Offset; // Format the address FindRoutineAddress (caller, &nearAddress0, &nearIndex0, FALSE); FindRoutineAddress (caller, &nearAddress1, &nearIndex1, TRUE); if (nearAddress0 < nearAddress1) { nearAddress = nearAddress0; nearIndex = nearIndex0; } else { nearAddress = nearAddress1; nearIndex = nearIndex1; } // End IF/ELSE // If the address is out of bounds, just display the address if (nearAddress > 0x00100000) // Format the addresses MySprintfW (wszTemp, sizeof (wszTemp), L"%p -- EBP = %p", caller, stackFrame.AddrFrame.Offset); else // Format the addresses MySprintfW (wszTemp, sizeof (wszTemp), L"%p (%S + %p) -- EBP = %p", caller, StartAddresses[nearIndex].StartAddressName, nearAddress, stackFrame.AddrFrame.Offset); #define NewMsg(a) SendMessageW (hWndCC_LB, LB_ADDSTRING, 0, (LPARAM) (a)); UpdateWindow (hWndCC_LB) NewMsg (wszTemp); #undef NewMsg } // End WHILE ////CLEANUP: ////if (lpSymInfo) //// free (lpSymInfo); ////if (pSym) //// free (pSym); } // End DoStackWalk
void PrintCallStack(const CONTEXT *pContext) { HANDLE hProcess = GetCurrentProcess(); SymInitialize(hProcess, NULL, TRUE); CONTEXT c = *pContext; STACKFRAME64 sf; memset(&sf, 0, sizeof(STACKFRAME64)); DWORD dwImageType = IMAGE_FILE_MACHINE_I386; #ifdef _M_IX86 sf.AddrPC.Offset = c.Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = c.Esp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = c.Ebp; sf.AddrFrame.Mode = AddrModeFlat; #elif _M_X64 dwImageType = IMAGE_FILE_MACHINE_AMD64; sf.AddrPC.Offset = c.Rip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = c.Rsp; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrStack.Offset = c.Rsp; sf.AddrStack.Mode = AddrModeFlat; #elif _M_IA64 dwImageType = IMAGE_FILE_MACHINE_IA64; sf.AddrPC.Offset = c.StIIP; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = c.IntSp; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrBStore.Offset = c.RsBSP; sf.AddrBStore.Mode = AddrModeFlat; sf.AddrStack.Offset = c.IntSp; sf.AddrStack.Mode = AddrModeFlat; #else #error "Platform not supported!" #endif HANDLE hThread = GetCurrentThread(); while (true) { if (!StackWalk64(dwImageType, hProcess, hThread, &sf, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) break; DWORD64 address = sf.AddrPC.Offset; if (address == 0) break; // Get symbol name char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {0}; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; pSymbol->MaxNameLen = MAX_SYM_NAME ; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); SymFromAddr(hProcess, address, NULL, pSymbol); // Get module name IMAGEHLP_MODULE64 moduleInfo = {0}; moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); TCHAR* szModule = _T(""); // SymGetModuleInfo64 will fail in unicode version // http://msdn.microsoft.com/en-us/library/windows/desktop/ms681336(v=vs.85).aspx if (SymGetModuleInfo64(hProcess, address, &moduleInfo)) szModule = moduleInfo.ModuleName; // Get file name and line count IMAGEHLP_LINE64 lineInfo = {0}; lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); DWORD displacement; if (SymGetLineFromAddr64(hProcess, address, &displacement, &lineInfo)) { _tprintf(_T("%016llX %s!%s [%s @ %lu]\n"), pSymbol->Address, szModule, pSymbol->Name, lineInfo.FileName, lineInfo.LineNumber); } else { _tprintf(_T("%016llX %s!%s\n"), pSymbol->Address, szModule, pSymbol->Name); } } SymCleanup(hProcess); }
void StackDump( LPVOID pMem, DWORD dwBytes) { STACKFRAME64 stStackFrame = {0}; CONTEXT stContext = {0}; stContext.ContextFlags = CONTEXT_ALL; __asm call x __asm x: pop eax __asm mov stContext.Eip, eax __asm mov stContext.Ebp, ebp __asm mov stContext.Esp, esp stStackFrame.AddrPC.Offset = stContext.Eip; stStackFrame.AddrPC.Mode = AddrModeFlat; stStackFrame.AddrFrame.Offset = stContext.Ebp; stStackFrame.AddrFrame.Mode = AddrModeFlat; stStackFrame.AddrStack.Offset = stContext.Esp; stStackFrame.AddrStack.Mode = AddrModeFlat; // BYTE SymBol[ sizeof(SYMBOL_INFO) + STACKWALK_MAX_NAMELEN ] = {0}; // // SYMBOL_INFO* pSymbol = (SYMBOL_INFO*)SymBol; // pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); // pSymbol->MaxNameLen = STACKWALK_MAX_NAMELEN; // // IMAGEHLP_LINE64 Line = {0}; // Line.SizeOfStruct = sizeof( IMAGEHLP_LINE64 ); HANDLE hProcess = GetCurrentProcess(); MEM_INFO stInfo; //stInfo.parCallStack = new STACK_ARRAY; //void * p = AllocMem(sizeof(STACK_ARRAY)); //stInfo.parCallStack = new( (void*)p ) STACK_ARRAY; stInfo.nMemSize = dwBytes; for( int i =0; i < g_Config::g_StackDepth ; i++ )// only retrieve 40 functions { BOOL b = StackWalk64( IMAGE_FILE_MACHINE_I386, hProcess, GetCurrentThread(), &stStackFrame ,&stContext, 0, SymFunctionTableAccess64 , SymGetModuleBase64, NULL ); if ( !b ) { break; } DWORD64 dwDisplacement = 0; if (stStackFrame.AddrPC.Offset == stStackFrame.AddrReturn.Offset) { break; } ////////////////////////////////////////////////////////////////////////// //if( SymFromAddr( hProcess, stStackFrame.AddrPC.Offset, &dwDisplacement, pSymbol )) //{ // CString cs = "Ordinal823"; // if( cs == pSymbol->Name) // { // break; // } // //} ////////////////////////////////////////////////////////////////////////// if( i <= 1 )// ignore the functions on the top of stack which is our own. { continue; } stInfo.parCallStack.push_back( stStackFrame.AddrPC.Offset ); } g_Config::m_MemMap[pMem] = stInfo; }
void kul_real_se_handler(EXCEPTION_POINTERS* pExceptionInfo){ const std::string& tid(kul::this_thread::id()); uint sig = pExceptionInfo->ExceptionRecord->ExceptionCode; if(pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) for(auto& f : kul::SignalStatic::INSTANCE().se) f(sig = 11); if(!kul::SignalStatic::INSTANCE().q){ HANDLE process = GetCurrentProcess(); SymInitialize(process, NULL, TRUE); CONTEXT context_record = *pExceptionInfo->ContextRecord; STACKFRAME64 stack_frame; memset(&stack_frame, 0, sizeof(stack_frame)); #if defined(_WIN64) int 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 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; SYMBOL_INFO* symbol; symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 ); symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); std::cout << "[bt] Stacktrace:" << std::endl; while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), &stack_frame, &context_record, NULL, &SymFunctionTableAccess64, &SymGetModuleBase64, NULL)) { DWORD64 displacement = 0; if (SymFromAddr(process, (DWORD64)stack_frame.AddrPC.Offset, &displacement, symbol)){ DWORD dwDisplacement; IMAGEHLP_LINE64 line; IMAGEHLP_MODULE64 moduleInfo; ZeroMemory(&moduleInfo, sizeof(IMAGEHLP_MODULE64)); moduleInfo.SizeOfStruct = sizeof(moduleInfo); std::cout << "[bt] "; if (::SymGetModuleInfo64(process, symbol->ModBase, &moduleInfo)) std::cout << moduleInfo.ModuleName << " "; std::cout << symbol->Name << " + [0x" << std::hex << displacement << "]"; if (SymGetLineFromAddr64(process, (DWORD64)stack_frame.AddrPC.Offset, &dwDisplacement, &line)) std::cout << " - " << line.FileName << ": " << std::to_string(line.LineNumber); else std::cout << " - ??:"; std::cout << std::endl; } } } exit(sig); }
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); }
LONG WINAPI PtokaX_UnhandledExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) { static volatile LONG PermLock = 0; // When unhandled exception happen then permanently 'lock' here. We terminate after first exception. while(InterlockedExchange(&PermLock, 1) == 1) { ::Sleep(10); } // Set failure hook __pfnDliFailureHook2 = PtokaX_FailHook; // Check if we have debug symbols if(FileExist(sDebugSymbolsFile.c_str()) == false) { #ifdef _BUILD_GUI ::MessageBox(NULL, "Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because file with debug symbols" " (PtokaX.pdb) is missing. If you know why this crash happen then please report it as bug to [email protected]!", "PtokaX crashed!", MB_OK | MB_ICONERROR); #else AppendLog("Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because file with debug symbols" " (PtokaX.pdb) is missing. If you know why this crash happen then please report it as bug to [email protected]!"); #endif ExceptionHandlingUnitialize(); exit(EXIT_FAILURE); } // Initialize debug symbols SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES); if(SymInitialize(GetCurrentProcess(), PATH.c_str(), TRUE) == FALSE) { #ifdef _BUILD_GUI ::MessageBox(NULL, "Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because initializatin of" " debug symbols failed. If you know why this crash happen then please report it as bug to [email protected]!", "PtokaX crashed!", MB_OK | MB_ICONERROR); #else AppendLog("Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because initializatin of" " debug symbols failed. If you know why this crash happen then please report it as bug to [email protected]!"); #endif ExceptionHandlingUnitialize(); exit(EXIT_FAILURE); } // Generate crash log filename time_t acc_time; time(&acc_time); struct tm *tm = localtime(&acc_time); strftime(sDebugBuf, 128, "Crash-%d.%m.%Y-%H.%M.%S.log", tm); // Open crash file FILE * fw = fopen((sLogPath + sDebugBuf).c_str(), "w"); if(fw == NULL) { #ifdef _BUILD_GUI ::MessageBox(NULL, "Something bad happen and PtokaX crashed. PtokaX was not able to create file with information why this crash happen." " If you know why this crash happen then please report it as bug to [email protected]!", "PtokaX crashed!", MB_OK | MB_ICONERROR); #else AppendLog("Something bad happen and PtokaX crashed. PtokaX was not able to create file with information why this crash happen." " If you know why this crash happen then please report it as bug to [email protected]!"); #endif ExceptionHandlingUnitialize(); SymCleanup(GetCurrentProcess()); exit(EXIT_FAILURE); } string sCrashMsg = "Something bad happen and PtokaX crashed. PtokaX collected information why this crash happen to file "; sCrashMsg += string(sDebugBuf); sCrashMsg += ", please send that file to [email protected]!"; // Write PtokaX version, build and exception code fprintf(fw, "PtokaX version: " PtokaXVersionString " [build " BUILD_NUMBER "]" #ifdef _M_X64 " (x64)" #endif "\nException Code: %x\n", ExceptionInfo->ExceptionRecord->ExceptionCode); { // Write windoze version where we crashed if is possible OSVERSIONINFOEX ver; memset(&ver, 0, sizeof(OSVERSIONINFOEX)); ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if(GetVersionEx((OSVERSIONINFO*)&ver) != 0) { fprintf(fw, "Windows version: %d.%d SP: %d\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.wServicePackMajor); } } // Write date and time when crash happen strftime(sDebugBuf, 128, "Date and time: %d.%m.%Y %H:%M:%S\n\n", tm); fprintf(fw, sDebugBuf); STACKFRAME64 sf64CallStack; memset(&sf64CallStack, 0, sizeof(STACKFRAME64)); sf64CallStack.AddrPC.Mode = AddrModeFlat; sf64CallStack.AddrStack.Mode = AddrModeFlat; sf64CallStack.AddrFrame.Mode = AddrModeFlat; #ifdef _M_X64 sf64CallStack.AddrPC.Offset = ExceptionInfo->ContextRecord->Rip; sf64CallStack.AddrStack.Offset = ExceptionInfo->ContextRecord->Rsp; sf64CallStack.AddrFrame.Offset = ExceptionInfo->ContextRecord->Rbp; #else sf64CallStack.AddrPC.Offset = ExceptionInfo->ContextRecord->Eip; sf64CallStack.AddrStack.Offset = ExceptionInfo->ContextRecord->Esp; sf64CallStack.AddrFrame.Offset = ExceptionInfo->ContextRecord->Ebp; #endif // Write where crash happen fprintf(fw, "Exception location:\n"); GetSourceFileInfo(sf64CallStack.AddrPC.Offset, fw); GetFunctionInfo(sf64CallStack.AddrPC.Offset, fw); // Try to write callstack fprintf(fw, "\nCall stack:\n"); // We don't want it like never ending story, limit call stack to 100 lines for(uint32_t ui32i = 0; ui32i < 100; ui32i++) { if(StackWalk64( #ifdef _M_X64 IMAGE_FILE_MACHINE_AMD64, #else IMAGE_FILE_MACHINE_I386, #endif GetCurrentProcess(), GetCurrentThread(), &sf64CallStack, ExceptionInfo->ContextRecord, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL) == FALSE || sf64CallStack.AddrFrame.Offset == 0) { break; } GetSourceFileInfo(sf64CallStack.AddrPC.Offset, fw); GetFunctionInfo(sf64CallStack.AddrPC.Offset, fw); } fclose(fw); #ifdef _BUILD_GUI ::MessageBox(NULL, sCrashMsg.c_str(), "PtokaX crashed!", MB_OK | MB_ICONERROR); #else AppendLog(sCrashMsg.c_str()); #endif ExceptionHandlingUnitialize(); SymCleanup(GetCurrentProcess()); exit(EXIT_FAILURE); }
void stackgetcallstack(duint csp, std::vector<CALLSTACKENTRY> & callstackVector, bool cache) { if(cache) { SHARED_ACQUIRE(LockCallstackCache); auto found = CallstackCache.find(csp); if(found != CallstackCache.end()) { callstackVector = found->second; return; } callstackVector.clear(); return; } // Gather context data CONTEXT context; memset(&context, 0, sizeof(CONTEXT)); context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; if(SuspendThread(hActiveThread) == -1) return; if(!GetThreadContext(hActiveThread, &context)) return; if(ResumeThread(hActiveThread) == -1) return; // Set up all frame data STACKFRAME64 frame; ZeroMemory(&frame, sizeof(STACKFRAME64)); #ifdef _M_IX86 DWORD machineType = IMAGE_FILE_MACHINE_I386; frame.AddrPC.Offset = context.Eip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Ebp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = csp; frame.AddrStack.Mode = AddrModeFlat; #elif _M_X64 DWORD machineType = IMAGE_FILE_MACHINE_AMD64; frame.AddrPC.Offset = context.Rip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Rsp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = csp; frame.AddrStack.Mode = AddrModeFlat; #endif const int MaxWalks = 50; // Container for each callstack entry (50 pre-allocated entries) callstackVector.clear(); callstackVector.reserve(MaxWalks); for(auto i = 0; i < MaxWalks; i++) { if(!StackWalk64( machineType, fdProcessInfo->hProcess, hActiveThread, &frame, &context, StackReadProcessMemoryProc64, SymFunctionTableAccess64, StackGetModuleBaseProc64, StackTranslateAddressProc64)) { // Maybe it failed, maybe we have finished walking the stack break; } if(frame.AddrPC.Offset != 0) { // Valid frame CALLSTACKENTRY entry; memset(&entry, 0, sizeof(CALLSTACKENTRY)); StackEntryFromFrame(&entry, (duint)frame.AddrFrame.Offset + sizeof(duint), (duint)frame.AddrPC.Offset, (duint)frame.AddrReturn.Offset); callstackVector.push_back(entry); } else { // Base reached break; } } EXCLUSIVE_ACQUIRE(LockCallstackCache); if(CallstackCache.size() > MAX_CALLSTACK_CACHE) CallstackCache.clear(); CallstackCache[csp] = callstackVector; }