Assuming you are talking about a purely software debugger, not an ICE, Jtag or otherwise hardare assisted debugger, then the simple answer is that the processor is simply executing code when it is in the debugger like any other program.
I'm guessing that what you want to know is how does the debugger suspend your program and then pick it up again without affecting it. The exact details depend on the architecture in question, the system running, the exact goals of the debugger and other factors, however in general:
The debugger is entered by an exception - this could be a software interrupt implanted in the code to cause a breakpoint, a hardware exception such as a bad instruction or a memory access violation or whatever other means there are to activate the debugger.
The first thing the debugger will do is save the context of the processor - this normally includes all CPU registers and the state of the MMU (if applicable). This is not unlike the operations performed on a multi-tasking system to context switch from one task to the next. Think of the debugger as just another "task" - at the exception, the currently executing program (your application) gets "swapped out" and the debugger is activated. Another way to look at is is that the debugger is an interrupt handler - your program gets interrupted, the debugger runs, and eventually your program resumes.
Note that in many architectures, much of the context save may have been done by the hardware in processing the exceptions that invoked the debugger.
If the CPU in question has multiple operating modes, tt will have assumed a "supervisor" mode at the time the exception occured. The debugger will normally remain in a privileged mode while it is running so that it can write privileged registers (necessary when context switching back to the application), write code memory (necessary to implant breakpoints, load code patches etc.).
At this point a "bare metal" debugger will retain control of the CPU, usually with all interrupts required by the application system disabled, so that only the debugger code remains active. A debugger which is married to an operating system may allow other parts of the system to continue to run.
So now you can perform debug commands - poke around in memory, look at and change the processor registers etc. Note that you aran't actually manipulating the CPU registers (they are being used by the debugger) - What you are manipulating is the copies of the CPU registers that were saved when the debugger was activated. Since these will be restored before your application is restarted, any changes you make will take effect then.
When you get bored with the debugger and decide to let your program run again, the debugger will context switch back to your program - MMU state and processor registers will be restored - just like returning from an interrupt, or swapping of tasks. The CPU registers are restored from the copies made at the time the debugger was entered, unless you have modified those copies (with "CHANGE REGISTER" commands) the CPU will appear exactly as it did when the debugger interrupted.
Single-stepping is a bit trickier - because the debugger has to "get back in control" after only one instruction - there are several ways this is accomplished.
- The processor may have a trace interrupt which can be set to go off after one instruction.
- You can program a timer to generate an interrupt after just enough cycles to get you into one instruction.
- You can place breakpoints at all possible locations that can be reached after the next instruction to execute.
- You can "interpret" the next instruction (not as bad as it seems, since most instructions can be copied and executed from a local cache - you only need to interpret instruction which cause a change in the flow of control).
Breakpoints are usually implemented by stuffing a software interrupt instruction into the code location to be breakpointed. Most debuggers will wait and implant the breakpoints (and save the original instructions) just before the code is launched and on re-entry to the debugger restore the original opcodes before you get to the debugger command prompt. This way, the implanted breakpoints are never visible to the user in case he happens to examine the code memory while in the debugger.
Actually it's slightly more complicated than that - if you continue from a breakpoint, you don't want to immediately hit the same breakpoint again - you want the original code to execute until the next time that instruction is executed. For this reason, most debugger will single-step one instruction, then implant the breakpoints, then continue your program at full speed.
As noted at the beginning, the exact details of how all this is implemented can vary from one architecture/system to another - the above is a very general description of how many software based debugger work.
Dunfield Development Services http://www.dunfield.com
Low cost software development tools for embedded systems
For hardware assisted ICE (in general) and JTAG (in particular), a debugger can simply stop the core and boundary scan the memories and registers. This works with both internal and external memories, since JTAG can emulate the core in accessing external devices.
That really depends on the target - for ARM7/9, the debugger has the ability to halt the target (draining the pipeline, and then switching the clock to a special debug clock DCLK), boundary-scan access to the bus (both buses, in case of the Harvard ARM9), the ability to cycle the DCLK, and access to breakpoint/watchpoint comparators. It then inserts instructions (place valid instruction on instruction bus in a fetch cycle) into the pipeline and clocks the core which is halted otherwise (ARM7/9's are fully static, and can be halted infinitely), making the instructions advance through the pipeline. When there's data to be read/written from/to the databus, it reads/writes the data, and then continues clocking the core.
The situation is completely different with XScale targets. They have a special mini instruction cache (2kB size on most (all?) I've seen) which the debugger uses to load a small debug handler. When a debug exception occurs, the core branches to 0x0 in special debug state (an addition to the normal ARM core modes). The debugger placed the debug handler at 0x0, and from then on, the debug handler executes on the core just like the user code did before. The debugger and the debug handler communicate through a communication register that is accessible via coprocessor instructions (on the target) and via JTAG.
Direct boundary scan access to memories or registers seems to be implemented on the Cortex-M3 cores, but I haven't looked too closely at them. AFAIK PPC and 68k offer something similar.
The PPC and the 68k are rather different. I don't know much about controlling PPC cores with jtag, but with BDM, the debug interface injects instructions into the core, and can control breakpoints and single-stepping. For the 68k, the BDM interface works independently of the cpu core, uses its own interface to access registers and the bus. On ColdFires (modern m68k cores), the BDM bus interface can run even while the cpu core is running normally, allowing the debugger full access to memory without interrupting the processor.