Chapters

Hide chapters

Advanced Apple Debugging & Reverse Engineering

Fourth Edition · iOS 16, macOS 13.3 · Swift 5.8, Python 3 · Xcode 14

Section I: Beginning LLDB Commands

Section 1: 10 chapters
Show chapters Hide chapters

Section IV: Custom LLDB Commands

Section 4: 8 chapters
Show chapters Hide chapters

28. Hello, DTrace
Written by Walter Tyree

Heads up... You’re accessing parts of this content for free, with some sections shown as zrkefsric text.

Heads up... You’re accessing parts of this content for free, with some sections shown as cctupdgiv text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Omagerd! It’s DTrace time! DTrace is one of the coolest tools you’ve (likely?) never heard about. With DTrace, you can hook into a function or a group of functions using what’s called a probe. From there, you can perform custom actions to query information out of a specific process, or even system wide on your computer (and monitor multiple users)!

If you’ve ever used the Instruments application it might surprise you that a lot of the power underneath it is powered by DTrace.

In this chapter, you’ll explore a very small section of what DTrace is capable of doing by tracing Objective-C code in already compiled applications. Using DTrace to observe iOS frameworks (like UIKit) can give you an incredible insight into how the authors designed their code.

The Bad News

Let’s get the bad news out of the way first, because after that it’s all exciting and cool things from there. There are several things you need to know about DTrace:

  • You need to disable Rootless for DTrace to work. Do you remember decades ago in Chapter 1 where I mentioned you need to disable Rootless for certain functionality to work? In addition to letting LLDB attach to any process on your macOS, DTrace will not correctly function if System Integrity Protection is enabled. If you skipped Chapter 1, go back and disable Rootless now. Otherwise, you’ll need to sit on the sidelines for the remainder of this section.
  • DTrace is not implemented for iOS devices. Although the Instruments application uses DTrace under the hood for a fair amount of things, it can not run custom DTrace scripts on your iOS device. This means you can only run a limited set of predefined functionality on your iOS device. However, you can still run whatever DTrace scripts you want on the Simulator (or any other application on your macOS) regardless if you’re the owner of the code or not.
  • DTrace has a steep learning curve. DTrace expects you know what you’re doing and what you’re querying. The documentation assumes you know the underlying terminology for the DTrace components. You’ll learn about the fundamental concepts in this chapter but there is quite literally a whole book on this topic which explores the many aspects of DTrace that are out of the scope of what I’ll teach you.

In fact, it’s worth noting right up front, if DTrace interests you, get visit Brendan Gregg’s site and maybe read his book. It focuses on a wider range of topics that might not pertain to your Apple debugging/reverse engineering strategies, but it does teach you how to use DTrace.

Now that I’ve got that off my chest with the bad stuff, it’s time to have some fun.

Jumping Right In

I am not going to start you off with boring terminology. Ain’t nobody got time for that. Instead, you’ll first get your hands dirty, then figure out what you’re doing later.

Heads up... You’re accessing parts of this content for free, with some sections shown as pzgorgbiw text.

Heads up... You’re accessing parts of this content for free, with some sections shown as pqhucxnuz text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
sudo dtrace -n 'objc$target:UIViewController::entry' -p `pgrep SpringBoard`
dtrace: description 'objc$target:UIViewController::entry' matched 718 probes
sudo dtrace -n 'objc$target:UIViewController:-viewWillAppear?:entry { ustack(); }' -p `pgrep SpringBoard`

Heads up... You’re accessing parts of this content for free, with some sections shown as pmcalklot text.

Heads up... You’re accessing parts of this content for free, with some sections shown as lgqozswer text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
dtrace: description 'objc$target:UIViewController:-viewWillAppear?:entry ' matched 1 probe

Heads up... You’re accessing parts of this content for free, with some sections shown as wmbuxvwav text.

