Windows/C++:如何从信号处理程序中获取有用的堆栈跟踪
windows/c++: how can I get a useful stack trace from a signal handler?
我有一个Windows/C++应用程序(使用JUCE),我想在应用程序崩溃时将堆栈跟踪转储到文件中。在我的初始化代码中,我得到了:
signal(SIGABRT, abortHandler);
signal(SIGSEGV, abortHandler);
signal(SIGILL, abortHandler);
signal(SIGFPE, abortHandler);
然后我的处理程序看起来像:
void abortHandler(int signum)
{
juce::File log("stacktrace.txt");
log.appendText(juce::SystemStats::getStackBacktrace());
exit(signum);
}
但是,生成的堆栈跟踪不是发生崩溃的线程:
0: AudulusDebug32: juce::SystemStats::getStackBacktrace + 0x7f
1: AudulusDebug32: abortHandler + 0x61
2: AudulusDebug32: _XcptFilter + 0x1e3
3: AudulusDebug32: __tmainCRTStartup + 0x15f
4: AudulusDebug32: WinMainCRTStartup + 0xd
5: BaseThreadInitThunk + 0xe
6: RtlInitializeExceptionChain + 0x84
7: RtlInitializeExceptionChain + 0x5a
在内部,getStackBacktrace
执行以下操作:
HANDLE process = GetCurrentProcess();
SymInitialize (process, nullptr, TRUE);
void* stack[128];
int frames = (int) CaptureStackBackTrace (0, numElementsInArray (stack), stack, nullptr);
有没有办法获取发生崩溃的线程(或所有线程)的堆栈跟踪?
正如@HansPassant所建议的那样,我的解决方案是使用:
SetUnhandledExceptionFilter(TopLevelExceptionHandler);
在TopLevelExceptionHandler
中,我使用 StackWalk64
而不是调用 CaptureStackBackTrace
,它允许您指定要遍历的堆栈(而不是仅仅假设当前堆栈)。
这是代码:
LONG WINAPI TopLevelExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
{
std::ofstream f;
f.open("stacktrace.txt", std::ios::out | std::ios::trunc);
HANDLE process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
// StackWalk64() may modify context record passed to it, so we will
// use a copy.
CONTEXT context_record = *pExceptionInfo->ContextRecord;
// Initialize stack walking.
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;
juce::HeapBlock<SYMBOL_INFO> symbol;
symbol.calloc(sizeof(SYMBOL_INFO) + 256, 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
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))
{
IMAGEHLP_MODULE64 moduleInfo;
juce::zerostruct(moduleInfo);
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
if (::SymGetModuleInfo64(process, symbol->ModBase, &moduleInfo))
f << moduleInfo.ModuleName << ": ";
f << symbol->Name << " + 0x" << String::toHexString((juce::int64)displacement) << std::endl;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
相关文章:
- C++为构建时间获取QDateTime的可靠方法
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 使用指针从C++中的数组中获取最大值
- 如何获取std::result_of函数的返回类型
- 如何在openssl-ecc中获取十六进制格式的私钥
- 使用Unreal C++获取VR耳机的世界位置/方向
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 从C字符串中获取奇怪的字符串长度
- 为什么我的for循环不能正确获取argv
- 从python中调用C++函数并获取返回值
- 如何获取一个数字的前3位
- 获取字符串的长度并将其分配给数组
- 无法获取菜单选择以运行函数.C++
- 数组长度,为什么从命令行获取时不能使用它?
- Boost Spirit,获取迭代器内部语义动作
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- 具有默认值的引用获取函数
- Windows/C++:如何从信号处理程序中获取有用的堆栈跟踪
- 为仅标头库获取有用的 GCov 结果