Создание исключения minidump для исключения доступа с использованием SetUnhandledExceptionFilter()
Я использую следующий код для создания файла minidump всякий раз, когда есть структурированное исключение, сгенерированное из моего кода:
void CreateMiniDump( EXCEPTION_POINTERS* pep )
{
// Open the file
typedef BOOL (*PDUMPFN)(
HANDLE hProcess,
DWORD ProcessId,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
HANDLE hFile = CreateFile( _T("C:/temp/MiniDump.dmp"), GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
HMODULE h = ::LoadLibrary(L"DbgHelp.dll");
PDUMPFN pFn = (PDUMPFN)GetProcAddress(h, "MiniDumpWriteDump");
if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) )
{
// Create the minidump
MINIDUMP_EXCEPTION_INFORMATION mdei;
mdei.ThreadId = GetCurrentThreadId();
mdei.ExceptionPointers = pep;
mdei.ClientPointers = TRUE;
MINIDUMP_TYPE mdt = MiniDumpNormal;
BOOL rv = (*pFn)( GetCurrentProcess(), GetCurrentProcessId(),
hFile, mdt, (pep != 0) ? &mdei : 0, 0, 0 );
// Close the file
CloseHandle( hFile );
}
}
LONG WINAPI MyUnhandledExceptionFilter(
struct _EXCEPTION_POINTERS *ExceptionInfo
)
{
CreateMiniDump(ExceptionInfo);
return EXCEPTION_EXECUTE_HANDLER;
}
И я делаю SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
из главной точки входа в приложение (я не настраиваю его для каждого потока, хотя). После этого, чтобы протестировать этот код, я сделал следующее для генерации нарушения доступа: int* p = 0; *p = 0;
Файл дампа был сгенерирован. Затем я использовал windbg и открыл файл дампа и использовал команду .ecxr
, чтобы получить запись об исключении. Однако никакой информации не поступает (т.е. Я не получаю стек вызовов). Также, если я использую команду !analyze -v
, тогда она может показать строку, где произошел сбой. Кто-нибудь знает, что мне не хватает, и как это решить?
Кстати, я использую VC7-компилятор с флагом /EHa (asynchronuos exception model).
Ответы
Ответ 1
Ваш код, создающий мини-накопитель, в порядке, проблема заключается в посмертной отладке. Отладчик должен иметь доступ к исходному коду программы, файлам .pdb(которые должны быть файлами pdb, создаваемыми при выполнении этого исполняемого файла программы) и символам отладки ОС. Имея всю эту информацию, отладчик может показывать место исключения в исходном коде и стеке вызовов.
Процесс отладки после вскрытия с использованием отладчика Visual Studio подробно описан здесь: http://www.codeproject.com/KB/debug/postmortemdebug_standalone1.aspx Для WinDbg используйте файл Symbol, Source и Image путь для предоставления той же информации для отладчика.
Ответ 2
Однако никакой информации не поступает (т.е. я не получаю стек вызовов)
.ecxr
не должен печатать столбец, он просто должен установить контекст в контексте сохраненной записи исключений - вы хотите сделать что-то вроде k 10
для фактической печати. Или, поскольку вы используете WinDBG, откройте окно вызова.
(Возможно, вы уже это делаете, я не уверен в вашем описании, как .ecx не работает - он должен печатать что-то, чтобы вы знали, что он/не может сделать...)
Еще одна вещь, которую нужно проверить, это то, что вы на самом деле получаете указатели на указатели - код будет генерировать дамп без них, но вы получите фанк-код.
Вы упомянули в комментарии к ответу на Alex, имея некоторые помехи от DLL, переопределяющего ваш фильтр библиотекой времени выполнения... Это обычная проблема. Мне посчастливилось использовать технику, описанную Олегом Стародумовым:
Существует еще один подход, и его намного проще реализовать, чем предыдущие два. После того, как мы зарегистрировали собственный фильтр, мы можем исправить начало функции SetUnhandledExceptionFilter
, чтобы он больше не мог регистрировать фильтры.
Он предоставляет для этой цели удобный примерный код, который хорошо меня обслуживал на протяжении многих лет.