代码之家  ›  专栏  ›  技术社区  ›  Tim

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

  •  6
  • Tim  · 技术社区  · 16 年前

    如果我使用像 one described here 如何在堆栈顶部获取调用的描述/地址?

    基本上,我想要一些价值,我可以在调用我们的错误跟踪系统时使用。我想根据导致异常的指令的地址进行“唯一”标识。

    (通常是mydll.dll!1234ABDC()的形式)

    编辑:

    一些背景信息:

    我正在创建一个小型转储,通过电子邮件发送到缺陷跟踪系统(fogbugz)。为了减少重复,我正试图为这次坠机找到一个合理的“特征”。我知道FB有一个xml PI,但它需要用户登录,我们还不确定我们是否有能力让人们嗅探我们的流量并获取用户信息。目前,电子邮件的实施也更简单。稍后,我们将使用XMLAPI提交迷你转储。

    4 回复  |  直到 16 年前
        1
  •  4
  •   John Knoeller    16 年前

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

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

        2
  •  1
  •   Tim    16 年前

    这个 EXCEPTION_POINTERS 结构,它被发送到 TopLevelFilter() 包含一个 EXCEPTION_RECORD 包含 ExceptionAddress 。通过枚举带有的模块,您可以找出哪个DLL中有问题的操作码 CreateToolhelp32Snapshot 。您也可以使用中的功能 dbghelp.dll 找到地址对应的符号(它所在的函数)

        3
  •  1
  •   Tim    15 年前

    GetExceptionInformation将返回包含异常信息的EXCEPTION_POINTERS结构。ExceptionRecord成员包含ExceptionAddress成员,该成员是异常的地址。

    您需要将这个地址映射到代码中的模块相对位置,这样才有用。您可以使用GetModuleHandlex和GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS来获取HMODULE(这也是模块的基址)。然后可以使用GetModuleInformation获取发生异常的模块的实际名称。

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

        4
  •  0
  •   MSN    16 年前

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