[lldb-dev] [PATCH] Remove unnecessary writing to dr6/dr7 on linux

John Wolfe jlw at xinuos.com
Mon Feb 24 08:40:33 PST 2014


On 2/24/2014 4:19 AM, Matthew Gardiner wrote:
> John Wolfe wrote:
>> Matthew,
>>
>> These code segments are not "unnecessary" writes of dr6/dr7. They are 
>> initialization of the debug status and control registers (dr6/dr7) 
>> and intended to be executed only once - when hardware breakpoints are 
>> first set or the status checked.  The Intel manuals states clearly 
>> that the DSR fields must be cleared as hardware breakpoints are 
>> serviced and nowhere does it state that dr6 or dr7 are guaranteed to 
>> be "initialized" at any time.
> I appreciate that if hardware breakpoints are being used in a debugger 
> then dr6/7 must be serviced. However, I have written an intel i386 
> linux debugger previously, which implements execution breakpoints 
> purely by inserting 0xCC (BREAK) instructions into the code. It was 
> possible for the debugger to be ignorant of dr6/7 - and require no 
> initialization of those registers.

While the debug registers can be used for instruction break, lldb is 
primarily using them for data watchpoints.  Because the 
SIGTRAP/TRAP_TRACE handling routine must also check for a possible 
hardware (data) breakpoint and the initial action of tracing 
(controlling) another process will result in a trace signal, the 
initialization of dr6 and dr7
to indicate that there no existing data watchpoints is done on the first 
access.

>>
>> The check for DSR/DCR initialization is obviously needed when the the 
>> first attempt to set a watchpoint is attempted.    It is also needed 
>> in IsWatchPointHit() to handle OS variations in signaling a hardware 
>> breakpoint.  On Linux, at least more recent versions, a 
>> SIGTRAP/TRAP_HWBKPT clearly identifies the hardware breakpoint. On 
>> others, such as FreeBSD which has no TRAP_HWBKPT, the break is 
>> signaled with a SIGTRAP/TRAP_TRACE.   That is why the 
>> POSIXThread::TraceNotify()  does a check to determine if this trace 
>> trap is actually for a watchpoint.
> Agreed. Given that lldb does use HW breaks, then yes, 
> IsWatchPointHit() should do an initial read of the status register, 
> then clear any flags. Given what I understand of page 707 of 
> http://download.intel.com/design/processor/manuals/253668.pdf, I'm not 
> sure about write of zero_bits... the document details a non-trivial 
> mask for dr6...

While it looks like a non-trivial mask, these are "reserved" bits and 
the processor will force/return these to be 1.

>
>>
>> So, these initialization of dr6 and dr7 are needed on the x86 
>> architectures and I do not think they are the source of your 
>> problems.   If you have just written zero to dr6, how can a read of 
>> dr6 return the value of 0x118?  If this is at the time of the initial 
>> SIGTRAP/TRAP_TRACE, then the register reads/writes would be to the 
>> process context area.  If the process execution had been started, 
>> then the reserved bits (always 1) in dr6 should have resulted in a 
>> dr6 value
>> with the 0xffff0ff0 bits set.
> On face of it, I think you're right. It's strange though, that in the 
> 32-bit linux debugger, the read back of 0x118 from dr6 seems to vanish 
> when those zero-bit writes are removed.

The key word here is "seems".   By removing the code  and "zero_bits" 
local variable used to write a zero value to d6/7 in IsWatchpointHit(), 
you have potentially changed the location of the "RegisterValue value" 
on the stack.  Being uninitialized, if the ReadRegister() fails to 
return the register contents, you will be seeing a garbage value.
Different locations, potentially different garbage values.

A test with "value" initialized with a known bad value such as 0x0bad 
could confirm or refute this possibility.

>
>>
>> I suspect that there is still something wrong in the the write and or 
>> the read of the debug registers.   The register read/write routines 
>> are not good about reporting any errors and many uses simply assume 
>> that the value returned is valid.    I encountered something similar 
>> when implementing watchpoints on FreeBSD.   In my case the read of 
>> dr7 failed and I was looking at bits in an local RegisterValue.
> Yes, again I agree. There could be another issue here.
>>
>> I found it helpful to add debugging/logging code in 
>> FreeBSD/ProcessMonitor.cpp to log the debug register write/read's 
>> under control of POSIX_LOG_PTRACE.    If you do something similar in 
>> the Linux version, then
>>
>>       log enable -f ptrace.log linux ptrace
>>
>> might shed some light on what and where things may be going wrong.
>>
>> Hope that helps.
> Thanks for this bit - yes ptrace logging is appreciated. I pursue that 
> route for now. Unfortunately ptrace logging is pretty flakey , 
> currently. This was what I see in simple "lldb hello" debug session:
>
> operation ptrace(PTRACE_TRACEME, 0, (nil), (nil), 0) called from file 
> (null) line -1220763056
> operation ptrace(PTRACE_SETOPTIONS, 7972, (nil), (nil), 88) called 
> from file (null) line -1220763056
> operation ptrace(PTRACE_PEEKDATA, 7972, (nil), 0x8048340, 0) called 
> from file (null) line -1220763056
> operation ptrace() failed; errno=5 (<unknown>)
> operation ptrace(PTRACE_POKEUSER, 7972, (nil), 0x114, 4294967295) 
> called from file (null) line -1220763056
> operation ptrace(PTRACE_POKEUSER, 7972, (nil), 0x118, 4294967295) 
> called from file (null) line -1220763056
> operation ptrace(PTRACE_PEEKUSER, 7972, (nil), 0x114, 0) called from 
> file (null) line -1220763056
> operation ptrace(PTRACE_PEEKUSER, 7972, (nil), 0x114, 0) called from 
> file (null) line -1220763056
> operation ptrace(PTRACE_PEEKUSER, 7972, (nil), 0x114, 0) called from 
> file (null) line -1220763056
> operation ptrace(PTRACE_PEEKUSER, 7972, (nil), 0x114, 0) called from 
> file (null) line -1220763056
> operation ptrace(PTRACE_PEEKUSER, 7972, (nil), 0x114, 0) called from 
> file (null) line -1220763056
> operation ptrace(PTRACE_PEEKUSER, 7972, (nil), 0x114, 0) called from 
> file (null) line -1220763056
> operation ptrace(PTRACE_PEEKUSER, 7972, (nil), 0x114, 0) called from 
> file (null) line -1220763056
> operation ptrace(PTRACE_PEEKUSER, 7972, (nil), 0x114, 0) called from 
> file (null) line -1220763056
> operation ptrace(PTRACE_POKEUSER, 7972, (nil), 0x114, 4294967295) 
> called from file (null) line -1220763056
> operation ptrace(PTRACE_PEEKUSER, 7972, (nil), 0x118, 0) called from 
> file (null) line -1220763056
>
> The file/line data is wrong and the all-above return value for the 
> peeks is absent...
>
> Matt
>
>
>
>
>
> Member of the CSR plc group of companies. CSR plc registered in 
> England and Wales, registered number 4187346, registered office 
> Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 
> 0WZ, United Kingdom
> More information can be found at www.csr.com. Keep up to date with CSR 
> on our technical blog, www.csr.com/blog, CSR people blog, 
> www.csr.com/people, YouTube, www.youtube.com/user/CSRplc, Facebook, 
> www.facebook.com/pages/CSR/191038434253534, or follow us on Twitter at 
> www.twitter.com/CSR_plc.
> New for 2014, you can now access the wide range of products powered by 
> aptX at www.aptx.com.





More information about the lldb-dev mailing list