Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

LLDB: Examining a Program: Part III

DZone's Guide to

LLDB: Examining a Program: Part III

By the end of Part III, you'll have an application running on iOS and we're debugging it from our local mac!

· Mobile Zone
Free Resource

Discover how to focus on operators for Reactive Programming and how they are essential to react to data in your application.  Brought to you in partnership with Wakanda

We have everything set at this point to start remote debugging. We have our remote debugger configured and signed, we've moved over and signed our executable as well, and it runs. Let's spin it up and take a look.

Starting a Program with Debugserver

So, we need to do a couple of things here. First, you need to configure gandalf to multiplex the debug port on your phone to a port on your localsystem. To do this, your gandalf mapping file should contain something like this:

{"udid":"53b02cd8f5e3826f76dc0c70467fbf0b8b9684ae",
  "name":"i11", "forwarding": [{"local_port":2002, "device_port":22},
                               {"local_port":3000, "device_port":1122},
                               {"local_port":23946,"device_port":23946}]
                               }

Note the last line, where we map the port 23946 on the phone to 23946 on your local system. This is vital - this is the port debugserver will use to share debugging information with your local installation of lldb.

If this isn't in your mapping file, include it (the last line specifically, remember, the udid of your device will differ, and you need to make sure that these ports aren't being used for anything else or by another multiplexed phone on your computer).

Restart gandalf, you should be able to log back into your phone via SSH.

Now, on your phone, execute this command:

$ debugserver *:23946 ./function
debugserver-@(#)PROGRAM:debugserver  PROJECT:debugserver-340.3.124 for arm64.
Listening to port 23946 for a connection from *...

Good! It's hanging out, waiting for a remote debugger to attach. The *:23946 clause tells debugserver to accept connections from anywhere over port 23946. You can make this more restrictive, but as I use usbmux on a phone with no internet connection, this is fine. If you're attaching over TCP/IP (which you can do), I'd include the address of the host system, so this clause would look something like <my mac workstation address>:23946.

Now, let's attach.

Attaching with LLDB

Attaching is pretty straightforward:

$ lldb
(lldb) platform select remote-ios 
  Platform: remote-ios
 Connected: no
  SDK Path: "/Users/cclamb/Library/Developer/Xcode/iOS DeviceSupport/9.3.3 (13G34)"
  SDK Roots: [ 0] "/Users/cclamb/Library/Developer/Xcode/iOS DeviceSupport/9.3.3 (13G34)"
(lldb) process connect connect://localhost:23946
Process 1543 stopped
* thread #1: tid = 0xae1f0, 0x1fe29000 dyld`_dyld_start, stop reason = signal SIGSTOP
    frame #0: 0x1fe29000 dyld`_dyld_start
dyld`_dyld_start:
->  0x1fe29000 <+0>:  mov    r8, sp
    0x1fe29004 <+4>:  sub    sp, sp, #16
    0x1fe29008 <+8>:  bic    sp, sp, #15
    0x1fe2900c <+12>: ldr    r3, [pc, #0x70]           ; <+132>
(lldb)

Sweet!

Your data after selecting the remote-ios platform may very well differ; this is just fine. This is configured when you attach a device with a particular iOS revision level to your mac, and I haven't attached any devices at iOS 10 yet.

So, you can see some disassembly here. But wait, why not C code? you compiled with -g right?

Well, that's because you're not actually in your program yet! Let's see where we are:

(lldb) thread backtrace 
* thread #1: tid = 0xae1f0, 0x1fe29000 dyld`_dyld_start, stop reason = signal SIGSTOP
  * frame #0: 0x1fe29000 dyld`_dyld_start

So, we're in dyld:_dyld_start (you can actually see this in the previous output too). Wait, what?

Well, in iOS, every executable needs to be dynamically linked; as a result, every executable is started from _dyld_start(.) in the dynamic linker (dyld). You can see details on this linker by looking at the currently loaded libraries:

(lldb) image list
[  0] 02354203-2680-372F-8D38-3C4C2B42A8A3 0x1fe28000 /Users/cclamb/Library/Developer/Xcode/iOS DeviceSupport/9.3.3 (13G34)/Symbols/usr/lib/dyld 

We only have one library loaded right now - dynamic linker. This will change.

Now, let's set a breakpoint in main and run:

(lldb) breakpoint set --name main
Breakpoint 1: no locations (pending).
WARNING:  Unable to resolve breakpoint to any actual locations.
(lldb) continue
Process 1543 resuming
1 location added to breakpoint 1
Process 1543 stopped
* thread #1: tid = 0xae1f0, 0x0000bff4 function`main(argc=1, argv=0x0010ff44) + 22 at function.c:7, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000bff4 function`main(argc=1, argv=0x0010ff44) + 22 at function.c:7
   4   }
   5   
   6   int main(int argc, char* argv[]) {
-> 7     int i = 0xdeadc0de;
   8     call();
   9     return 0;
   10  }

Ah, here's some C source. Excellent - we have an application running on iOS and we're debugging it from our local mac!

Feel free to experiment with some additional lldb commands at this point to learn your way around a bit. In the next installment we'll look over the registers and stack, and then we'll start building a stack buffer overflow exploit example.

Learn how divergent branches can appear in your repository and how to better understand why they are called “branches".  Brought to you in partnership with Wakanda

Topics:
lldb ,ios ,mobile

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}