2011-08-25 60 views
1

我有一个简单的程序: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调试转储文件时出错?

谢谢。

回答

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

+0

谢谢约翰,它的工作原理。你提到“调试器没有看到异常事件”,这是因为转储文件是由代码创建的,对吧? –

+0

当调试器连接到进程时,它正在侦听调试事件(请参阅http://msdn.microsoft.com/zh-cn/library/ms679302(VS.85).aspx)。当发生异常时附加调试器时,它将看到一个EXCEPTION_DEBUG_EVENT事件并知道该过程中存在异常。事件通知发生在异常处理之前(第一次机会),并且如果在链中没有发现异常处理程序,则可能会再次发生。当您连接调试器时,它会在第一次机会通知后发生。 – John

+0

您可以通过使用'-g'和'-e event'来让调试器查看二次机会异常(如果该异常未被其他人捕获)。标志。'-e'告诉调试器在连接时发出给定事件的信号,所以你需要创建一个可继承的通知事件,发送它的句柄(作为十进制数)作为'-e'参数的值,然后等待事件创建子进程后。 – John

1

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

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