一个调试器的实现.docx

上传人:marr****208 文档编号:127927530 上传时间:2020-04-07 格式:DOCX 页数:127 大小:833.81KB
返回 下载 相关 举报
一个调试器的实现.docx_第1页
第1页 / 共127页
一个调试器的实现.docx_第2页
第2页 / 共127页
一个调试器的实现.docx_第3页
第3页 / 共127页
一个调试器的实现.docx_第4页
第4页 / 共127页
一个调试器的实现.docx_第5页
第5页 / 共127页
点击查看更多>>
资源描述

《一个调试器的实现.docx》由会员分享,可在线阅读,更多相关《一个调试器的实现.docx(127页珍藏版)》请在金锄头文库上搜索。

1、一个调试器的实现(一)调试事件与调试循环前言程序员离不开调试器,它可以动态显示程序的执行过程,对于解决程序问题有极大的帮助。如果你和我一样对调试器的工作原理很感兴趣,那么这一系列文章很适合你,这些文章记录了我开发一个调试器雏形的过程,希望对你有帮助。或许我写的代码很拙劣,还请大家多多见谅!这个调试器使用Visual Studio 2010作为开发工具,是一个控制台程序。为了简化,一切输入输出都使用C+标准库的相关类,而且省略了很多错误检查和处理的过程。启动被调试程序要想对一个程序进行调试,首先要做的当然是启动这个程序,这要使用CreateProcess这个Windows API来完成。例如,下

2、面的代码以记事本作为被调试程序:1#include2#include34intwmain(intargc,wchar_t*argv)56STARTUPINFOsi=0;7si.cb=sizeof(si);89PROCESS_INFORMATIONpi=0;1011if(CreateProcess(12TEXT(C:windowsnotepad.exe),13NULL,14NULL,15NULL,16FALSE,17DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,18NULL,19NULL,20&si,21&pi)=FALSE)2223std:wcoutTE

3、XT(CreateProcessfailed:)GetLastError()std:endl;24return-1;252627CloseHandle(pi.hThread);28CloseHandle(pi.hProcess);2930return0;31CreateProcess的第六个参数使用了DEBUG_ONLY_THIS_PROCESS,这意味着调用CreateProcess的进程成为了调试器,而它启动的子进程成了被调试的进程。除了DEBUG_ONLY_THIS_PROCESS之外,还可以使用DEBUG_PROCESS,两者的不同在于:DEBUG_PROCESS会调试被调试进程以及它

4、的所有子进程,而DEBUG_ONLY_THIS_PROCESS只调试被调试进程,不调试它的子进程。一般情况下我们只想调试一个进程,所以应使用后者。我建议在第六个参数中加上CREATE_NEW_CONSOLE标记。因为如果被调试程序是一个控制台程序的话,调试器和被调试程序的输出都在同一个控制台窗口内,显得很混乱,加上这个标记之后,被调试程序就会在一个新的控制台窗口中输出信息。如果被调试程序是一个窗口程序,这个标记没有影响。上面的代码仅仅是启动了被调试进程,然后就立即退出了。要注意的是,如果调试器进程结束了,那么被它调试的所有子进程都会随着结束。这就是为什么虽然CreateProcess调用成功了

5、,却看不到记事本窗口。调试循环调试器如何知道被调试进程内部发生了什么呢?是这样的,当一个进程成为被调试进程之后,在完成了某些操作或者发生异常时,它会发送通知给调试器,然后将自身挂起,直到调试器命令它继续执行。这有点像Windows窗口的消息机制。被调试进程发送的通知称为调试事件,DEBUG_EVENT结构体描述了调试事件的内容:1typedefstruct_DEBUG_EVENT2DWORDdwDebugEventCode;3DWORDdwProcessId;4DWORDdwThreadId;5union6EXCEPTION_DEBUG_INFOException;7CREATE_THREAD

