Jun 18 2008
10:15 Best part of MS 'optimisation' is that __inline attribute
11:57 actually, , the bombs explode twice as fast in this version. it's a bug :-)
Jun 19 2008
13:16 sfd
Jun 20 2008
10:19 click to yabber
Jun 29 2008
02:58 Where's the MUSIC??!!11!?
03:00 I cluck too soon. Any chance I can get a copy of this thing, and maybe mynephewthegeek can bolt the music back on? That was half the game...
Jun 30 2008
15:51 <Jabber>
16:36 You can get a copy over at home-of-the-underdogs, ; it runs well in DOSBOX
Jul 5 2008
03:46 what about wap.steike.com?
Jul 6 2008
14:39 It's gone. Sorry.
Jul 8 2008
21:56 this is freakin ballin. i was so happy to see this!
Jul 10 2008
14:25 jctoast@hotmail.com
Jul 11 2008
05:31 jjjj
Jul 16 2008
14:50 Click to yabber
Jul 18 2008
20:17 Click to jabber
Jul 23 2008
14:02 how do you freaking get to the open door on 64

steike / code / debugging itunes with gdb

It's occasionally useful to run iTunes under GDB without having it bomb out with a 'code 055' or having gdb segfault.

Here's how.

If you're worried about the morality of this, here's a tech note from Apple encouraging you to debug iTunes. If you try, here's what happens:

/Applications/iTunes.app/Contents/MacOS$ gdb -q ./iTunes 
Reading symbols for shared libraries ............... done
(gdb) run
Starting program: /Applications/iTunes.app/Contents/MacOS/iTunes 
Reading symbols for shared libraries .................................................... done

Program exited with code 055.
(gdb)

Ouch.

/Applications/iTunes.app/Contents/MacOS$ gdb -q -p 11079
/Applications/iTunes.app/Contents/MacOS/11079: No such file or directory.
Attaching to process 11079.
Segmentation fault

Ouch!!

Luckily, we can use GDB to debug itself:

/Applications/iTunes.app/Contents/MacOS$ /usr/libexec/gdb/gdb-powerpc-apple-darwin -q /usr/libexec/gdb/gdb-powerpc-apple-darwin
Reading symbols for shared libraries .... done
(gdb) run -q -p 11079
Starting program: /usr/libexec/gdb/gdb-powerpc-apple-darwin -q -p 11079
/Applications/iTunes.app/Contents/MacOS/11079: No such file or directory.
Attaching to process 11079.

Program received signal SIGSEGV, Segmentation fault.
0x9002d2c8 in ptrace ()

Ok, it segfaults inside the ptrace() system call. Maybe the parameters are bad?

(gdb) break ptrace
Breakpoint 1 at 0x9002d2b4
(gdb) run -p 11079
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /usr/libexec/gdb/gdb-powerpc-apple-darwin -q -p 11079
/Applications/iTunes.app/Contents/MacOS/11079: No such file or directory.
Attaching to process 11079.

Breakpoint 1, 0x9002d2b4 in ptrace ()
(gdb) p $r3
$1 = 14
(gdb) p $r4
$2 = 11079
(gdb) p $r5
$3 = 0
(gdb) p $r6
$4 = 0

ptrace manual page and header file:

SYNOPSIS
     #include <sys/types.h>
     #include <sys/ptrace.h>

     int
     ptrace(int request, pid_t pid, caddr_t addr, int data);

...

#define PT_ATTACHEXC    14      /* attach to running process with signal exception */

This exact same call succeeds for all applications except iTunes, so the bomb is probably not in gdb itself.

