3

Sometimes (meaning quite often) when I try to debug crashes from an iPad App, LLDB decides not to be too helpful and printing of variables (stack or class members) fails to work.

If I right-click (or CTRL+click) a variable in the debug window on the left and then "Print description" I get error messages like the following:

Printing description of error:
(NSURLError *) error = <register sp is not available>

or

Printing description of error:
(NSURLError *) error = <register ebp is not available>

If I try to use the debug console myself I get something like this:

(lldb) po error
(NSError *) $3 = 0x2124fc10 [no Objective-C description available]

Afterwards the right click seems to start working and yields the following:

Printing description of error:
(NSURLError *) error = 0x2124fc10

But all I get is the memory address, it fails to call description on it it seems. If I try to send the description message this happens:

(lldb) po [error description]
error: Execution was interrupted.
The process has been returned to the state before execution.

So this is not helpful either. What can be done to make the debugger usable again? I desperately have to catch a crash but everytime I can provoke it the above happens and I have no clue how to get to the error's core.

I googled for "register not available lldb" but found nothing, just some pastebin logs, no answers.

FYI: Using Xcode 4.5.2, iOS SDK 6.0, compiling "Debug"-Profile, no optimizations turned on, LLDB Debugger, iOS deployment target 5.0, happens on debugging in Simulator or on device (iPad 1 and 3, iPhone 4S, iPhone 3GS), debugged App is using GCD quite extensively.

Dunkelstern
  • 1,624
  • 12
  • 18

1 Answers1

9

You're hitting a bug in the lldb in Xcode 4.5.x with its volatile register list on i386.

Registers fall in to two classes: volatile and non-volatile (or callee-saved). When a function calls another function, all of the "volatile" registers may have their contents overwritten. All non-volatile/callee saved registers will be preserved by the called function (callee function) before they are reused, and their previous values restored before returning.

Sometimes the debug info will say that a variable is stored in a volatile register. If that function is in the middle of your stack and you want to examine that variable, the debugger cannot reconstruct that register's value -- it is lost. gdb would simply copy the volatile register's value up to the middle of the stack and print the variable with a (potentially) bogus value, leading developers to be very confused.

lldb knows the difference between volatile and non-volatile registers and won't let volatile registers be reused in the middle of a stack like that -- they'll say that the register value is unavailable instead.

Unfortunately in this case, you're seeing lldb claim it cannot reconstruct variables that are available. They are mis-categorized as volatile when they should be non-volatile. Without doing a lot of assembly-language inspection, this is not going to be easy for you to work around. The only solution here is to resume execution until you're back in that function again (i.e. it is now frame 0) and then all of the register values will be correctly marked as available.

This is fixed in Xcode 5, released September 2013.

Jason Molenda
  • 14,835
  • 1
  • 59
  • 61
  • So this should be fixed in 4.6 DP3? That'd be wonderful then I can use that to fix this nasty bug. – Dunkelstern Dec 05 '12 at 10:13
  • 2
    @ Dunkelstern: **No, it is not fixed.** I just installed Xcode 4.6, and still have exactly same problems. They only implemented now the ability to inspect NSDictionary and NSArray objects in debugger, which is very nice, but still I have tons of times when I see: , or stuff like this. – Beny Boariu Jan 29 '13 at 16:01
  • 1
    First, "" is commonly means that ... the variable is not available. This happens a lot when you're debugging optimized code -- if possible, I strongly recommend turning off optimization for your debug configuration. Second, there are only certain registers that are "preserved" -- saved -- when you call functions. If a variable is in a volatile aka non-preserved register, its contents cannot be reconstructed by the debugger. volatile regs on i386 are eax, edx, ecx, and the floating point/vector regs. lldb will show you ebx, ebp, esi, edi, and esp. – Jason Molenda Jan 29 '13 at 22:39
  • @Jason Molenda I see this all the time - and I have all optimizations off for Debug. The fact is that this costs me money every day - literal money out of my pocket - because it makes debugging that much harder and I spend that much more time waving the magic chicken to appease Xcode. I'd rather see the rest of the debugger work completely before features like array or dictionary introspection are added (though those are nice). Btw, what I see is that the variables and values are missing at about three stack frames above where I am. – Mike Fullerton May 31 '13 at 01:36
  • 2
    Mike, it's not clear exactly what you're reporting here. If lldb is saying that a given register is unavailable, on armv7 r0-r3, r9, and r12 are not available unless you're looking at the currently executing function. This isn't a *limitation* of lldb -- they really aren't available. gdb would blithely report whatever the contents of r9 were in frame 0 as the contents up on frame 4 -- but they likely were not the same and you'd be getting bad data. If you're seeing lldb say a variable is unavail because of optimization, you're building your program (or at least that comp unit) with optim. – Jason Molenda May 31 '13 at 21:24