Как получить строковое описание сбоя Win32 в то время как в фильтре верхнего уровня (я ищу адрес инструкции в верхней части стека) - PullRequest
6 голосов
/ 02 марта 2010

Если я использую класс / метод, такой как , описанный здесь , как я могу получить описание / адрес вызова в верхней части стека?

По сути, я хочу получить какое-то значение, которое можно использовать при вызове нашей системы отслеживания ошибок. Я хочу «однозначно» идентифицировать на основе адреса инструкции, вызвавшей исключение.

(Обычно это что-то вроде mydll.dll! 1234ABDC ())

EDIT:

Некоторая справочная информация:

Я создаю мини-дамп для отправки электронной почты в систему отслеживания дефектов (fogbugz). Чтобы уменьшить количество дубликатов, я пытаюсь придумать разумную «подпись» для аварии. Я знаю, что есть xml PI для FB, но для этого требуется вход пользователя, и мы пока не уверены, что можем позволить себе прослушивать наш трафик и получать информацию о пользователях. Электронная почта также проще для реализации. Позже мы будем использовать XML API для отправки мини-дампов.

Ответы [ 4 ]

4 голосов
/ 02 марта 2010

Вам нужно поместить код для этого в ваш фильтр исключений, к тому времени, когда вы получите обработчик исключений, большая часть контекстной информации об исключении будет потеряна.

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 голос
/ 02 марта 2010

GetExceptionInformation вернет структуру EXCEPTION_POINTERS, которая содержит информацию об исключении. Элемент ExceptionRecord содержит элемент ExceptionAddress, который является адресом исключения.

Вам нужно будет сопоставить этот адрес с относительным расположением модуля в вашем коде, чтобы быть полезным. Вы можете использовать GetModuleHandleEx с GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, чтобы получить HMODULE (который также является базовым адресом модуля). Затем GetModuleInformation можно использовать для получения фактического имени модуля, в котором произошло исключение.

Это может быть не очень полезно для вас, если ошибка на самом деле находится внутри системной DLL. Более сложной схемой будет генерирование трассировки стека (используя Stackwalk64 в dbghelp) и игнорирование самых верхних фреймов, которых нет в вашем коде.

1 голос
/ 02 марта 2010

Структура EXCEPTION_POINTERS, отправляемая на TopLevelFilter(), содержит структуру EXCEPTION_RECORD, которая содержит ExceptionAddress. По какому адресу вы можете выяснить, в какой DLL код операции нарушен, перечислив модули с CreateToolhelp32Snapshot . Вы также можете использовать функции в dbghelp.dll, чтобы найти символ, соответствующий адресу (функция, в которой он находится)

0 голосов
/ 02 марта 2010

Вы можете избежать трудностей печати строки для исключения (что произойдет, если вы можете сохранить мини-дамп, но не можете отформатировать строку без сбоя?), Сохранив мини-дамп вместо этого и используя cdb.exe или windbg.exe для извлечь информацию об исключении.

...