Heads up... You’re accessing parts of this content for free, with some sections shown as dslobdcab text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
objc_msgSend(self_or_class, SEL, ...);
printf("\nUIViewcontroller is: 0x%p\n", arg0);
sudo dtrace -n 'objc$target:UIViewController:-viewWillAppear?:entry { printf("\nUIViewcontroller is: 0x%p\n", arg0); ustack(); }' -p `pgrep SpringBoard`

Heads up... You’re accessing parts of this content for free, with some sections shown as fksyssmuh text.

Heads up... You’re accessing parts of this content for free, with some sections shown as zjzewqfuj text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
sudo dtrace -n 'objc$target:::entry { @[probemod] = count() }' -p `pgrep SpringBoard`

DTrace Terminology

Now that you’ve gotten your hands dirty on some quick DTrace one-liners, it’s time to learn about the terminology so you actually know what’s going on in these scripts.

dtrace -n 'objc$target:NSObject:-description:entry / arg0 = 0 / { @[probemod] = count(): }' -p `pgrep SpringBoard`

Heads up... You’re accessing parts of this content for free, with some sections shown as zfxyqxdif text.

Heads up... You’re accessing parts of this content for free, with some sections shown as wtdytlrub text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Heads up... You’re accessing parts of this content for free, with some sections shown as xsjilngex text.

Heads up... You’re accessing parts of this content for free, with some sections shown as kcmulfryx text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
provider:module:function:name / predicate / { action }
dtrace -n 'objc$target:NSView:-init*:entry' -p `pgrep -x Xcode`
dtrace: description ’objc$target:NSObject:-init:entry’ matched 1 probe
CPU     ID                    FUNCTION:NAME
  2 512130                      -init:entry
  2 512130                      -init:entry
  2 512130                      -init:entry
  2 512130                      -init:entry

Heads up... You’re accessing parts of this content for free, with some sections shown as wwridfrif text.

Heads up... You’re accessing parts of this content for free, with some sections shown as shraflxad text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Learning While Listing Probes

Included in the DTrace command options is a nice little option, -l, which will list all the probes you’ve matched against in your probe description. When you have the -l option, DTrace will only list the probes and not execute any actions, regardless of whether you supply them or not.

sudo dtrace -ln ’objc$target:::’ -p `pgrep -x Finder`
sudo dtrace -ln 'objc$target:NSView::' -p `pgrep -x Finder`
sudo dtrace -ln 'objc$target:NSView::' -p `pgrep -x Finder` | wc -l

Heads up... You’re accessing parts of this content for free, with some sections shown as fqjizpcor text.

Heads up... You’re accessing parts of this content for free, with some sections shown as xxzalnges text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
sudo dtrace -ln 'objc$target:NSView:-initWithFrame?:' -p `pgrep -x Finder`
sudo dtrace -ln 'objc$target:NSView:-initWithFrame?:entry' -p `pgrep -x Finder`

A Script That Makes DTrace Scripts

When working with DTrace, not only do you get to deal with an exceptionally steep learning curve, you also get to deal with some cryptic errors if you get a build time or runtime DTrace error (yeah, it’s on the same level of cryptic as some of those Swift compiler errors).

Exploring DTrace Through tobjectivec.py

Time to take a whirlwind tour of this script while exploring DTrace on Objective-C code.

Heads up... You’re accessing parts of this content for free, with some sections shown as lfxabnrin text.

Heads up... You’re accessing parts of this content for free, with some sections shown as gznavjcew text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
(lldb) tobjectivec -g
#!/usr/sbin/dtrace -s  /* 1 */

#pragma D option quiet  /* 2 */

dtrace:::BEGIN { printf("Starting... use Ctrl + c to stop\n"); } /* 3 */
dtrace:::END   { printf("Ending...\n"  ); }                      /* 4 */

/* Script content below */

objc$target:::entry /* 5 */
{
    printf("0x%016p %c[%s %s]\n", arg0, probefunc[0], probemod, (string)&probefunc[1]); /* 6 */
}

Heads up... You’re accessing parts of this content for free, with some sections shown as gfhiwxnuh text.

