如果我使用像one described here这样的类/方法,如何在堆栈顶部获取调用的描述/地址?
基本上我想要一些我可以在调用我们的bug跟踪系统时使用的值。我希望根据导致异常的指令的地址“唯一地”识别。
(通常是mydll.dll形式的东西!1234ABDC())
编辑:
一些背景资料:
我正在创建一个minidump,通过电子邮件发送到缺陷跟踪系统(fogbugz)。为了减少重复,我试图为崩溃提出一个合理的“签名”。我知道FB有一个xml PI,但它需要用户登录,我们还不确定我们是否有能力让人们嗅探我们的流量并获取用户信息。电子邮件现在也很容易实现。稍后我们将使用XML API提交minidump。
答案 0 :(得分:4)
您需要在异常过滤器中放置代码来执行此操作,当您到达异常处理程序时,异常的大部分上下文信息都已丢失。
try
{
// whatever
}
except (MyExceptionFilter(GetExceptionInformation()))
{
}
您的过滤器看起来像这样
LONG WINAPI MyExceptionFilter (
EXCEPTION_POINTERS * pExcept,
BOOL fPassOn)
{
EXCEPTION_RECORD * pER = pExcept->ExceptionRecord;
DWORD dwExceptionCode = pER->ExceptionCode;
TCHAR szOut[MAX_PATH*4]; // exception output goes here.
szOut[0] = 0;
MEMORY_BASIC_INFORMATION mbi;
DWORD cb = VirtualQuery (pER->ExceptionAddress, &mbi, sizeof(mbi));
if (cb == sizeof(mbi))
{
TCHAR szModule[MAX_PATH];
if (GetModuleFileName ((HMODULE)mbi.AllocationBase, szModule, MAX_PATH))
{
wsprintf(szOut, "Exception at '%s' + 0x%X", szModule,
(ULONG_PTR)pER->ExceptionAddress - (ULONG_PTR)mbi.AllocationBase);
}
}
return EXCEPTION_EXECUTE_HANDLER;
}
当然,您需要为64位体系结构调整一点输出,因为在这种情况下ExceptionAddress和AllocationBase将是64位数量。
答案 1 :(得分:1)
发送到EXCEPTION_POINTERS
的{{1}}结构包含TopLevelFilter()
结构,其中包含EXCEPTION_RECORD
。通过使用CreateToolhelp32Snapshot枚举模块,您可以在哪个地址中找出违反操作码的DLL。您还可以使用ExceptionAddress
中的函数来查找与地址对应的符号(它所在的函数)
答案 2 :(得分:1)
GetExceptionInformation将返回EXCEPTION_POINTERS结构,其中包含有关异常的信息。 ExceptionRecord成员包含一个ExceptionAddress成员,它是异常的地址。
您需要将此地址映射到代码中的模块相对位置才有用。您可以将GetModuleHandleEx与GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS一起使用以获取HMODULE(它也是模块的基址)。然后可以使用GetModuleInformation来获取发生异常的模块的实际名称。
如果故障实际上在系统DLL中,这可能对您没有帮助。更复杂的方案是生成堆栈跟踪(在dbghelp中使用Stackwalk64),并忽略代码中不存在的最顶层帧。
答案 3 :(得分:0)
您可以通过保存minidump并使用cdb.exe或windbg.exe来避免为异常打印字符串的痛苦(如果您可以保存minidump但无法格式化字符串而不会崩溃会发生什么?)提取异常信息。