Objective-C: Printing Class Name from Dtrace

When analyzing an Objective-C application with Dtrace, one big challenge is how to introspect any objective-c objects that are passed as parameters into the various trace points.

While you can use the Objective-C provider (documented on the dtrace man page) to trace particular methods of specific classes, it doesn’t really help for actually introspecting an instance or class.

By “introspecting”, I mean “printing out the damned class name”, for example.

Full monty on the click through.

Useful example: internally to the appkit, there is a function called forwardMethod() that is used by the responder chain to forward events from one responder to another. It shows up in lots of backtraces and, sometimes, it is really nice to know exactly what/when/why/how/who is being diddled by said function.

Like just about everything else that deals with messaging some object, forwardMethod() takes an object as the first parameter and a selector as the second parameter (poke at it w/gdb for a bit to see what I mean). Given what it logs w/the script below, there is very likely a third argument that is event itself. Ignored for this example’s purpose.

D, the programming language used to write dtrace probes, is a very C like language. It does pointers. And pointer de-referencing. Relatively straightforward.


A dtrace probe runs in the kernel. Thus, it doesn’t have direct access to the inferior’s memory. While printing the class name in C would is easy — printf("%s\n", obj->isa->name); — doing the same in D requires that the various bits o’ memory be copied over from the inferior into the kernel.

And, when copied, the memory shows up in a buffer — a buffer that contains a pointer and, thus, requires a bit o’ double de-referencing magic. Old school Mac programmers should feel right at home about now.

Anyway, what follows is a probe that will print the name of the class of the object to which forwardMethod() is about to, well, forward a method and the name of the method that is about to be forwarded (Huge thanks to Daniel Delwood — who commented on this entry with something very very useful — for boatloads of help on this):

#pragma D option quiet
    isaptr = *(uint32_t*)copyin(arg0, 4);
    classnameptr = *(uint32_t*)copyin(isaptr+8, 4);
    classname = copyinstr(classnameptr);
    printf("[%s %s]\n", classname, copyinstr(arg1));

This obviously assumes a 32 bit process. Even with 64 bit types, this won’t work on a 64 bit process because the innards of Objective-C are opaque (to eliminate binary compatibility issues in the future, not for obfuscation reasons in the present).

You can run this against TextEdit easily enough. Yes, the environment variable is still necessary. Note that this actually launches the inferior (TextEdit) and, thus, traces it from the beginning.

sudo dtrace -s forwardMethod.d -c /Applications/TextEdit.app/Contents/MacOS/TextEdit

The output will look something like:

[NSKVONotifying_NSTextView mouseMoved:]
[NSClipView mouseMoved:]
[NSKVONotifying_ScalingScrollView mouseMoved:]
[NSView mouseMoved:]
[NSWindow mouseMoved:]

While useful to answer the particular question asked, hopefully this recipe will provide a useful foundation to provide other types of analysis.

5 Responses to “Objective-C: Printing Class Name from Dtrace”

  1. The Omni Mouth » More objc method tracing says:

    […] Objective-C: Printing Class Name from Dtrace […]

  2. David Mandelin’s blog » Blog Archive » DTrace C++ Mysteries Solved says:

    […] have been added as part of Objective C support, Googled “dtrace objective c”, found a blog post, followed a link from there to the Apple dtrace man page, saw the “-xmangled” option, […]

  3. Plastkort says:

    Interesting information. Does the same principle apply to Java?

  4. Alex says:

    Does the same principle apply to Java?

  5. Nicolas Seriot says:

    A coworker and I found what seems to be an undocumented behaviour of the -F option.

    Consider this minimal DTrace script:

    pid$target::*NSDate*:entry {}
    pid$target::*NSDate*:return {}

    With -F, DTrace pretty prints the Objective-C messages, including the class/instance method sign.

    $ sudo dtrace -s objc_calls.d -F -c /Applications/TextEdit.app/Contents/MacOS/TextEdit
    1 -> +[NSDatePicker initialize]
    1 -> +[NSDatePickerCell initialize]
    1 <- +[NSDatePickerCell initialize]
    1 +[NSDate distantFuture]
    0 <- +[NSDate distantFuture]

    By the way, TextEdit initializing NSDatePicker on startup seems kind of weird.

Leave a Reply

Line and paragraph breaks automatic.
XHTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>