Создание исключения 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, чтобы он больше не мог регистрировать фильтры.

Он предоставляет для этой цели удобный примерный код, который хорошо меня обслуживал на протяжении многих лет.