如何在顶级过滤器中获取 Win32 崩溃的字符串描述(我正在寻找堆栈顶部指令的地址)

发布于 2024-08-23 05:24:32 字数 460 浏览 12 评论 0原文

如果我使用类似 此处描述的类/方法 如何获取堆栈顶部调用的描述/地址?

基本上我想要一些可以在调用我们的错误跟踪系统时使用的值。我想根据引起异常的指令的地址来“唯一”识别。

(它通常采用 mydll.dll!1234ABDC() 的形式)

编辑:

一些背景信息:

我正在创建一个小型转储以通过电子邮件发送到缺陷跟踪系统(fogbugz)。为了减少重复,我试图为崩溃提出一个合理的“签名”。我知道 FB 有一个 xml PI,但它需要用户登录,而且我们还不确定是否可以让人们嗅探我们的流量并获取用户信息。目前,电子邮件的实施也更简单。稍后我们将使用 XML API 提交小型转储。

If I use a class/method like the one described here how can I get the description/address of the call at the top of the stack?

Basically I want some value I can use in a call to our bug tracking system. I want to "uniquely" identify based on the address of the instruction that caused the exception.

(It is usually something of the form of mydll.dll!1234ABDC())

EDIT:

Some background information:

I am creating a minidump to email to a defect tracking system (fogbugz). In order to reduce duplicates I am trying to come up with a reasonable "signature" for the crash. I know there is an xml PI for FB, but it requires a user logon and we are not sure yet that we can afford to have people sniffing our traffic and getting user information. Emailing is also simpler for now to implement. Later on we will use the XML API to submit minidumps.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不必了 2024-08-30 05:24:32

您需要将执行此操作的代码放入异常过滤器中,当您到达异常处理程序时,异常的大部分上下文信息已经丢失。

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 位数量。

You need to put the code to do this in your exception filter, by the time you get to the exception handler much of the context information for the exception has been lost.

try 
{
  // whatever
}
except (MyExceptionFilter(GetExceptionInformation()))
{
}

Your filter will look something like this

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;
}

Of course, you will need to adjust your output a bit for 64 bit architectures, since the ExceptionAddress and AllocationBase will be 64 bit quantities in that case.

对岸观火 2024-08-30 05:24:32

发送到 TopLevelFilter()EXCEPTION_POINTERS 结构包含一个 EXCEPTION_RECORD 结构,其中包含 ExceptionAddress。您可以通过使用 CreateToolhelp32Snapshot。您还可以使用dbghelp.dll中的函数来查找与该地址对应的符号(它所在的函数)

The EXCEPTION_POINTERS struct which is sent to TopLevelFilter() contains an EXCEPTION_RECORD struct which contains the ExceptionAddress. Which this address you can figure out in which DLL the offending opcode is by enumerating the modules with CreateToolhelp32Snapshot. You can also use the functions in dbghelp.dll to find the symbol which correspond to the address (the function it is in)

余罪 2024-08-30 05:24:32

GetExceptionInformation 将返回 EXCEPTION_POINTERS 结构,其中包含有关异常的信息。 ExceptionRecord 成员包含一个 ExceptionAddress 成员,它是异常的地址。

您需要将此地址映射到代码中的模块相对位置才能发挥作用。您可以将 GetModuleHandleEx 与 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 一起使用来获取 HMODULE(这也是模块的基地址)。然后可以使用 GetModuleInformation 来获取发生异常的模块的实际名称。

如果错误实际上位于系统 DLL 内部,这可能对您没有多大帮助。更复杂的方案是生成堆栈跟踪(使用 dbghelp 中的 Stackwalk64),并忽略代码中不存在的最顶层帧。

GetExceptionInformation will return the EXCEPTION_POINTERS struct which contains information about the exception. The ExceptionRecord member contains an ExceptionAddress member, which is the address of the exception.

You'll need to map this address to a module relative location in your code to be useful. You can use GetModuleHandleEx with the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS to get the HMODULE (which is also the base address of the module). GetModuleInformation can then be used to get the actual name of the module that the exception occurred in.

This may not be that helpful to you if the fault is actually inside of a system DLL. A more sophisticated scheme would be to generate a stack trace (using Stackwalk64 in dbghelp), and ignoring the topmost frames that are not in your code.

岁月静好 2024-08-30 05:24:32

您可以通过保存小型转储并使用 cdb.exe 或 Windbg.exe 提取异常来避免打印异常字符串的痛苦(如果您可以保存小型转储但无法在不崩溃的情况下格式化字符串会发生什么?)信息。

You can avoid the pain of printing a string for the exception (what happens if you can save the minidump but can't format a string without crashing?) by saving the minidump instead and using cdb.exe or windbg.exe to extract the exception information.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文