windows获取程序调试信息

来源:互联网 发布:上海用友软件 编辑:程序博客网 时间:2024/05/17 19:58

windows获取程序调试信息

通常能调试的时候,可以放断点进行调试以及加日志log的方式,然后有时候无法放断点调试(比如正式版本),此时我们需要查看日志log进行分析问题。日志一般通过写文件完成,但是如果我们程序都是通过printf outputDebugString输出的调试信息,此时该如何查看这些调试信息。不知道你是否注意到VS调试程序时候,会把这些信息输出到输出窗口,这是如何实现的呢?接下来我们就去实现一个调试器

  • WaitForDebugEvent
BOOL WINAPI WaitForDebugEvent(  _Out_ LPDEBUG_EVENT lpDebugEvent,  _In_  DWORD         dwMilliseconds);

用于等待调试事件,调用此函数会阻塞当前线程,当比如prinft,创建线程等事件就会唤醒此函数。得到事件通知,然后解析DEBUG_EVENT结构,并对事件进行响应,处理完成后调试器将会调用ContinueDebugEvent,并根据参数来通知调试目标执行相应操作。

lpDebugEvent :指向接收调试事件信息的DEBUG_ ENENT结构的指针
dwMilliseconds:指定用来等待调试事件发生的毫秒数,如果 这段时间内没有调试事件发生,函数将返回调用者;如果将该参数指定为INFINITE,函数将一直等待直到调试事件发生

  • ContinueDebugEvent
BOOL ContinueDebugEvent(  DWORD dwProcessId,       // process to continue  DWORD dwThreadId,        // thread to continue  DWORD dwContinueStatus   // continuation status);

此函数允许调试器恢复先前由于调试事件而挂起的线程。(比如我们写的调试器为进程A, 被调试的进程为B,当A的WaitForDebugEvent接收到事件的时候,B进程的发出事件的线程会被挂起,当A处理完事件后调用ContinueDebugEvent恢复B中被挂起的那个线程)

dwProcessId: 为被调试进程的进程标识符
dwThreadId : 为欲恢复线程的线程标识符
dwContinueStatus指定了该线程将以何种方式继续,包含两个定义值DBG_CONTINUE和DBG_EXCEPTION_NOT_HANDLED

  • DebugActiveProcess
BOOL DebugActiveProcess(  DWORD dwProcessId   // process to be debugged);

此函数允许将调试器捆绑到一个正在运行的进程上(这里我们传入进程B的进程id)。

下来就是获取调试信息的主要代码

DWORD CDebugInfoDlg::GetDebugInfoProc( LPARAM lparam ){ CDebugInfoDlg* pThis = (CDebugInfoDlg*)lparam; if (pThis->m_hProcess == INVALID_HANDLE_VALUE) {  return 1; } DebugActiveProcess(pThis->m_dwProcessId); while (m_bThreadLive) {  DEBUG_EVENT DebugEv;                   // debugging event information   // Wait for a debugging event to occur. The second parameter indicates   // that the function does not return until a debugging event occurs.   WaitForDebugEvent(&DebugEv, INFINITE);   // Process the debugging event code.   switch (DebugEv.dwDebugEventCode)   {   case EXCEPTION_DEBUG_EVENT:    // Process the exception code. When handling    // exceptions, remember to set the continuation    // status parameter (dwContinueStatus). This value    // is used by the ContinueDebugEvent function.    switch (DebugEv.u.Exception.ExceptionRecord.ExceptionCode)    {    case EXCEPTION_ACCESS_VIOLATION:     // First chance: Pass this on to the system.     // Last chance: Display an appropriate error.     break;   case EXCEPTION_BREAKPOINT:     // First chance: Display the current     // instruction and register values.     break;   case EXCEPTION_DATATYPE_MISALIGNMENT:     // First chance: Pass this on to the system.     // Last chance: Display an appropriate error.     break;   case EXCEPTION_SINGLE_STEP:     // First chance: Update the display of the     // current instruction and register values.     break;   case DBG_CONTROL_C:     // First chance: Pass this on to the system.     // Last chance: Display an appropriate error.     // Handle other exceptions.     break;   }    break;   case CREATE_THREAD_DEBUG_EVENT:     // As needed, examine or change the thread's registers     // with the GetThreadContext and SetThreadContext functions;     // and suspend and resume thread execution with the     // SuspendThread and ResumeThread functions.     break;   case CREATE_PROCESS_DEBUG_EVENT:     // As needed, examine or change the registers of the     // process's initial thread with the GetThreadContext and     // SetThreadContext functions; read from and write to the     // process's virtual memory with the ReadProcessMemory and     // WriteProcessMemory functions; and suspend and resume     // thread execution with the SuspendThread and ResumeThread     // functions.     break;   case EXIT_THREAD_DEBUG_EVENT:     // Display the thread's exit code.     break;   case EXIT_PROCESS_DEBUG_EVENT:     // Display the process's exit code.     break;   case LOAD_DLL_DEBUG_EVENT:     // Read the debugging information included in the newly     // loaded DLL.     break;   case UNLOAD_DLL_DEBUG_EVENT:     // Display a message that the DLL has been unloaded.     break;   case OUTPUT_DEBUG_STRING_EVENT:     // Display the output debugging string.     {     char szbuf[1024] = {0};     DWORD dwRead = 0;     //读取被调试进程调试信息     if(ReadProcessMemory(pThis->m_hProcess, DebugEv.u.DebugString.lpDebugStringData, szbuf,          DebugEv.u.DebugString.nDebugStringLength, &dwRead))     {      EnterCriticalSection(&g_cs);      CDebugInfoDlg::m_csBuf += szbuf;      LeaveCriticalSection(&g_cs);      ::PostMessage(pThis->m_hWnd, WM_UPDATA_VIEW, 0, 0);     }    }    break;  }   // Resume executing the thread that reported the debugging event.   ContinueDebugEvent(DebugEv.dwProcessId,    DebugEv.dwThreadId, DBG_CONTINUE);  } return 0;}

这些api不仅仅可以读取调试信息,还能实现抓取异常崩溃的调用堆栈等功能。

1 0
原创粉丝点击