Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I trap to the debugger and continue on iOS hardware?

On Mac OS X and in the iOS simulator (both x86), we can trap to the debugger (LLDB) using the int3 instruction in inline assembly. This is nice because it traps to a particular line of code but we can continue immediately by hitting continue in the debugger.

Is there a way to do this on iOS hardware?

An answer to an older question mentions raise(SIGINT) which as far as I can see (from examining signal.h) does not exist. Another answer mentions the trap assembly instruction, which causes a build error ("Unrecognized instruction mnemonic"). Also unrecognized is the BKPT assembly instruction mentioned in ARM documentation.

I've tried __builtin_trap() which almost, almost does what I want, but does not allow me to continue. I keep hitting it unless I advance the instruction pointer manually using jump +1 or register write pc `$pc+8\`, which is much less convenient than just hitting continue.

I'm building for iOS 9 for 32- and 64-bit devices using Xcode 7.3.1. Any help is appreciated!

like image 302
Luke Avatar asked Jun 09 '16 21:06

Luke


People also ask

Does Xcode have a debugger?

The Xcode debugger provides several methods to step through your code and inspect variables. You can precisely control execution of your code from a breakpoint, stepping into and out of called functions as necessary to determine where your bug occurs.

How do I debug in Xcode step by step?

When you run an application in Xcode, the debugger is automatically started and attached to the process of the application. Click the Run button in the top left or press Command + R. From the moment the application is up and running, we can start inspecting the process and, if necessary, debug it.


2 Answers

Apple's libc signal.h includes XNU's sys/signal.h, which does define SIGINT (on all platforms):

// [...]

#define SIGHUP  1   /* hangup */
#define SIGINT  2   /* interrupt */
#define SIGQUIT 3   /* quit */
// [...]

So while I cannot confirm that this practice does indeed work (due to lack of an iOS 9 device on my part), the barrier that held you back should not actually be a problem.

As for the assembly instructions, BKPT is a valid ARM instruction, though only for A32. The A64 variant is called BRK.
If you're building fat binaries and use either of those unconditionally, you will always run into compiler error.

Also note that both instructions require an immediate value (which is passed to the debugger). Omitting that value will produce a compiler error as well.

That said, you should be able to insert debug instructions for A32 and A64 with a simple #ifdef:

#ifdef __aarch64__
asm volatile("BRK 0");
#else
asm volatile("BKPT 0");
#endif

You can substitute 0 by any value of your choosing between 0 and 255.

A note on the TRAP instruction: While Apple's assembler seems to accept this instruction for A32 and translates it to 0xe7ffdefe, it will issue an "unrecognized instruction mnemonic" on A64, analogous to the BKPT instruction.
I was also unable to find any reference to the instruction on the ARM Information Center or in Apple's documentation.

like image 121
Siguza Avatar answered Oct 25 '22 12:10

Siguza


I've had a similar problem using Swift on OS X: 1) raise(SIGINT) didn't work for me in background processes (e.g: SceneKit's Scene Renderer Protocol). (perhaps a missing handler?) 2) __builtin_trap() doesn't allow continuing after 3) asm(" int3 ") requires ObjC and header files, which scared me off at first. But it wasn't too bad. Just added three lines in two new files:

---- NSObject+MachineTrap.h ----

void machineTrap(void);

---- NSObject+MachineTrap.h ----

#import "NSObject+MachineTrap.h"
void machineTrap(void) { asm (" int3 "); } /// Program has TRAPPED to DEBUGGER ///`

(My choice of int3 over say BRK, BKPT, SVC may not be correct.)

like image 38
Allen King Avatar answered Oct 25 '22 11:10

Allen King