In the force case scenario, breakpoints are set by changing the existing code and setting debugging code (for x86) interruption.
The code has a length of 1 byte, thus it's safe to modify an existing instruction (of any length).
However, it's necessary to know, where an instruction actually begins. (Without debugging information, the only way to know where an instruction begins is through careful disassembling)
- Save the existing instruction
- Write the interruption code
- Proceed with execution
- On breakpoint event, restore the original code
- Move the execution register to point to the instruction
- Execute a single-step instruction
- Once single-step is completed, restore the debugging break point code
The downside of this approach is the need of single-stepping operation, in order to restore the break-point back.
Actually the next event might not be necessary a single-step event, an error could be returned (because the instruction ire-executed) or another breakpoint. But the breakpoint code must be restored as soon as possible (thus applying single-step is needed)