Memories… programmer friendly assertions in Xcode

Well, things certainly tend to come around. After almost exactly 6 years, I once again find myself wanting to programmatically pause a program at interesting times for inspection using gdb. Where the code decides what’s interesting, mind you, not the developer’s symbolic breakpoint. Those six years have brought a new platform (iOS) and three new CPU architectures, so that trusty macro referenced in the link needs some updating. And update it I did – see the code fragment below.

O, and by the way, that’s gdb in its friendly Xcode disguise, of course. There’s a limit to how much mental abuse I can take, and that limit is comfortably reached by having to manually manage memory in Objective-C. I feel your pain, my embedded hardware brethren.

What I want…

So, we need to insert some code to break at a certain point or condition. A staple assert (false) won’t do, because there’s only so much you can do after the assert fires the near-fatal SIGABRT signal. You won’t be able to continue the program, or rewind the program counter. You probably won’t be able to use all that symbolic debug information in a very meaningful way. Admittedly, you can probably set up signal handlers in the debugger to pause on SIGABRT, but being a developer, you will forget that at least on the one occasion when it really mattered. And sometimes the interesting time is just interesting, not the beginning of the end of your program.

But there are other signals! SIGINT is a fine candidate to bring up the debugger. It will catch the signal and generally save your life. But there’s a snag. And another snag. The first is that SIGINT will kill your program when not run under the debugger. Unless you set up a signal handler or sigmask, but you’ll only do that in at most one or two of your applications. This is bad, because I’ll often just Run, not Debug,  development builds trusting Xcode to debug “just in time”. And this works fine for, e.g., segmentation violations. So why shouldn’t I have that for my programmatic breakpoints?

The second snag when using a plain kill is that the debugger will stop in the wrong stack frame. I have chosen the bold type to prevent the use of expletives. This frame mismatch requires me (and you, should you choose this ill-advised way) to navigate all of the two stack frames up to the point where your actual call (and probably the failed condition) is. Only two clicks of the “step out” button for the casual observer, but a huge productivity and mood sink for the developer who’s been observing the app not so casually for half an hour waiting for the bug to occur. This does not happen with gdb breakpoints. This does not happen with segmentation violations. So why should I have to put up with it for my programmatic breakpoints?

…is what you get

Fortunately, here is a solution that does not have these drawbacks. Using the original 2004 approach no less, ported to Intel and ARM. In a nutshell, the code has the following features. Most importantly, it breaks at the right stack frame and source line (using an inline asm block to generate the syscall to SYS_kill). And when run under the debugger, the debugger will come to the front just as if a normal breakpoint was reached, for your stepping and symbol-printing pleasure. Even better, when not running under the debugger (i.e., when started directly from Springboard), the application will simply suspend itself so you can safely attach the debugger when returning from a field test (aka the coffee corner).

There are two small issues with the simulator left, waiting for some heroic, last-man-standing developer to solve them. In the simulator, when started using the “Run” command instead of the “Debug” command, the app will suspend itself instead of attaching just-in-time. You’ll notice soon enough, though, and a simple click of the “Pause” button in the debugger will do what it purports to do. And due to a more general non-feature of Xcode, if you started the app using Springboard and it hits the breakpoint code, you’ll have to attach the debugger by typing in the apps process ID.

The Codes

The AmIBeingDebugged function is courtesy of Apple. Get the original here: http://developer.apple.com/library/mac/qa/qa2004/qa1361.html

And don’t forget that you might need to #import (or #include) <sys/signal.h> and <unistd.h> in files where you’ll be using these macros.


// In a suitable header
extern bool AmIBeingDebugged (void);
#if TARGET_CPU_ARM
#define DEBUGSTOP(signal) __asm__ __volatile__ ("mov r0, %0\nmov r1, %1\nmov r12, #37\nswi 128\n" : : "r" (getpid ()), "r" (signal) : "r12", "r0", "r1", "cc");
#define DEBUGGER do { int trapSignal = AmIBeingDebugged () ? SIGINT : SIGSTOP; DEBUGSTOP(trapSignal); if (trapSignal == SIGSTOP) { DEBUGSTOP (SIGINT); } } while (false);
#else
#define DEBUGGER do { int trapSignal = AmIBeingDebugged () ? SIGINT : SIGSTOP; __asm__ __volatile__ ("pushl %0\npushl %1\npush $0\nmovl %2, %%eax\nint $0x80\nadd $12, %%esp" : : "g" (trapSignal), "g" (getpid ()), "n" (37) : "eax", "cc"); } while (false);
#endif

// In an implementation file, far far away
extern bool AmIBeingDebugged (void)
{
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid () };
struct kinfo_proc info = { 0 };
size_t size = sizeof (info);
sysctl (mib, sizeof (mib) / sizeof (*mib), &info, &size, NULL, 0);

// We're being debugged if the P_TRACED flag is set.
return (info.kp_proc.p_flag & P_TRACED) != 0;
}

7 Comments

StevenOctober 12th, 2010 at 01:06

Helemaal mee eens!

Je bent de bom!

DavidOctober 12th, 2010 at 12:32

Nice little idea! Time to give it a try 😉

MarjanOctober 12th, 2010 at 14:58

You are the best!!

broneDecember 3rd, 2010 at 18:42

I’ve been using this for a month or two now. It works very well… thanks! I’ve made two additions to mine:

1. MOV R12,#37 isn’t always valid (don’t remember what I was doing precisely, probably trying to compile as Thumb1), so you want to load literal 37 the same way the value `signal’ is loaded.

2. If you add a NOP after the SWI 128, Xcode puts the current instruction marker on the DEBUGSTOP line rather than the next one.

Here’s my version of the macro in full. Best viewed in a fixed width font.

#define R_DEBUG_BREAK() \
do \
{ \
int signal=SIGINT; \
int blah=37; \
__asm__ __volatile__( \
“mov r0,%0\n” \
“mov r1,%1\n” \
“mov r12,%2\n” \
“swi 128\n” \
“nop\n” \
: \
:”r”(getpid()),”r”(signal),”r”(blah) \
:”r12″,”r0″,”r1″,”cc”); \
} \
while(0)

broneDecember 3rd, 2010 at 18:45

Looks like the blog software stripped out the spaces from my macro. The font that would make the result look good hasn’t been invented yet…

m20December 6th, 2010 at 22:34

Thanks so much for the feedback, I’ll edit the post!

stevenApril 27th, 2011 at 09:47

Great.

Leave a comment

Your comment