Дамп Windbg, сгенерированный программно, не может быть отлажен

У меня есть простая программа:

int ExecuteCommand(wchar_t* commandLine)
{

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    BOOL bRet;
    DWORD lpExitCode;

    memset(&si, 0, sizeof(si));
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;

    bRet = CreateProcess(
        NULL, // pointer to name of executable module
        commandLine, // pointer to command line string
        NULL, // process security attributes
        NULL, // thread security attributes
        FALSE, // handle inheritance flag
        NORMAL_PRIORITY_CLASS, // creation flags
        NULL, // pointer to new environment block
        NULL, // pointer to current directory name
        &si, // pointer to STARTUPINFO
        &pi // pointer to PROCESS_INFORMATION
        );

    if(bRet) WaitForSingleObject(pi.hProcess, INFINITE); // wait for process to finish

    GetExitCodeProcess(pi.hProcess, &lpExitCode);

    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);

    return lpExitCode;
}

void CreateCoreDump()
{
    wchar_t buffer[256];
    wsprintf(buffer, _T("windbg -p %d -c \".dump /mfh /u C:\\Tmp\\crashdump.dmp\""), GetCurrentProcessId());

    ExecuteCommand(buffer);
}

DWORD ExceptionFilter()
{
    CreateCoreDump();

    return EXCEPTION_CONTINUE_SEARCH;
}


int _tmain(int argc, _TCHAR* argv[])
{
    __try
    {
        int* p = NULL;
        *p = 100;
    }
    __except(ExceptionFilter())
    {
    }
    return 0;
}

Он будет генерировать дамп ядра при возникновении исключения, используя функцию CreateCoreDump. Хотя файл дампа может быть успешно сгенерирован, он кажется бесполезным:
Если я открою этот файл дампа с помощью windbg, в стеке вызовов ничего не будет!!!

Но, если я отлаживаю это приложение прямо в windbg, и ставлю точку останова в строке вызова CreateCoreDump, а затем запускаю команду windbg:

.dump /mfh C:\Tmp\mydump.dmp

Откройте этот файл дампа с помощью WinDbg, я вижу полный стек вызовов.

Я сделал что-то не так, либо при создании файла дампа, либо при отладке файла дампа с помощью windbg?


person baye    schedule 25.08.2011    source источник


Ответы (2)


Когда вы подключаете отладчик после возникновения исключения, отладчик не видит событие исключения. Он создает поток с точкой останова, поэтому стек в этом потоке выглядит примерно так:

0:001> kc
Call Site
ntdll!DbgBreakPoint
ntdll!DbgUiRemoteBreakin+0x38
kernel32!BaseThreadInitThunk+0xd
ntdll!RtlUserThreadStart+0x1d

Если вы вручную установите текущий поток в поток 0 (используйте ~0s), вы увидите свой стек

0:001> ~0s
ntdll!ZwWaitForSingleObject+0xa:
00000000`76e5135a c3              ret
0:000> kc
Call Site
ntdll!ZwWaitForSingleObject
KERNELBASE!WaitForSingleObjectEx
tmp!ExceptionFilter
tmp!main$filt$0
ntdll!__C_specific_handler
ntdll!RtlpExecuteHandlerForException
ntdll!RtlDispatchException
ntdll!KiUserExceptionDispatch
tmp!main
tmp!__mainCRTStartup
kernel32!BaseThreadInitThunk
ntdll!RtlUserThreadStart

Когда вы запускаете свою программу под отладчиком, происходят две вещи: во-первых, есть только один поток, а во-вторых, отладчик знает об исключении, поэтому он напечатает что-то вроде этого:

This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.

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

person John    schedule 25.08.2011
comment
Спасибо, Джон, это работает. Вы упомянули, что отладчик не видит событие исключения, потому что файл дампа создается кодом, верно? - person baye; 26.08.2011
comment
Когда отладчик подключен к процессу, он прослушивает события отладки (см. msdn.microsoft.com/en-us/library/ms679302(VS.85).aspx). Когда отладчик подключен, когда возникает исключение, он увидит событие EXCEPTION_DEBUG_EVENT и узнает, что в процессе есть исключение. Уведомление о событии происходит перед обработкой исключения (первый шанс) и может произойти во второй раз, если в цепочке не найден обработчик исключения. Когда вы подключаете отладчик, это происходит после уведомления о первом шансе. - person John; 26.08.2011
comment
Вы можете заставить отладчик увидеть исключение второго шанса (если исключение не перехвачено кем-то другим), используя -g и -e event. флаги. -e указывает отладчику сигнализировать о данном событии, когда оно присоединено, поэтому вам нужно создать наследуемое событие уведомления, отправить его дескриптор (в виде десятичного числа) в качестве значения для аргумента -e и дождаться события после создания дочернего процесса. - person John; 26.08.2011

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

void CreateCoreDump(LPEXCEPTION_POINTERS p)
{
    wchar_t buffer[256];
    // I used the command line debugger, cdb, and added a "qd" command for it to exit after dumping.
    wsprintf(buffer, _T("cdb.exe -p %d -c \".dump /mfh /u /xt 0x%x /xp 0x%p C:\\Tmp\\crashdump.dmp\";qd"), GetCurrentProcessId(), GetCurrentThreadId(), p);
    ExecuteCommand(buffer);
}

DWORD ExceptionFilter(LPEXCEPTION_POINTERS p)
{
    CreateCoreDump(p);
    return EXCEPTION_CONTINUE_SEARCH;
}

int _tmain(int argc, _TCHAR* argv[])
{
    __try
    {
        int* p = NULL;
        *p = 100;
    }
    __except(ExceptionFilter(GetExceptionInformation()))
    {
    }
    return 0;
}

Затем, когда вы открываете дамп в Windgb, отладчик знает об исключении. Вы можете использовать .ecxr для установки текущего потока и стека в точке исключения.

0:000> .ecxr
eax=00000000 ebx=00000000 ecx=6ec4471c edx=00000000 esi=00000001 edi=010c337c
eip=010c108b esp=0038f5e8 ebp=0038f818 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
test!wmain+0x14:
010c108b c70064000000    mov     dword ptr [eax],64h  ds:002b:00000000=????????
0:000> kc
test!wmain
test!__tmainCRTStartup
kernel32!BaseThreadInitThunk
ntdll!__RtlUserThreadStart
ntdll!_RtlUserThreadStart
person plodoc    schedule 30.08.2011