Instruction address breakpoint conditions are faults, while other debug
conditions are traps. The debug exception may report either or both at one
time. The following paragraphs present details for each class of debug
Table 12-2. Debug Exception Conditions
Flags to Test Condition
BS=1 Single-step trap
B0=1 AND (GE0=1 OR LE0=1) Breakpoint DR0, LEN0, R/W0
B1=1 AND (GE1=1 OR LE1=1) Breakpoint DR1, LEN1, R/W1
B2=1 AND (GE2=1 OR LE2=1) Breakpoint DR2, LEN2, R/W2
B3=1 AND (GE3=1 OR LE3=1) Breakpoint DR3, LEN3, R/W3
BD=1 Debug registers not available; in use by ICE-386.
BT=1 Task switch
The RF (restart flag) permits the debug handler to retry instructions that cause other kinds of faults in addition to debug faults. When it detects a fault, the processor automatically sets RF in the flags image that it pushes onto the stack. (It does not, however, set RF for traps and aborts.)
When RF is set, it causes any debug fault to be ignored during the next instruction. (Note, however, that RF does not cause breakpoint traps to be ignored, nor other kinds of faults.)
The processor automatically clears RF at the successful completion of every instruction except after the IRET instruction, after the POPF instruction, and after a JMP, CALL, or INT instruction that causes a task switch. These instructions set RF to the value specified by the memory image of the EFLAGS register.
The processor automatically sets RF in the EFLAGS image on the stack before entry into any fault handler. Upon entry into the fault handler for instruction address breakpoints, for example, RF is set in the EFLAGS image on the stack; therefore, the IRET instruction at the end of the handler will set RF in the EFLAGS register, and execution will resume at the breakpoint address without generating another breakpoint fault at the same address.
If, after a debug fault, RF is set and the debug handler retries the faulting instruction, it is possible that retrying the instruction will raise other faults. The retry of the instruction after these faults will also be done with RF=1, with the result that debug faults continue to be ignored. The processor clears RF only after successful completion of the instruction.
Real-mode debuggers can control the RF flag by using a 32-bit IRET. A 16-bit IRET instruction does not affect the RF bit (which is in the high-order 16 bits of EFLAGS). To use a 32-bit IRET, the debugger must rearrange the stack so that it holds appropriate values for the 32-bit EIP, CS, and EFLAGS (with RF set in the EFLAGS image). Then executing an IRET with an operand size prefix causes a 32-bit return, popping the RF flag into EFLAGS.
When using data breakpoints it is recommended that either the LE or GE bit of DR7 be set also. If either LE or GE is set, any data breakpoint trap is reported exactly after completion of the instruction that accessed the specified memory item. This exact reporting is accomplished by forcing the 80386 execution unit to wait for completion of data operand transfers before beginning execution of the next instruction. If neither GE nor LE is set, data breakpoints may not be reported until one instruction after the data is accessed or may not be reported at all. This is due to the fact that, normally, instruction execution is overlapped with memory transfers to such a degree that execution of the next instruction may begin before memory transfers for the prior instruction are completed.
If a debugger needs to preserve the contents of a write breakpoint location, it should save the original contents before setting a write breakpoint. Because data breakpoints are traps, a write into a breakpoint location will complete before the trap condition is reported. The handler can report the saved value after the breakpoint is triggered. The data in the debug registers can be used to address the new value stored by the instruction that triggered the breakpoint.
The processor clears the TF bit before invoking the handler. If TF=1 in the flags image of a TSS at the time of a task switch, the exception occurs after the first instruction is executed in the new task.
The single-step flag is normally not cleared by privilege changes inside a task. INT instructions, however, do clear TF. Therefore, software debuggers that single-step code must recognize and emulate INT n or INTO rather than executing them directly.
To maintain protection, system software should check the current execution privilege level after any single step interrupt to see whether single stepping should continue at the current privilege level.
The interrupt priorities in hardware guarantee that if an external interrupt occurs, single stepping stops. When both an external interrupt and a single step interrupt occur together, the single step interrupt is processed first. This clears the TF bit. After saving the return address or switching tasks, the external interrupt input is examined before the first instruction of the single step handler executes. If the external interrupt is still pending, it is then serviced. The external interrupt handler is not single-stepped. To single step an interrupt handler, just single step an INT n instruction that refers to the interrupt handler.
Note that if the debug exception handler is a task, the T-bit of its TSS should not be set. Failure to observe this rule will cause the processor to enter an infinite loop.
With prior generations of processors, this feature is used extensively for trapping execution of specific instructions. With the 80386, the needs formerly filled by this feature are more conveniently solved via the debug registers and interrupt 1. However, the breakpoint exception is still useful for debugging debuggers, because the breakpoint exception can vector to a different exception handler than that used by the debugger. The breakpoint exception can also be useful when it is necessary to set a greater number of breakpoints than permitted by the debug registers.
Chapter 12 -- Debugging
prev: 12.2 Debug Registers
next: Chapter 13 -- Executing 80286 Protected-Mode Code