如何从SEH异常生成堆栈跟踪
How to generate stack trace from SEH exception
我正在使用Win32 SEH:捕获异常
try
{
// illegal operation that causes access violation
}
__except( seh_filter_func(GetExceptionInformation()) )
{
// abort
}
过滤函数如下所示:
int seh_filter_func(EXCEPTION_POINTERS *xp)
{
// log EIP, other registers etc. to file
return 1;
}
到目前为止,这是有效的,xp->ContextRecord->Eip
中的值告诉我是哪个函数导致了访问违规(实际上是-ntdll.dll!RtlEnterCriticalSection,EDX的值告诉我这个函数是用伪参数调用的)。
然而,这个函数在很多地方都被调用,包括从其他WinAPI函数调用,所以我仍然不知道是哪个代码负责用伪参数调用这个函数。
根据EXCEPTION_POINTERS
中的信息或其他信息,我是否可以使用任何代码来生成通往EIP现在所在位置的函数调用链的跟踪?(在外部调试器下运行程序不是一个选项)。
只要EIP值就可以了,因为我可以在链接器映射和符号表中查找它们,尽管如果有一种方法可以自动将它们映射到符号名称,那就更好了。
我在这个项目中使用C++Builder 2006,尽管MSVC++解决方案可能无论如何都能工作。
我认为你可以使用Boost.Stacktrace:
#include <boost/stacktrace.hpp>
int seh_filter_func(EXCEPTION_POINTERS *xp)
{
const auto stack = to_string( boost::stacktrace::stacktrace() );
LOG( "%s", stack.c_str() );
return 1;
}
在64位模式下,SEH过滤器函数似乎在同一堆栈上执行,而不展开它,因此您确实可以查看boost::stacktrace::stacktrace()
的后缀来查看错误发生的位置,如另一个答案所示。
但是,它在32位模式下对我不起作用。我必须使用DbgHelp.h
/DbgHelp.lib
中的StackWalk64
函数遍历堆栈。尽管它需要STACKFRAME64
来启动,但可以用从xp->ContextRecord
的CONTEXT
结构中获得的相应寄存器来填充它。
以下代码适用于我的32位模式:
#include <boost/stacktrace.hpp> // For symbols only
#include <DbgHelp.h>
#pragma comment(lib, "DbgHelp.lib")
int seh_filter_func(EXCEPTION_POINTERS* xp) {
CONTEXT context = *xp->ContextRecord;
STACKFRAME64 s;
ZeroMemory(&s, sizeof(s));
s.AddrPC.Offset = context.Eip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrFrame.Offset = context.Ebp;
s.AddrFrame.Mode = AddrModeFlat;
s.AddrStack.Offset = context.Esp;
s.AddrStack.Mode = AddrModeFlat;
// Not thread-safe!
for (int i = 0;
StackWalk64(
IMAGE_FILE_MACHINE_I386,
GetCurrentProcess(),
GetCurrentThread(),
&s,
&context,
NULL,
NULL,
NULL,
NULL);
i++) {
std::cout << i << ": " << boost::stacktrace::frame((void*)s.AddrPC.Offset) << "n";
}
return 1;
}
出于某种原因,即使我用相应的64位寄存器替换32位寄存器,这在64位模式下也不起作用。它正确地打印第一帧,然后打印一些不清楚的内容。
- 用于解析 win64 堆栈跟踪的命令行客户端(可以访问符号服务器)
- 提升堆栈跟踪不显示函数名称和行号
- cygwin_exception::open_stackdumpfile:将堆栈跟踪转储到 class4.exe.sta
- 如何按指针查看堆栈跟踪
- WinDbg 不显示某些小型转储文件的完整堆栈跟踪
- 发布代码的 gdb 堆栈跟踪可读性如何影响 x64?
- 提升::堆栈跟踪::safe_dump_to输出大小
- Qt 5.9中的QML崩溃-帮助读取堆栈跟踪
- 如何获取崩溃的DLL的堆栈跟踪?
- 当外部源代码中发生异常时,无法正确使用自创建的小型转储文件的堆栈跟踪
- 在 Linux 平台上以 C/C++ 打印进程的所有线程堆栈跟踪
- Boost 堆栈跟踪异步信号安全吗?
- 使用 gdb 时无法获取堆栈跟踪
- VC++ 堆栈跟踪不会解析生产环境中的函数名称
- 从堆栈跟踪中查找共享库中的源代码行
- 捕获异常后的堆栈跟踪
- 是否有一种便携式/标准的方法可以在堆栈跟踪中获取文件名和亚麻布
- 为什么谷歌测试不打印堆栈跟踪或文件名
- 在明夫中打印堆栈跟踪
- GDB 显示奇怪的堆栈跟踪