Facilities for x86 debugging Introduction to Pentium features their debugging of software

advertisement
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
Least significant word
31
LEN
3
16
R/W
3
LEN
2
R/W
2
LEN
1
R/W
1
Most significant word
LEN
0
R/W
0
L
0
What kinds of breakpoints?
LEN
LEN
00 = one byte
01 = two bytes
10 = undefined
11 = four bytes
R/W
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
CR4
3
other feature bits
D
E
0
Debug Status Register (DR6)
15
B B
T S
0
B
D
0
1
1
1 1
1
1
1
1
B
3
B
2
B
1
Least significant word
31
16
unused ( all bits here are set to 1 )
Most significant word
B
0
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)
Download