170 likes | 293 Views
Facilities for x86 debugging. Introduction to Pentium features that can assist programmers in their debugging of software. TF-bit in EFLAGS. Our ‘trydebug.s’ demo showed how to use the TF-bit to perform ‘single-stepping’ of a Linux application program (e.g., ‘hello’)
E N D
Facilities for x86 debugging Introduction to Pentium features that can assist programmers in their debugging of software
TF-bit in EFLAGS • Our ‘trydebug.s’ demo showed how to use the TF-bit to perform ‘single-stepping’ of a Linux application program (e.g., ‘hello’) • The ‘popfd’ instruction was used to set TF • But single-stepping starts only AFTER the immediately following instruction executes • An exception-handler for INT-1 can display information about the state of the task
Using ‘objdump’ output • You can generate an assembler ‘listing’ of the instructions in our ‘hello’ application • You can then use the listing to follow along with the ‘single-stepping’ through that code • Here’s how to do it: $ objdump –d hello > hello.u • (The ‘-d’ option stands for ‘disassembly’)
A slight ‘flaw’ • We cannot single-step the execution of an ‘int-0x80’ instruction (Linux’s system-calls) • Our exception-handler’s ‘iretd’ instruction will restore the TF-bit to EFLAGS, but the single-step ‘trap’ doesn’t take effect until after the immediately following instruction • This means we ‘skip’ seeing a display of the registers immediately after ‘int-0x80’
Fixing the ‘flaw’ • The Pentium offers a way to overcome the problem of a delayed effect when TF is set • We can use the Debug Registers to set an instruction ‘breakpoint’ which will interrupt the CPU at a specific instruction-address • There are six Debug Registers: DR0, DR1, DR2, DR3 (breakpoints) DR6 (the Debug Status register) DR7 *the Debug Control register)
Breakpoint Address Registers DR0 DR1 DR2 DR3
Special ‘MOV’ instructions • Use ‘mov DRn, genreg’ to write into DRn • Use ‘mov genreg, DRn’ to read from DRn • These instructions are ‘privileged’ (i.e., can only be executed by code running in ring0)
Debug Control Register (DR7) 15 0 0 0 G D 0 0 1 G E L E G 3 L 3 G 2 L 2 G 1 L 1 G 0 L 0 Least significant word 31 16 LEN 3 R/W 3 LEN 2 R/W 2 LEN 1 R/W 1 LEN 0 R/W 0 Most significant word
What kinds of breakpoints? LEN R/W LEN 00 = one byte 01 = two bytes 10 = undefined 11 = four bytes R/W 00 = break on instruction fetch only 01 = break on data writes only 10 = undefined (unless DE set in CR4) 11 = break on data reads or writes (but not on instruction fetches)
Control Register 4 • The Pentium uses Control Register 4 to activate certain extended features of the processor, while still allowing for backward compatibility of software written for earlier Intel x86 processors • An example: Debug Extensions (DE-bit) 31 3 0 other feature bits D E CR4
Debug Status Register (DR6) 15 0 B T B S B D 0 1 1 1 1 1 1 1 1 B 3 B 2 B 1 B 0 Least significant word 31 16 unused ( all bits here are set to 1 ) Most significant word
Where to set a breakpoint • Suppose you want to trigger a ‘debug’ fault at the instruction immediately following the software Linux ‘int-0x80’ system-call • Your debug exception-handler can use the saved CS:EIP values on its stack to check that ‘int-0x80’ has caused an exception • Machine-code is: 0xCD, 0x80 (2 bytes) • So set a ‘breakpoint’ at address EIP+2
How to set this breakpoint isrDBG: push ebp mov ebp, esp pushad ; put breakpoint-address in DR0 mov eax, 4[ebp] add eax, #2 mov dr0, eax
Setting a breakpoint (continued) ; enable local breakpoint for DR0 mov eax, DR7 bts eax, #0 ; set LE0 mov DR7, eax … popad pop ebp iretd
Detecting a ‘breakpoint’ • Your debug exception-handler reads DR6 to check for occurrences of breakpoints mov eax, DR6 ; get debug status bt eax, #0 ; breakpoint #0? jnc notBP0 ; no, another cause bts 12[ebp], #16 ; set the RF-bit ; or disable breakpoint0 in register DR7 notBP0:
In-Class Exercise #1 • Modify the debug exception-handler in our ‘trydebug.s’ demo-program (on website) so that it will ‘single-step’ past ‘int-0x80’ • But don’t forget to disable any breakpoints that might still be in effect when you enter the ‘do_exit’ procedure (to terminate your ‘hello’ application), by writing a zero value into the Debug Control Register DR7
In-class exercise #2 • After you have completed exercise #1, you can try this further exercise: use a different Debug Register (i.e.,, DR1, DR2, or DR3) to set an instruction-breakpoint at the entry to your ‘int-0x80’ service-routine • This will allow you to do single-stepping of your system-call handlers (e.g., ‘do_write’) • (A problem arises with ‘do_read’ though)