Aug 6 2012

The selfless debugger

You know that feeling. You’re on a deadline. It’s 9:00 at night. You have a demo the next morning. Suddenly Xcode freaks out. Apps running half the time. Rebooting your phone. Rebooting your computer. Finally the phone decides to run your App for awhile.

That’s happening to me right now on a Thursday night (gotta take a break for my blood pressure to return to normal, so might as well write something). I figured I’d pass on a trick for working around a particular bit of tool uncooperativeness: I can’t look at any object data inside of some blocks.

With Xcode 4.4, both lldb and gdb are refusing to display instance variables inside of a couple of blocks (rdar:/12038473). Some work fine. Others don’t. Perhaps it’s just a deadline-sensitive implementation and everything will work after my time of trial. Breakpoints are working great and I can single-step, but the data display isn’t working. I can’t print out stuff in the console:

(gdb) print _iCloudAvailable
Cannot access memory at address 0x38

(gdb) call [self iCloudOn]
Unable to access variable "self"
$24 = <variable optimized away by compiler>

(gdb) print self
Unable to access variable "self"
$25 = <variable optimized away by compiler>

(Optimization is off.) Even worse, “hover over a variable” puts up a value, it just happens to be wrong:

Lying debugger

Notice at the very bottom – the print statement shows the proper value (1), while hover-and-display is showing a stale value. The left-hand debugger panel which shows the tree view of ivars shows the same stale data. It’s not just gdb – I started this debugging rollercoaster with lldb, and it was having the exact same problem.

The problem I’m having is “self” is not available. All the interesting stuff in this chunk of code keys off of self, such as method calls and instance variable access. I’m very interested in what some of these methods return and what ivar values are. If only self were there, life would be good. So let’s put it there.

I added an NSLog in the code which prints out self:

      NSLog (@"self is %p", self);

Which when run prints out something straightforward like

2012-08-02 20:58:37.595 ClassBuilder[199:707] self is 0x2b0800

If you’re not familiar with it, %p is the “print the value of a pointer in hex without dereferencing it” format specifier.

Now copy and paste that value, and just print it.

(gdb) print 0x2b0800
$8 = 2820096

That puts the value of self into one of the debugger session variables. Everything you print something, you get a new debugger variable you can use as a shorthand to refer to that value. self can now be referenced by $8. Why $8? I had printed out seven other values before I needed to reference self in this session. Plus it matches the screen shot. I’ve replaced other $values with $XX just because the order of numbers isn’t terribly interesting.

(gdb) call [$8 iCloudOn]
$XX = 1 '\001'

Dereferencing a raw address can be a pain:

(gdb) print $8->_iCloudAvailable
Attempt to extract a component of a value that is not a structure pointer.

You can cast it, though. “Hey debugger, treat this pointer as a ClassBuilderAppDelegate pointer first, and then dereference it.”:

(gdb) print ((ClassBuilderAppDelegate *) $8)->_iCloudAvailable
$XX = 1 '\001'

But that’s also a pain to type that cast over and over. So, just print it out again, casting it to the correct type:

(gdb) print ((ClassBuilderAppDelegate *) $8)
$9 = (ClassBuilderAppDelegate *) 0x2b0800

Now $9 hold a numeric value, but also has the type of my ClassBuilderAppDelegate pointer. $9 can new be dereferenced directly to peek at instance variables:

(gdb) print $9->_iCloudAvailable
$10 = 1 '\001'

Any place you’d use self in a debugger expression, you can use $9. These debugger variables aren’t scoped, and live the duration of the debugging session, so you can exit the function or block where you were doing your investigation and still refer to the object in another context. Well, so long as the object is still alive, of course. Because I’m debugging my app delegate I know the object will be alive for the entire program.

It’s not pretty, but can help you from having to go full-caveman and put logging after every line to see what’s going on in a tricky debugging situation.

(Dig Debugging? Our Advanced Mac and Advanced iOS Bootcamps take deep dives into Debugging.)

9 Comments

  1. livings124

    The Xcode 4.4.1 has a bug fix:

    “The LLDB debugger gets the wrong address for some variables. 12006552″

    Could that be related?

  2. Mark Dalrymple

    Eeeenteresting. I don’t have 4.4.1 yet, but will check it out.

  3. Daan

    I trained myself to distrust my own coding instead of saying ‘GBD *and* LLDB are broken’ so it took me a while to even google this. I want my IDE to work with me, not against me. If I want to NSLog, I don’t want to use an NSLinguisticTagAdjective. I don’t want processes to get ‘hung in the debugger’, so I have to reboot my device or even my mac. I don’t care if I’m a million nested blocks deep, I want to be able to print self and not get denied access to it.

    I really think that the Xcode team doesn’t use Xcode. How can you ship a version 4.4.1 with so many time consuming, annoying bugs that you can hardly get to developing? How can you demand that your users upgrade to at least 10.7.4 (I refuse to believe that 10.7.3 misses critical parts to make Xcode run) and give them so much crap?

  4. Mark Dalrymple

    Daan: Totally agree. I tend to blame myself before blaming the frameworks and tools. This time I don’t see how it could be anything but tool lossage.

    What’s really sad is a bunch of those time sinks have been in there forever. And things like textfromxcode.com wouldn’t be so funny if it wasn’t so true.

  5. Daan

    And don’t start me on crashes..I’m on an average of 5 crashes a day. And I’m not doing some obscure stuff it’s not really supposed to be able to do, just real basic iOS projects.

  6. Josh Lytle

    Did you ever figure out why this was happening? I’m running 4.5 and seem to get this sort of thing. It’s incredibly frustrating. All seemed to be working fine, but w/in the last week, it has started doing this.

    I’ve google’d and am still coming up short. Scheme is in debug mode (some suggestions was that build was in release mode)

    Thanks,
    Josh (BNR Class of 1/2012)

  7. Mark Dalrymple

    Not yet – I’ve been working with an Apple engineer off and on supplying information. I actually owe them some data.

    Please file a radar, and reference mine – 12038473 . The more information they can get, the merrier.

  8. J Smith

    I have been dealing with local variables disappearing for a week now. Along with all the hideous usability issues, like code completion selections intermittently timing out at 1/4 second.

    When stepping through code afflicted with unavailable local variables, the current line pointer jumps around _exactly_ like the debugger was stepping through optimized code, even if the compile options say -O0. I worry that the compiler is screwing up and optimizing the code even when explicitly being told not to.

Leave a Comment

Join the discussion. Do not worry, your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>