Thursday, April 16, 2009

Quickies for gdb

Quickies for gdb: "Debugging

* gdb'ing specific architectures [permalink]
With a fat binary (32/64bit), gdb picks the 64 bit version. If you're trying to debug a 32-bit unit test on the command-line though, the 64-bitness of /Developer/Tools/otest gets in the way:

% gdb /Developer/Tools/otest
2008-10-31 19:29:50.834 otest[711:813] Error loading
/blah/blah/blah/build/Debug/Tests.octest/Contents/MacOS/Tests:
dlopen(/blah/blah/blah/build/Debug/Tests.octest/Contents/MacOS/Tests,
265): no suitable image found. Did find:
/blah/blah/blah/build/Debug/Tests.octest/Contents/MacOS/Tests:
mach-o, but wrong architecture
2008-10-31 19:29:50.887 otest[711:813] The test bundle at
build/Debug/Tests.octest could not be loaded because it is built for a
different architecture than the currently-running test rig (which is
running as unknown).
2008-10-31 19:29:50.904 otest[714:203] *** NSTask: Task create for
path '/blah/blah/blah/build/Debug/Tests.octest/Contents/MacOS/Tests'
failed: 8, 'Exec format error'. Terminating temporary process.

You can supply a -arch flag to pick what you want:

% gdb -arch i386 /Developer/Tools/otest

And then debug your 32-bit unit test.

General

* Break on szone_error not working [permalink]
Sometimes when you have memory corruption issues, the malloc library happily informs you:

Borkdoku(11062,0xcec0600) malloc: *** error for object 0xd109010:
incorrect checksum for freed object - object was probably modified
after being freed, break at szone_error to debug

Which is fine and dandy, but it lies. I've never gotten szone_error to actually do anything. Try breaking on malloc_printf instead.

* Breaking on exceptions [permalink]
It can be annoying tracking down the cause of thrown exceptions in Cocoa. you get a notice like 2007-05-05 17:18:00.702 QueenStitcher[2804:117] *** Assertion failure in -[NSColorWell setColor:], NSColorWell.m:497, u suk l0s3r, and then the runloop happily runs again, giving you no clue where the problem is. I tell gdb to always break on Cocoa exceptions:

fb -[NSException raise]
fb objc_exception_throw()

For maximal enjoyment, add these two lines to your ~/.gdbinit file, so they'll get set no matter how you invoke gdb (no need to add these to every single project, for instance).

I've been told VoiceOver uses exceptions heavily, so if you're doing VoiceOver development, these breaks may cause you pain.

* Displaying four-character ints [permalink]
Old-school Mac programming (and Quicktime, and other places) use four-character ints, things like 'bork'. You can have gdb print them out if you need to look at one or two of them:

(gdb) print/T 1936746868
$4 = 'spit'

(thanks to Daniel Jalkut for the print/T trick)

* Finding 'self' on Intel [permalink]
(gdb) po *(int*)($ebp+8)

* Ignoring signals [permalink]
(gdb) handle SIGTRAP nostop

The signal still goes to your program. Another handy option is 'ignore' to prevent it coming to the program. Also there is 'print' to print a message go on.

* Printing method arguments [permalink]
If you've hit a breakpoint on a method that doesn't have debug symbols, you can sometimes get useful information by looking in the processor registers. Arguments start in $r3 and go up from there. For Objective-C method sends, $r3 has 'self', and $r4 has the name of the method. Subsequent arguments are in $5 and so on.

(gdb) print (char*) $r4
$5 = 0x90874160 'drawRect:'

(gdb) po $r5
<BWStitchView: 0x1a6670>

* Printing object retain count in gdb [permalink]
In the gdb console:
(gdb) print (int)[theObject retainCount]

If you're expecting to have an excessively high number of retains, you can use (unsigned int) in the cast. I find (int) a skootch faster to type.

* Printing wide character strings [permalink]
gdb won't by default let you print wide character strings. Here is a little bit of gdb code that'll let you print them. In case that page moves, here is the relevant stuff. Paste this into your .gdbinit and then you can use wchar_print:

define wchar_print
echo '

set $i = 0
while (1 == 1)
set $c = (char)(($arg0)[$i++])
if ($c == '\0')
loop_break
end
printf '%c', $c
end

echo '

end

document wchar_print
wchar_print <wstr>
Print ASCII part of <wstr>, which is a wide character string of type wchar_t*.
end

* Seeing functions and selectors [permalink]
info selectors will show you all of the selectors in the application's symbol table. info functions will show you all of the functions. You can supply regular expressions to limit the output.

* Using libgmalloc in gdb [permalink]
libgmalloc puts guard pages at the end of malloc'd blocks of memory, letting you catch buffer overruns. (This will hugely inflate your program's working set, and may lead to swapping) To turn on libgmalloc in gdb, do this:

(gdb) set env DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib

* calling objective-C methods in gdb [permalink]
To call an Objective-C method in the gdb console, you have to cast the return type (since gdb doesn't really know what the return value is):

(gdb) call (void)[textField setStringValue: @'Bork']

Hacks

* Loading a bundle into a running program [permalink]
Sometimes it's handy to load a bundle into a running app to do some poseAsClass: for doing some debugging or reverse engineering. Make a Cocoa bundle which has the code you want to load, then do:

(gdb) call (id) objc_getClass('NSBundle')
$1 = (struct objc_object *) 0xa0a051d8

gdb) call (id)[$1 bundleWithPath:@'/blah/blah/PoseAsClassBundle.bundle']
$2 = (struct objc_object *) 0x51467e0

(gdb) call (BOOL)[$2 load]
Reading symbols for shared libraries . done"

No comments: