一个【调试事件】是被调试过程中的事件,导致内核通知调试器。调试事件包括创建进程,创建线程,加载动态链接库(DLL),卸载DLL,发送输出字符串和生成异常。
如果在调试器等待一个调试事件时发生调试事件,内核将使用描述该事件的信息来填充WaitForDebugEvent指定的DEBUG_EVENT结构。
当内核通知调试器调试事件时,它也会挂起受影响进程中的所有线程。调试器通过使用ContinueDebugEvent继续调试事件之前,线程不会恢复执行。在调试进程时可能会发生以下调试事件。
调试事件 | 描述 | ||||
CREATE_PROCESS_DEBUG_EVENT | |||||
每当在正在调试的进程中创建新进程时或每当调试器开始调试已经活动的进程时生成。内核在进程开始以用户模式执行之前,内核为新进程生成任何其他调试事件之前生成此调试事件。 | |||||
DEBUG_EVENT结构包含CREATE_PROCESS_DEBUG_INFO结构。该结构包括新进程的句柄,进程的图像文件的句柄,进程的初始线程的句柄以及描述新进程的其他信息。 | |||||
进程的句柄具有PROCESS_VM_READ和PROCESS_VM_WRITE访问权限。如果调试器对线程有这些类型的访问权限,则可以使用ReadProcessMemory和WriteProcessMemory函数来读取和写入进程的内存。 | |||||
进程的图像文件的句柄具有GENERIC_READ访问权限,并打开以进行读取共享。 | |||||
进程的初始线程的句柄具有THREAD_GET_CONTEXT,THREAD_SET_CONTEXT和THREAD_SUSPEND_RESUME对线程的访问权限。如果调试器对线程有这些类型的访问权限,则可以使用GetThreadContext和SetThreadContext函数从线程的寄存器读取和写入,并可以使用SuspendThread和ResumeThread来暂停和恢复线程,功能。 | |||||
CREATE_THREAD_DEBUG_EVENT | |||||
每当在被调试的进程中创建新线程或每当调试器开始调试已经活动的进程时生成。此调试事件在新线程以用户模式开始执行之前生成。 | |||||
DEBUG_EVENT结构包含CREATE_THREAD_DEBUG_INFO结构。该结构包括新线程的句柄和线程的起始地址。句柄具有THREAD_GET_CONTEXT,THREAD_SET_CONTEXT和THREAD_SUSPEND_RESUME对线程的访问权限。如果一个调试器对线程有这些类型的访问权限,它可以使用GetThreadContext和SetThreadContext函数从线程的寄存器中读取和写入,并可以使用SuspendThread和ResumeThread来挂起和恢复线程,功能。 | |||||
EXCEPTION_DEBUG_EVENT | |||||
在正在调试的进程中发生异常时生成。可能的例外包括尝试访问不可访问的内存,执行断点指令,尝试除以零,或结构化异常处理中记录的任何其他异常。 | |||||
DEBUG_EVENT结构包含EXCEPTION_DEBUG_INFO结构。此结构描述导致调试事件的异常。 | |||||
除了标准异常条件外,控制台进程调试期间可能会发生额外的异常代码。当CTRL + C输入到处理CTRL + C信号并正在调试的控制台进程时,内核会生成一个DBG_CONTROL_C异常代码。此异常代码不是由应用程序处理。应用程序不应该使用异常处理程序来处理它。仅为了调试器的好处而提出,仅在调试器附加到控制台进程时使用。 | |||||
如果一个进程没有被调试,或者调试器通过未处理的DBG_CONTROL_C异常(通过gn命令),则搜索应用程序的处理函数列表,如SetConsoleCtrlHandler 功能所述。 | |||||
如果调试器处理DBG_CONTROL_C异常(通过gh命令),应用程序将不会注意到CTRL + C,除了这样的代码。 | |||||
while ((inputChar = getchar()) != EOF) ... while(gets(inputString))... | |||||
因此,调试器不能用于停止这种代码中的读取等待。 | |||||
EXIT_PROCESS_DEBUG_EVENT | |||||
正在调试的进程中的最后一个线程退出时生成。在内核卸载进程的DLL并更新进程的退出代码之后,这种调试事件会立即发生。 | |||||
DEBUG_EVENT结构包含一个指定退出代码的EXIT_PROCESS_DEBUG_INFO结构。 | |||||
调试器在接收到此调试事件时释放与进程相关联的任何内部结构。内核关闭调试器的退出进程和所有进程的线程的句柄。 | |||||
EXIT_THREAD_DEBUG_EVENT | |||||
每当正在调试的进程的一部分线程退出时生成。内核在更新线程的退出代码后立即生成此调试事件。 | |||||
DEBUG_EVENT结构包含一个指定退出代码的EXIT_THREAD_DEBUG_INFO结构。 | |||||
调试器在接收到此调试事件时释放与线程相关联的任何内部结构。系统关闭调试器的退出线程的句柄。 | |||||
如果退出的线程是进程的最后一个线程,则不会发生此调试事件。在这种情况下,会发生EXIT_PROCESS_DEBUG_EVENT调试事件。 | |||||
LOAD_DLL_DEBUG_EVENT | |||||
每当正在调试的进程加载DLL时生成。当系统加载程序解析到DLL的链接或调试进程使用LoadLibrary函数时,会发生此调试事件。此调试事件仅在内核将DLL附加到进程的虚拟地址空间时发生。 | |||||
DEBUG_EVENT结构包含LOAD_DLL_DEBUG_INFO结构。该结构包括新加载的DLL的句柄,DLL的基地址以及描述该DLL的其他信息。 | |||||
通常,调试器在接收到此调试事件时加载与DLL相关联的符号表。 | |||||
OUTPUT_DEBUG_STRING_EVENT | |||||
当被调试的进程使用OutputDebugString功能时生成。 | |||||
DEBUG_EVENT结构包含OUTPUT_DEBUG_STRING_INFO结构。此结构指定调试字符串的地址,长度和格式。 | |||||
UNLOAD_DLL_DEBUG_EVENT | |||||
每当正在调试的进程通过使用FreeLibrary函数卸载DLL时生成。此调试事件仅在上一次从进程的地址空间卸载DLL(即DLL的使用次数为零时)发生。 | |||||
DEBUG_EVENT结构包含UNLOAD_DLL_DEBUG_INFO结构。此结构在卸载DLL的进程的地址空间中指定了DLL的基址。 | |||||
通常,调试器在收到此调试事件后卸载与DLL关联的符号表。 | |||||
当进程退出时,内核会自动卸载进程的DLL,但不生成UNLOAD_DLL_DEBUG_EVENT调试事件。 |