The software breakpoints are generally used for applications in RAM, because changing the instructions in RAM is easy for the debugger.
With software breakpoints, the debugger replaces an instructions with an illegal instruction or with a dedicated breakpoint instruction supported by the instruction set of the microcontroller. To illustrate this, below is some code in RAM starting at address 0×100. The LDA load instruction from the address 0×80 is encoded as 0×3788, as the following figure shows:
If you set a breakpoint on the multiply MULA instruction at address 0×102. Assuming that this architecture has a breakpoint instruction encoded as 0xffff, the debugger simply can replace the opcode at address 0×102 with the 0xffff BKPT opcode:
If the processor runs the code at address 0×102, it triggers the debug module as defined in the microcontroller architecture.
You can use this as well in your application code. For example the ARM Cortex architecture supports the BKPT instruction. You can use this to have present in an interrupt routine to stop your target. The processor will cause an illegal instruction exception which the debugger can catch, as the following listing shows:
1 void __attribute__((interrupt)) ISR_Unhandled(void) { 2 asm("BKPT 255"); /* sofware breakpoint */ 3 }
The debugger does the replacement just as part of restarting the processor. And it restores the original content after the processor has stopped. The debugger maintains a list of places where it has replaced the memory with the breakpoint instructions. You can see the replaced instruction, as the following image shows: