Although most of the Windows debugging functions are used to create a debugger, several functions are designed for use in the process being debugged.
To start a process and debug it, a debugger must use CreateProcess, as described in the previous section.
To debug a process that is already executing, the debugger should use DebugActiveProcess with the process identifier retrieved by OpenProcess. DebugActiveProcess attaches the debugger to the active process. In this case, only the active process can be debugged; its child processes cannot. The debugger must have appropriate access to the executing process to use DebugActiveProcess. For more information about access rights, see Security.
After the debugger has either created or attached itself to the process it intends to debug, the kernel notifies the debugger of all debugging events that occur in the process, and, if specified, in any child processes. For more information about debugging events, see Debugging Events.
The debugger uses the WaitForDebugEvent function at the beginning of its main loop. This function blocks the debugger until a debugging event occurs. When the debugging event occurs, the system suspends all threads in the process being debugged and notifies the debugger of the event. The debugger can call the SetDebugErrorLevel function to set the minimum error level at which Windows will pass the debugging event to it.
The debugger can interact with the user, or manipulate the state of the process being debugged, by using the GetThreadContext, GetThreadSelectorEntry, ReadProcessMemory, SetThreadContext, and WriteProcessMemory functions. GetThreadSelectorEntry returns the descriptor table entry for a specified selector and thread. Debuggers use the descriptor table entry to convert a segment-relative address to a linear virtual address. The ReadProcessMemory and WriteProcessMemory functions require linear virtual addresses.
Debuggers frequently read the memory of the process being debugged and write the memory that contains instructions to the instruction cache. After the instructions are written, the debugger calls FlushInstructionCache to execute the cached instructions.
The debugger uses the ContinueDebugEvent function at the end of its main loop. This function allows the process being debugged to continue executing.