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

3. Attaching With LLDB
Written by Walter Tyree

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

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

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

Unlock now

Now that you’ve learned about the two most essential commands, help and apropos, it’s time to investigate all the ways LLDB can attach itself to a process.

As used in the previous chapters, the phrase LLDB “attaching” is actually a bit misleading. A program named debugserver — found in Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/ for macOS — is responsible for “attaching” to a target process. It’s LLDB’s job to bring up and coordinate with debugserver.

Creating a Debuggee Program

To understand how LLDB attaches to a program, you need to have a simple program that you control — just in case you didn’t disable SIP in the first chapter.

Open Terminal and navigate to the global tmp directory:

$ cd /tmp

The contents of this directory are erased when your computer reboots. It’s a great spot for throwaway programs or making content you don’t need to stick around.

Use your favorite text editor to create a file named hello_world.swift. For simplicity, the steps are described using the nano editor.

$ nano hello_world.swift

Add the following Swift code:

import Foundation

print("hello, world!")
CFRunLoopRun()

To save the file in nano, use Control-O. To exit, use Control-X.

Exit the text editor, and compile the program:

$ swiftc hello_world.swift

Upon success, you’ll have an executable named hello_world that prints "hello, world!" and waits forever in a loop thanks to the CFRunLoopRun() call.

Test the hello_world program by typing:

$ ./hello_world

Your terminal window should display “hello, world!” and then nothing else. Use Control-C to terminate this program when the euphoria has worn off. You’ll use this program in a second to discover the different ways LLDB can attach to a process.

Attaching to an Existing Process

Now, you’ll see how to attach LLDB to an existing process. First, you’ll need to create a process to debug, and then you’ll attach to it.

$ ./hello_world &
$ lldb -n hello_world
(lldb) q
$ pgrep -x hello_world
$ lldb -p 57086

Attaching to a Future Process

The previous command only addresses a running process. If the process you want to debug isn’t running, or is already attached to a debugger, the previous commands will fail. How can you catch a process that’s about to be launched if you don’t know the PID yet without directly launching the process?

pkill hello_world
$ lldb -n hello_world -w
$ /tmp/hello_world

Launching a Process Using LLDB

Another way to attach to a process is to specify the path to the executable and then launch the process from within LLDB:

$ lldb -f /tmp/hello_world
(lldb) process launch

Options While Launching

The process launch command comes with a suite of options worth further exploration. If you’re curious and want to see the full list of available options for process launch, simply type help process launch in an LLDB session.

$ lldb -f /bin/ls
(lldb) target create "/bin/ls"
Current executable set to '/bin/ls' (arm64e).
(lldb) process launch
Process 7681 launched: '/bin/ls' (arm64e)
... # Omitted directory listing output
Process 7681 exited with status = 0 (0x00000000)
(lldb) process launch -w /Applications
$ cd /Applications
$ ls
(lldb) process launch -- /Applications
$ ls /Applications
(lldb) process launch -- ~/Desktop
Process 57442 launched: '/bin/ls' (arm64e)
ls: ~/Desktop: No such file or directory
Process 57442 exited with status = 1 (0x00000001)
(lldb) process launch -X true -- ~/Desktop
(lldb) help run
...
Command Options Usage:
  run [<run-args>]


'run' is an abbreviation for 'process launch -X true --'
(lldb) run ~/Desktop

Environment Variables

For Terminal programs, environment variables can be equally as important as the program’s arguments. If you were to consult the man 1 ls, you’d see that the ls command can display output in color so long as the color environment variable, CLICOLOR, is enabled. You also have the “color palette” environment variable LSCOLORS to tell how to display certain file types.

(lldb) env
(lldb) process launch -E LSCOLORS=Db -E CLICOLOR=1  -- /usr/share

(lldb) process launch -E LSCOLORS=Af -E CLICOLOR=1  -- /usr/share
LSCOLORS=Af CLICOLOR=1 ls /Applications/

stdin, stderr and stout

Using the launch options, you can control where to send the output of a program.

(lldb) process launch -o /tmp/ls_output.txt -- /Applications
Process 15194 launched: '/bin/ls' (arm64e)
Process 15194 exited with status = 0 (0x00000000)
$ cat /tmp/ls_output.txt
(lldb) target delete
(lldb) target create /usr/bin/wc
$ echo "hello world" > /tmp/wc_input.txt
(lldb) process launch -i /tmp/wc_input.txt
Process 24511 launched: '/usr/bin/wc' (arm64e)
       1       2      12
Process 24511 exited with status = 0 (0x00000000)
$ wc < /tmp/wc_input.txt
(lldb) run
(lldb) process launch -n
Process 28849 launched: '/usr/bin/wc' (arm64e)
Process 28849 exited with status = 0 (0x00000000)

The curses Interface

If you’ve spent a lot of time debugging in Xcode, you might’ve become comfortable seeing the stack trace, the variables window and other data as you work with the debugger. In Terminal, you can use a curses-style GUI for a similar experience. At an LLDB prompt, type:

(lldb) gui

Key Points

  • Launch LLDB and attach to processes using -n, -p or -w switches.
  • Use the -f switch to launch LLDB and then explicitly launch the process from within LLDB.
  • Use target create and target delete to load and detach an executable to a running LLDB session.
  • Use process launch to launch a process from within LLDB.
  • Use -E flags to set environment variables for a target process.
  • Use -i and -o to control where a target process should get its input and output.
  • The run command is an alias for process launch --.
  • The gui command gives an Xcode-esque interface for when you’re using Terminal for your lldb session.

Where to Go From Here?

You can find more interesting options to play with via the help command, but that’s for you to explore on your own.

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.
© 2024 Kodeco Inc.

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

Unlock now