The ptrace() function is in the Darwin module xnu:

	if (uap->req == PT_ATTACH) {

		/*
		 * You can't attach to a process if:
		 *	(1) it's the process that's doing the attaching,
		 */
		if (t->p_pid == p->p_pid)
			return (EINVAL);

		/*
		 *	(2) it's already being traced, or
		 */
		if (ISSET(t->p_flag, P_TRACED))
			return (EBUSY);

		/*
		 *	(3) it's not owned by you, or is set-id on exec
		 *	    (unless you're root).
		 */
		if ((t->p_cred->p_ruid != p->p_cred->p_ruid ||
			ISSET(t->p_flag, P_SUGID)) &&
		    (error = suser(p->p_ucred, &p->p_acflag)) != 0)
			return (error);

		if ((p->p_flag & P_TRACED) && isinferior(p, t))
			return(EPERM);

		if (ISSET(t->p_flag, P_NOATTACH)) {
			psignal(p, SIGSEGV);
			return (EBUSY);
		}

Funny how the important part isn't commented at all :-)

The only other mention of this magic NOATTACH flag is this:

        if (uap->req == PT_DENY_ATTACH) {
	        if (ISSET(p->p_flag, P_TRACED)) {
				exit1(p, W_EXITCODE(ENOTSUP, 0), retval);
				/* drop funnel before we return */
				thread_funnel_set(kernel_flock, FALSE);
				thread_exception_return();
				/* NOTREACHED */
			}
		SET(p->p_flag, P_NOATTACH);

		return(0);
	}

.. also in ptrace().

/usr/include/sys/errno.h:#define ENOTSUP        45              /* Operation not supported */

.. and so we have the origin of the strange '055' exit code (055 octal is 45 in decimal)

So, there is an undocumented system call:

    ptrace(PT_DENY_ATTACH, 0, 0, 0);

.. that lets a process avoid being debugged.

#include <sys/types.h>
#include <sys/ptrace.h>
int main() {
  ptrace(PT_DENY_ATTACH, 0, 0, 0);
  sleep(100);
}
~/dev/airtunes$ gdb -q ./evil
Reading symbols for shared libraries .. done
(gdb) run
Starting program: /Users/erlingalf/Dev/airtunes/evil 
Reading symbols for shared libraries . done

Program exited with code 055.
(gdb)
/Users/erlingalf/dev/airtunes$ ./evil & 
[2] 12220
/Users/erlingalf/dev/airtunes$ gdb -q -p 12220
/Users/erlingalf/Dev/airtunes/12220: No such file or directory.
Attaching to process 12220.
zsh: segmentation fault  gdb -q -p 12220
Same exact symptoms!

Summary

~/dev/airtunes$ gdb -q /Applications/iTunes.app/Contents/MacOS/iTunes 
Reading symbols for shared libraries ............... done
(gdb) break ptrace
Breakpoint 1 at 0x9002d2b4
(gdb) run
Starting program: /Applications/iTunes.app/Contents/MacOS/iTunes 
Reading symbols for shared libraries .................................................... done

Breakpoint 1, 0x9002d2b4 in ptrace ()
(gdb) return
Make selected stack frame return now? (y or n) y
#0  0x00249610 in ?? ()
(gdb) cont
Continuing.
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
.. and it works. Enjoy.

Changes for Tiger

At some point since that piece was written, the example at the end of the text stopped working; now, all OSX programs call ptrace() several times on startup:

(gdb) break ptrace
Breakpoint 1 at 0x900541f4
(gdb) run
Starting program: /Applications/Calculator.app/Contents/MacOS/Calculator 
Reading symbols for shared libraries ............................................................................... done
Breakpoint 1, 0x900541f4 in ptrace ()
(gdb) bt
#0  0x900541f4 in ptrace ()
#1  0x92857a00 in _NSInitializePlatform ()
#2  0x909ad55c in call_class_loads ()
#3  0x909ad470 in call_load_methods ()
#4  0x909a8308 in map_images ()
#5  0x8fe0fc94 in __dyld__ZN16ImageLoaderMachO14doNotificationE15dyld_image_modejPK15dyld_image_info ()
#6  0x8fe06258 in __dyld__ZN4dyld12notifyAddingERSt6vectorIP11ImageLoaderSaIS2_EE ()
#7  0x8fe0ef78 in __dyld__ZN11ImageLoader15runInitializersERKNS_11LinkContextE ()
#8  0x8fe03784 in __dyld__ZN4dyld24initializeMainExecutableEv ()
#9  0x000022d4 in ?? ()
#10 0x000023a4 in ?? ()
#11 0x00009390 in ?? ()
(gdb) p/x $r3
$5 = 0xf000
(gdb) p/x $r4
$6 = 0x0
(gdb) finish
Run till exit from #0  0x900541f4 in ptrace ()
0x92857a00 in _NSInitializePlatform ()
(gdb) p/x $r3
$7 = 0xffffffff
(gdb) 

As you can see, they call ptrace(0xf000, 0, 0, 0). The function code 0xF000 is clearly bad (the valid ones are all below 50 or so), so the call just fails. The error is ignored, and life goes on. This is in NSInitializePlatform, and there are more calls all over the place.

The calls are all neatly placed before and after various stages of the startup process, and are numbered neatly as well (nn00 going in, nnFF going out; sometimes a few more in-between); I'm guessing they were either used for profiling or were added as suitable places for kernel extensions to jump in and do their thing. Or they might just be there to make system call traces more readable. Who knows?

To get iTunes running in gdb again, you just need to breakpoint the right ptrace call:

(gdb) break ptrace if $r3 == 31
Breakpoint 1 at 0x900541f4
(gdb) cont
The program is not being run.
(gdb) run
Starting program: /Applications/iTunes.app/Contents/MacOS/iTunes 
Reading symbols for shared libraries ......................................................................... done

Breakpoint 1, 0x900541f4 in ptrace ()
(gdb) bt
#0  0x900541f4 in ptrace ()
#1  0x002888fc in ?? ()
#2  0x8fe15b8c in __dyld__ZN16ImageLoaderMachO16doInitializationERKN11ImageLoader11LinkContextE ()
#3  0x8fe0b5b0 in __dyld__ZN11ImageLoader23recursiveInitializationERKNS_11LinkContextE ()
#4  0x8fe0ef84 in __dyld__ZN11ImageLoader15runInitializersERKNS_11LinkContextE ()
#5  0x8fe03784 in __dyld__ZN4dyld24initializeMainExecutableEv ()
#6  0x000046d4 in ?? ()
#7  0x000045b0 in ?? ()
#8  0x00004510 in ?? ()
(gdb) return
Make selected stack frame return now? (y or n) y
#0  0x002888fc in ?? ()
(gdb) cont
Continuing.
Reading symbols for shared libraries ........ done

Comments

On the original Wiki, some anonymous passer-by added this section.

I tried this on Tiger with iTunes 5, and noticed the following.

iTunes 5 on OSX Tiger (1.4) seems to call ptrace more often. I haven't checked what arguments it passes to ptrace, but there seems to come no harm from just ignoring all those ptrace-call, like outlined above. But because it's quite tendious to return from each ptrace call manually, I created a small gdb-script that does the work for me. Here it comes:

break ptrace
commands 1
    return
   continue
end

Now just call gdb with gdb -x -q ./iTunes, and it automatically ignores all ptrace calls without bothering you.

Another anonymous commenter sent a link to this kext to disable PT_DENY_ATTACH.

"Evil Genius" pointed out that Phrack posted instructions on how to disable it by NOPing out the libc stub for ptrace().

[Comment on this]