Если я использую класс/метод как тот, описал здесь, как я могу получить описание/адрес вызова наверху стека?
В основном я хочу некоторое значение, которое я могу использовать в вызове для нашей системы отслеживания ошибок. Я хочу "исключительно" определить на основе адреса инструкции, которая вызвала исключение.
(Это обычно - что-то вроде формы mydll.dll! 1234ABDC ())
Править:
Некоторая справочная информация:
Я создаю мини-дамп на адрес электронной почты к дефектной системе слежения (fogbugz). Для сокращения дубликатов, я пытаюсь придумать разумную "подпись" для катастрофического отказа. Я знаю, что существует xml PI для FB, но он требует пользовательского входа в систему, и мы еще не уверены, что можем позволить себе иметь людей, осуществляющих сниффинг нашего трафика и получающих пользовательскую информацию. Пользование электронной почтой также более просто на данный момент реализовать. Позже мы будем использовать API XML для представления мини-дампов.
Вам нужно поместить код для этого в свой фильтр исключений, к тому времени, когда вы доберетесь до обработчика исключения, большая часть контекстной информации для исключения будет был потерян.
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-битными величинами.
GetExceptionInformation вернет структуру EXCEPTION_POINTERS, которая содержит информацию об исключении. Член ExceptionRecord содержит член ExceptionAddress, который является адресом исключения.
Вам нужно будет сопоставить этот адрес с относительным расположением модуля в вашем коде, чтобы он был полезен. Вы можете использовать GetModuleHandleEx с GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, чтобы получить HMODULE (который также является базовым адресом модуля). Затем GetModuleInformation может использоваться для получения фактического имени модуля, в котором возникла исключительная ситуация.
Это может быть не очень полезно для вас, если ошибка действительно находится внутри системной DLL. Более сложной схемой было бы создание трассировки стека (с использованием Stackwalk64 в dbghelp) и игнорирование самых верхних кадров, которых нет в вашем коде.
Вы можете избежать мучений с печатью строки для исключения (что произойдет, если вы можете сохранить минидамп, но не можете отформатировать строку без сбоя?), сохранив вместо этого минидамп и используя cdb.exe или windbg.exe для извлечения информации об исключении.
Структура EXCEPTION_POINTERS
, которая отправляется на TopLevelFilter ()
, содержит структуру EXCEPTION_RECORD
, которая содержит ExceptionAddress
. По какому именно этому адресу вы можете выяснить, в какой библиотеке DLL нарушает код операции, перечислив модули с помощью CreateToolhelp32Snapshot . Вы также можете использовать функции из dbghelp.dll
, чтобы найти символ, соответствующий адресу (функции, в которой он находится)