处理关键的调试事件

来源:互联网 发布:数据库系统教程答案 编辑:程序博客网 时间:2024/06/10 05:59

必知

可以先阅读一下[Win32]一个调试器的实现(三)异常,写得非常好!

当程序中发生异常时,我们的调试器是会接收到EXCEPTION_DEBUG_EVENT调试事件的。但是这时候到底要不要处理这个调试事件,我们还必须斟酌一下。因为很可能程序里有相应的异常处理代码,而这时我们的调试器就没有什么必要接管这个异常。异常的分发过程如图:
异常的分发过程
这里是我的代码,可以拿去把玩一下,感受一下Windows的异常机制:
①myDEBUG.cpp

#include "stdafx.h"#include <iostream>#include <Windows.h>using namespace std;DWORD continue_status = DBG_EXCEPTION_NOT_HANDLED;//异常调试事件处理函数void OnException(const EXCEPTION_DEBUG_INFO* excpt_debug_info){    cout<<"\tAn exception occured at "<<hex<<excpt_debug_info->ExceptionRecord.ExceptionAddress<<endl        <<"\tException code: "<<excpt_debug_info->ExceptionRecord.ExceptionCode<<dec<<endl;    if(excpt_debug_info->dwFirstChance){        cout<<"\tfirst chance"<<endl;        continue_status = DBG_EXCEPTION_NOT_HANDLED;    }else{        cout<<"\tsecond chance"<<endl;        continue_status = DBG_EXCEPTION_NOT_HANDLED;    }}void main(){    PROCESS_INFORMATION process_info;    STARTUPINFO startup_info;    memset(&process_info, 0, sizeof(process_info));    memset(&startup_info, 0, sizeof(startup_info));    startup_info.cb = sizeof(STARTUPINFO);    if(CreateProcess(TEXT("E:\\myCode\\dividedByZero\\Debug\\dividedByZero.exe"),NULL, NULL, NULL, FALSE,        DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE,NULL, NULL, &startup_info, &process_info)){            //ResumeThread(process_info.hThread);            while(true){                DEBUG_EVENT debug_info;                if(!WaitForDebugEvent(&debug_info, INFINITE))                    break;                switch (debug_info.dwDebugEventCode)                {                case CREATE_PROCESS_DEBUG_EVENT://创建进程                    cout<<"CREATE_PROCESS_DEBUG_EVENT"<<endl;                    break;                case CREATE_THREAD_DEBUG_EVENT://创建线程                    cout<<"CREATE_THREAD_DEBUG_EVENT"<<endl;                    break;                case EXIT_THREAD_DEBUG_EVENT://退出线程                    cout<<"EXIT_THREAD_DEBUG_EVENT"<<endl;                    break;                case EXIT_PROCESS_DEBUG_EVENT://退出进程                    cout<<"EXIT_PROCESS_DEBUG_EVENT"<<endl;                    break;                case EXCEPTION_DEBUG_EVENT://发生异常                    cout<<"EXCEPTION_DEBUG_EVENT"<<endl;                    OnException(&debug_info.u.Exception);                    break;                case OUTPUT_DEBUG_STRING_EVENT://调用OutputDebugString函数                    cout<<"OUTPUT_DEBUG_STRING_EVENT"<<endl;                    break;                case RIP_EVENT://发生系统调试错误                    cout<<"RIP_EVENT"<<endl;                    break;                case LOAD_DLL_DEBUG_EVENT://加载dll                    cout<<"LOAD_DLL_DEBUG_EVENT"<<endl;                    break;                case UNLOAD_DLL_DEBUG_EVENT://卸载dll                    cout<<"UNLOAD_DLL_DEBUG_EVENT"<<endl;                    break;                }                if(debug_info.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)                    break;                ContinueDebugEvent(debug_info.dwProcessId, debug_info.dwThreadId, continue_status);            }            CloseHandle(process_info.hThread);            CloseHandle(process_info.hProcess);    }else{        cout<<"Can't create process."<<endl;    }}

②dividedByZero.cpp

#include "stdafx.h"#include <Windows.h>int _tmain(int argc, _TCHAR* argv[]){    OutputDebugString(TEXT("Warning! An exception will be thrown!"));    __try {        int a = 0;        int b = 10 / a;        getchar();    }    __except(EXCEPTION_EXECUTE_HANDLER) {        OutputDebugString(TEXT("Entered exception handler."));    }    return 0;}

以上两段代码结合起来的效果如图:
效果

思路

现在可以知道,EXCEPTION_DEBUG_EVENT调试事件是调试器和debugee交互的重要手段,通过处理EXCEPTION_DEBUG_EVENT调试事件可以完成常规的断点、单步执行等操作。而ContinueDebugEvent函数的第三个参数非常重要,我们可以使用DBG_CONTINUEDBG_EXCEPTION_NOT_HANDLED来影响调试器的行为。
所以,若我们希望调试器仅仅在程序没有异常处理器时才对接管异常,就可以在第一次接收到异常调试事件时以DBG_EXCEPTION_NOT_HANDLED继续执行,在第二次接收到异常调试事件时才对其进行处理。

0 0