Mac OSX 下利用GDB调试itunes

原文:http://steike.com/code/debugging-itunes-with-gdb/

调试itunes时,设置端点到<dyld_stub_ptrace>,然后run。触发端点后return,然后con。完事大吉!!!
附原文:

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.

Why can't you just use GDB?

There's no real reason why you shouldn't be able to connect GDB to iTunes -- there's even this tech note from Apple encouraging you to do so. However, 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. iTunes crashed with "exit code 055" on startup. What happens if we try to connect to an already-running instance of iTunes?

/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!! GDB itself explodes.

Luckily, we can use GDB to debug itself to see what's wrong:

/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, incidentally, 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: /tmp/evil 
Reading symbols for shared libraries . done

Program exited with code 055.
(gdb)
/tmp$ ./evil & 
[2] 12220
/tmp$ gdb -q -p 12220
/tmp/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().

Comments

Thanks much -- I need to debug an iTunes visualizer plugin and this certainly lifts the veil. FWIW, the ptrace man page documents PT_DENY_ATTACH and its behavior exactly: "...used by the traced process; it allows a process that is not currently being traced to deny future traces by its parent. All other arguments are ignored. If the process is currently being traced, it will exit with the exit status of ENOTSUP; otherwise, it sets a flag that denies future traces. An attempt by the parent to trace a process which has set this flag will result in a segmentation violation in the parent."
— David Gish 2009-06-25
[Good to see they finally got around to documenting it (most of this page was written in 2004!)]



 

转载于:https://www.cnblogs.com/GrowUP-EveryDay/archive/2013/01/07/2849511.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值