Title: Facilities for x86 debugging
1Facilities for x86 debugging
- Introduction to Pentium features that can assist
programmers in their debugging of software
2TF-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
3Using 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 - Heres how to do it
- objdump d hello gt hello.u
- (The -d option stands for disassembly)
4A slight flaw
- We cannot single-step the execution of an
int-0x80 instruction (Linuxs system-calls) - Our exception-handlers iretd instruction will
restore the TF-bit to EFLAGS, but the single-step
trap doesnt take effect until after the
immediately following instruction - This means we skip seeing a display of the
registers immediately after int-0x80
5Fixing 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)
6Breakpoint Address Registers
DR0
DR1
DR2
DR3
7Special 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)
8Debug 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
9What 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)
10Control 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
11Debug Status Register (DR6)
15
0
B D
0
1
1
1
1
1
1
1
B 3
B 2
B 1
B S
B T
1
B 0
Least significant word
31
16
unused ( all bits here are set to 1 )
Most significant word
12Where 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
CSEIP 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 EIP2
13How to set this breakpoint
- isrDBG push ebp
- mov ebp, esp
- pushad
- put breakpoint-address in DR0
- mov eax, 4ebp
- add eax, 2
- mov dr0, eax
14Setting a breakpoint (continued)
- enable local breakpoint for DR0
- mov eax, DR7
- bts eax, 0 set LE0
- mov DR7, eax
-
- popad
- pop ebp
- iretd
15Detecting 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 12ebp, 16 set the RF-bit
- or disable breakpoint0 in register DR7
- notBP0
16In-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 dont 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
17In-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)