<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>~clay &#187; debug</title>
	<atom:link href="http://daemons.net/~clay/tag/debug/feed/" rel="self" type="application/rss+xml" />
	<link>http://daemons.net/~clay</link>
	<description>merely my musings</description>
	<lastBuildDate>Mon, 10 May 2010 17:48:58 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Getting past ptrace()</title>
		<link>http://daemons.net/~clay/2005/12/26/pesky-ptrace/</link>
		<comments>http://daemons.net/~clay/2005/12/26/pesky-ptrace/#comments</comments>
		<pubDate>Mon, 26 Dec 2005 13:38:37 +0000</pubDate>
		<dc:creator>clay</dc:creator>
				<category><![CDATA[Geek]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[os x]]></category>
		<category><![CDATA[ppc]]></category>
		<category><![CDATA[ptrace]]></category>

		<guid isPermaLink="false">http://daemons.net/~clay/?p=36</guid>
		<description><![CDATA[During the holiday break I figured I'd learn some PowerPC (PPC) assembly while I still had the chance, given Apple's decision to move to x86 early next year. Debugging simple programs isn't much fun, though, so I figured I'd start poking around with a big application. An annoying thing kept happening everytime I fired up the app under the debugger, though; it exited immediately with a strange error code:
<code>
% gdb /Applications/blah.app/Contents/MacOS/blah
(gdb) run
Program exited with code 055.
</code>

Bummer. I remembered the same problem happening with that commercial Solaris app years before, but I never paid much attention to it back then, because it was possible to work around the problem by attaching to the program after it was already up and running. Apple seems to be a bit smarter than that, though, because whenever I attached to a running copy of the application, GDB seg faulted:
<code>
(gdb) attach 17813
Attaching to program: `/Applications/blah.app/Contents/MacOS/blah', process 17813.
Segmentation fault
</code>

Since I wanted to know why the application was exiting, I figured I'd step through it one instruction at a time until I found the culprit.]]></description>
			<content:encoded><![CDATA[<p>The holidays have given me a chance to relax and geek around with Mac OS X, and I&#8217;ve finally gotten around to installing the Developer Tools package, which includes the GNU C compiler (gcc) and the GNU debugger (gdb). Over the years I&#8217;ve gotten pretty comfortable using gdb to troubleshoot programs on SPARC and Intel platforms. Debugging requires that you know a bit about assembly language, and I had learned x86 assembly back in the day when I was coding fun little graphics toys for DOS, and had learned some SPARC assembly trying to, uhm, correct an annoying license issue in a piece of commercial software.</p>
<p>During the holiday break I figured I&#8217;d learn some PowerPC (PPC) assembly while I still had the chance, given Apple&#8217;s decision to move to x86 early next year. Debugging simple programs isn&#8217;t much fun, though, so I figured I&#8217;d start poking around with a big application. An annoying thing kept happening everytime I fired up the app under the debugger, though; it exited immediately with a strange error code:<br />
<code><br />
% gdb /Applications/blah.app/Contents/MacOS/blah<br />
(gdb) run<br />
Program exited with code 055.<br />
</code></p>
<p>Bummer. I remembered the same problem happening with that commercial Solaris app years before, but I never paid much attention to it back then, because it was possible to work around the problem by attaching to the program after it was already up and running. Apple seems to be a bit smarter than that, though, because whenever I attached to a running copy of the application, GDB seg faulted:<br />
<code><br />
(gdb) attach 17813<br />
Attaching to program: `/Applications/blah.app/Contents/MacOS/blah', process 17813.<br />
Segmentation fault<br />
</code></p>
<p>Since I wanted to know why the application was exiting, I figured I&#8217;d step through it one instruction at a time until I found the culprit.<br />
<span id="more-36"></span><br />
In simple programs, it&#8217;s usually sufficient to set a breakpoint on the <code>main()</code> function, but that skips over the C run-time start-up code. Since I wanted to step through each and every instruction in the program, including the start-up code, I used Apple&#8217;s <code>otool</code> command to print the application&#8217;s text segment, which gave me the address of the first instruction. I&#8217;ll demonstrate with /bin/ls:<br />
<code><br />
[satellite:~] clay% otool -tvV /bin/ls | head -5<br />
/bin/ls:<br />
(__TEXT,__text) section<br />
00001ac4        or      r26,r1,r1<br />
00001ac8        addi    r1,r1,0xfffc<br />
00001acc        rlwinm  r1,r1,0,0,26<br />
00001ad0        li      r0,0x0<br />
</code></p>
<p>This shows that the first instruction in /bin/ls is located at address 0&#215;1ac4, so I set a breakpoint for that and started running the program. Again, using /bin/ls to demonstrate:<br />
<code><br />
(gdb) break *0x1ac4<br />
Breakpoint 1 at 0x1ac4<br />
(gdb) run<br />
Starting program: /bin/ls</p>
<p>Breakpoint 1, 0x00001ac4 in ?? ()<br />
</code></p>
<p>Now it helps to see the instruction that&#8217;s about to be executed, so I setup a display that prints the instruction at $pc (the program counter) everytime the program stops:<br />
<code><br />
(gdb) display/i $pc<br />
1: x/i $pc  0x1ac4:     mr      r26,r1<br />
</code></p>
<p>At first glance it may seem that GDB and <code>otool</code> print different instructions at address 0&#215;1ac4:<br />
<code>
<pre>
otool:   or r26,r1,r1
GDB:     mr r26,r1
</pre>
<p></code></p>
<p>GDB is nice and prints user-friendly mnemonics like <code>mr</code> (for move register), which are easier to read and understand than the literal instructions that <code>otool</code> prints, but the instructions are identical.</p>
<p>Now the plan was to step over instruction after instruction, using <code>stepi</code>, until I found the offending bit of code. This was somewhat tedious, so I ended up using <code>nexti</code> quite a bit, which steps over function calls instead of stepping into them, speeding up the debugging. The only problem with that was that sometimes I would step over the function that caused the program to abort. Whenever that happened, I added a breakpoint on the address of the function call and then used <code>stepi</code> to step into the offending function. After several rounds of this (I think I was up to 11 breakpoints) I finally found where the program was stopping:<br />
<code><br />
0x90054204 in ptrace ()<br />
1: x/i $pc  0x90054204 &lt;ptrace +36&gt;:    sc<br />
(gdb) stepi<br />
Program exited with code 055.<br />
</code></p>
<p>&#8220;sc&#8221; is the PPC instruction that invokes a system call. Since GDB is nice enough to print symbols when it can, I decided to see if ptrace is a documented system call in Darwin. Sure enough, it is:</p>
<blockquote><p><code><br />
PTRACE(2)                   BSD System Calls Manual                  PTRACE(2)</p>
<p>NAME<br />
     ptrace -- process tracing and debugging</p>
<p>SYNOPSIS<br />
     #include &lt;sys/types.h&gt;<br />
     #include &lt;sys/ptrace.h&gt;</p>
<p>     int<br />
     ptrace(int request, pid_t pid, caddr_t addr, int data);</p>
<p>DESCRIPTION<br />
     ptrace() provides tracing and debugging facilities.<br />
</code></p></blockquote>
<p>Well that sounds interesting, since I was having trouble debugging the process, and the process is calling this system call that provides some type of debugging facility. The man page describes how a debugger (like GDB) might use ptrace() to control another process, but that wasn&#8217;t what I was interested in. I was looking for a way a debugged program might be able to control the debugger. Reading on, the man page hinted that this might be possible:</p>
<blockquote><p><code><br />
     [...] except for one special case noted below, all ptrace() calls are made by the tracing process [...]<br />
</code></p></blockquote>
<p>Hmm, does that one special case allow a traced process to invoke ptrace() to control a debugger? Sure enough, it does:</p>
<blockquote><p><code><br />
PT_DENY_ATTACH</p>
<p>This request is the other operation 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.<br />
</code></p></blockquote>
<p>Bingo! This explains both the seg fault and the exit immediately after startup. So now that I knew why the program wasn&#8217;t cooperating with GDB, I could coerce it into playing nicely. First, a disassembly of the ptrace() function:<br />
<code><br />
(gdb) disas<br />
Dump of assembler code for function ptrace:<br />
0x900541e0 &lt;ptrace +0&gt;:  li      r7,0<br />
0x900541e4 &lt;ptrace +4&gt;:  mflr    r0<br />
0x900541e8 &lt;ptrace +8&gt;:  bcl-    20,4*cr7+so,0x900541ec &lt;ptrace +12&gt;<br />
0x900541ec  &lt;ptrace +12&gt;: mflr    r8<br />
0x900541f0  &lt;ptrace +16&gt;: mtlr    r0<br />
0x900541f4  &lt;ptrace +20&gt;: addis   r8,r8,4091<br />
0x900541f8  &lt;ptrace +24&gt;: lwz     r8,7860(r8)<br />
0x900541fc  &lt;ptrace +28&gt;: stw     r7,0(r8)<br />
0x90054200  &lt;ptrace +32&gt;: li      r0,26<br />
0x90054204  &lt;ptrace +36&gt;: sc<br />
0x90054208  &lt;ptrace +40&gt;: b       0x90054210 &lt;ptrace +48&gt;<br />
0x9005420c  &lt;ptrace +44&gt;: b       0x90054230 &lt;ptrace +80&gt;<br />
0x90054210  &lt;ptrace +48&gt;: mflr    r0<br />
0x90054214  &lt;ptrace +52&gt;: bcl-    20,4*cr7+so,0x90054218 &lt;ptrace +56&gt;<br />
0x90054218 &lt;ptrace +56&gt;: mflr    r12<br />
0x9005421c  &lt;ptrace +60&gt;: mtlr    r0<br />
0x90054220  &lt;ptrace +64&gt;: addis   r12,r12,4091<br />
0x90054224  &lt;ptrace +68&gt;: lwz     r12,7792(r12)<br />
0x90054228  &lt;ptrace +72&gt;: mtctr   r12<br />
0x9005422c  &lt;ptrace +76&gt;: bctr<br />
0x90054230  &lt;ptrace +80&gt;: blr<br />
End of assembler dump.<br />
</code></p>
<p>Now I don&#8217;t know exactly what all of that means, but I saw the &#8220;sc&#8221; instruction in the middle of the function and I knew I wanted to avoid making that system call. The obvious thing to try was to set a breakpoint on function entry and then use the <code>jump</code> command to jump right to the last instruction in the function, effectively bypassing that pesky system call:<br />
<code><br />
(gdb) break ptrace<br />
Breakpoint 11 at 0x900541f4<br />
(gdb) run<br />
Starting program: /Applications/blah.app/Contents/MacOS/blah</p>
<p>Breakpoint 11, 0x900541f4 in ptrace ()<br />
(gdb) jump *0x90054230<br />
Continuing at 0x90054230.<br />
</code></p>
<p>When I did that, breakpoint 11 fired again, so I did the <code>jump</code> again, and breakpoint 11 fired again, so, well, the short story is that I had to do the <code>jump</code> 6 times before the program continued on. Maybe the developers were paranoid and called ptrace() six times. Whatever the reason, after finally getting past all six ptrace()s, the program started up just fine:<br />
<code><br />
(gdb) jump *0x90054230<br />
Continuing at 0x90054230.<br />
Reading symbols for shared libraries . done</p>
<p></code></p>
<p>The program ran as normal, under control of the debugger. Now that I know how to get it to run under GDB I can start poking around with some of the more interesting bits of code.</p>
<p>I hope everyone&#8217;s having a nice holiday, and I promise to post more often! <img src='http://daemons.net/~clay/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://daemons.net/~clay/2005/12/26/pesky-ptrace/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
