以编程方式生成的 Windbg 转储无法调试

发布于 2024-12-01 14:33:55 字数 1826 浏览 4 评论 0原文

我有一个简单的程序:

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 调试转储文件时是否做错了什么?

I have a simple program:

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;
}

It will generate a core dump when there is an exception, using function CreateCoreDump. Although the dump file could be generated successfully, it seems useless:
If I open this dump file using windbg, there is nothing in call stack!!!

But, if I debug this application directly in windbg, and set breakpoint at the line of calling CreateCoreDump, and then run windbg command:

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

Open this dump file with WinDbg, I can see the full call stack.

Did I do something wrong, either in generating the dump file, or debugging the dump file using windbg?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

太傻旳人生 2024-12-08 14:33:55

当异常发生后附加调试器时,调试器不会看到异常事件。它创建一个具有断点的线程,因此该线程上的堆栈看起来像这样:

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命令进入有趣的线程。在这种情况下,您不需要这样做,因为当前的调试器线程已经是您想要的线程。

When you attach the debugger after the exception happens, the debugger does not see the exception event. It creates a thread that has a breakpoint so the stack on that thread looks something like this:

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

If you manually set the current thread to thread 0 (use ~0s) you will see your stack

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

When you start your program under the debugger two things happen, first, there is only one thread, and second the debugger knows about the exception so it will print something like this:

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

which tells you that you need to use the .ecxr commmand to get to the interesting thread. In this case you do not need to because the current debugger thread is already the one you want.

感情洁癖 2024-12-08 14:33:55

您必须将异常记录添加到转储中。例如,我更改了您的示例以检索过滤器中的异常信息,并在生成转储时将其传递到命令行。

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

You have to add the exception record to the dump. For instance, I changed your sample to retrieve the exception information in the filter and pass it on the command line when generating the dump.

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;
}

Then when you open the dump in windgb, the debugger knows about the exception event. You can use .ecxr to set the current thread and stack at the exception point.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文