Heads up... You’re accessing parts of this content for free, with some sections shown as nhgodlbad text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
(lldb) tobjectivec
Copied script to clipboard... paste in Terminal
sudo /tmp/lldb_dtrace_profile_objc.d  -p 95129  2>/dev/null
$ sudo /tmp/lldb_dtrace_profile_objc.d  -p 95129  2>/dev/null
Password:
Starting... use Ctrl + c to stop

Heads up... You’re accessing parts of this content for free, with some sections shown as hsteqrzow text.

Heads up... You’re accessing parts of this content for free, with some sections shown as bjlurgdyp text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

(lldb) continue
(lldb) tobjectivec -m *StatusBar* -g
objc$target:*StatusBar*::entry
{
  printf("0x%016p %c[%s %s]\n",
    arg0, probefunc[0], probemod, (string)&probefunc[1]);
}
(lldb) tobjectivec -m *StatusBar*

Heads up... You’re accessing parts of this content for free, with some sections shown as sndinwtos text.

Heads up... You’re accessing parts of this content for free, with some sections shown as dpqofqvyf text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
 sudo /tmp/lldb_dtrace_profile_objc.d  -p 2646  2>/dev/null

Tracing Debugging Commands

I often find it insightful to know what’s happening behind the scenes when I’m executing simple debugging commands and the code that’s going on behind them to make it work for me.

(lldb) tobjectivec
(lldb) po @"hi this is a long string to avoid tagged pointers"

Heads up... You’re accessing parts of this content for free, with some sections shown as zrgoqnfir text.

Heads up... You’re accessing parts of this content for free, with some sections shown as rppaxrfen text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
(lldb) expression -l swift -O -- class b { }; let a = b()
0x000000010336eb08 +[_TtCs12_SwiftObject initialize]
0x000000010336eb08 +[_TtCs12_SwiftObject class]
0x000000010589c9e8 +[_TtCs12_SwiftObject initialize]
0x000000010589c9e8 -[_TtCs12_SwiftObject self]

Tracing an Object

You can use DTrace to trace method calls for a particular reference.

(lldb) po UIApp
<UIApplication: 0x7fa774600f90>

Heads up... You’re accessing parts of this content for free, with some sections shown as jmvazttil text.

Heads up... You’re accessing parts of this content for free, with some sections shown as kxqamltaf text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
(lldb) tobjectivec -g -p 'arg0 == 0x7fa774600f90'
/* Script content below */

objc$target:::entry / arg0 == 0x7fa774600f90 /
{
    printf("0x%016p %c[%s %s]\n", arg0, probefunc[0], probemod, (string)&probefunc[1]);
}
(lldb) tobjectivec -p 'arg0 == 0x7fa774600f90'
(lldb) tobjectivec -g -p 'arg0 == 0x7fa774600f90' -a '@[probefunc] = count()'
/* Script content below */

objc$target:::entry / arg0 == 0x7fa774600f90 /
{
    @[probefunc] = count()
}

Heads up... You’re accessing parts of this content for free, with some sections shown as zqbywswyl text.

Heads up... You’re accessing parts of this content for free, with some sections shown as kwvivspub text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Other DTrace Ideas

Here’s some other ideas for you to try out on your own time:

(lldb) tobjectivec -f ?init*
(lldb) tobjectivec -m NSXPC*
(lldb) tobjectivec -m UIControl -f -touchesBegan?withEvent?

Key Points

  • Using DTrace requires disabling System Integrity Protection and sudo.
  • DTrace can run as a one line command or with a script for more complex procedures.
  • Use the -l switch when testing out DTrace commands to keep from crashing your system.
  • When working with DTrace, always think about filtering results so you aren’t overwhelmed with output.
  • DTrace doesn’t work on an iOS device, but does work on the Simulator.

Where to Go From Here?

This is only the tip of the DTrace iceberg. There’s a lot more that is possible with DTrace.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2025 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as krfyrsgyc text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now