6、_DEBUG_INFOCreateThread;8CREATE_PROCESS_DEBUG_INFOCreateProcessInfo;9EXIT_THREAD_DEBUG_INFOExitThread;10EXIT_PROCESS_DEBUG_INFOExitProcess;11LOAD_DLL_DEBUG_INFOLoadDll;12UNLOAD_DLL_DEBUG_INFOUnloadDll;13OUTPUT_DEBUG_STRING_INFODebugString;14RIP_INFORipInfo;15u;16DEBUG_EVENT,17*LPDEBUG_EVENT;dwDebugE

7、ventCode描述了调试事件的类型,总共有9类调试事件:CREATE_PROCESS_DEBUG_EVENT创建进程之后发送此类调试事件,这是调试器收到的第一个调试事件。CREATE_THREAD_DEBUG_EVENT创建一个线程之后发送此类调试事件。EXCEPTION_DEBUG_EVENT发生异常时发送此类调试事件。EXIT_PROCESS_DEBUG_EVENT进程结束后发送此类调试事件。EXIT_THREAD_DEBUG_EVENT一个线程结束后发送此类调试事件。LOAD_DLL_DEBUG_EVENT装载一个DLL模块之后发送此类调试事件。OUTPUT_DEBUG_STRING_

8、EVENT被调试进程调用OutputDebugString之类的函数时发送此类调试事件。RIP_EVENT发生系统调试错误时发送此类调试事件。UNLOAD_DLL_DEBUG_EVENT卸载一个DLL模块之后发送此类调试事件。每种调试事件的详细信息通过联合体u来记录,通过u的字段的名称可以很快地判断哪个字段与哪种事件关联。例如CREATE_PROCESS_DEBUG_EVENT调试事件的详细信息由CreateProcessInfo字段来记录。dwProcessId和dwThreadId分别是触发调试事件的进程ID和线程ID。一个调试器可能同时调试多个进程,而每个进程内又可能有多个线程,通过这两

9、个字段就可以知道调试事件是从哪个进程的哪个线程触发的了。本系列文章只考虑单进程单线程的情况,因此这两个字段不会被用到,因为在调用CreateProcess的时候已经获取到这两个值了。调试器通过WaitForDebugEvent函数获取调试事件,通过ContinueDebugEvent继续被调试进程的执行。ContinueDebugEvent有三个参数,第一和第二个参数分别是进程ID和线程ID,表示让指定进程内的指定线程继续执行。通常这是在一个循环中完成的,如下面的代码所示:1voidOnProcessCreated(constCREATE_PROCESS_DEBUG_INFO*);2voidO

10、nThreadCreated(constCREATE_THREAD_DEBUG_INFO*);3voidOnException(constEXCEPTION_DEBUG_INFO*);4voidOnProcessExited(constEXIT_PROCESS_DEBUG_INFO*);5voidOnThreadExited(constEXIT_THREAD_DEBUG_INFO*);6voidOnOutputDebugString(constOUTPUT_DEBUG_STRING_INFO*);7voidOnRipEvent(constRIP_INFO*);8voidOnDllLoaded(

11、constLOAD_DLL_DEBUG_INFO*);9voidOnDllUnloaded(constUNLOAD_DLL_DEBUG_INFO*);1011BOOLwaitEvent=TRUE;12DEBUG_EVENTdebugEvent;13while(waitEvent=TRUE&WaitForDebugEvent(&debugEvent,INFINITE)1415switch(debugEvent.dwDebugEventCode)1617caseCREATE_PROCESS_DEBUG_EVENT:18OnProcessCreated(&debugEvent.u.CreatePro

12、cessInfo);19break;2021caseCREATE_THREAD_DEBUG_EVENT:22OnThreadCreated(&debugEvent.u.CreateThread);23break;2425caseEXCEPTION_DEBUG_EVENT:26OnException(&debugEvent.u.Exception);27break;2829caseEXIT_PROCESS_DEBUG_EVENT:30OnProcessExited(&debugEvent.u.ExitProcess);31waitEvent=FALSE;32break;3334caseEXIT_

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 其它相关文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号