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 the system 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.