Page 1 of 1

Debugging complex daemons from start

PostPosted: Sun Sep 18, 2016 5:28 pm
by backendbilly
I've never come across examples related to debugging complex daemons on iOS such as locationd. Attaching is never an issue but debugging the daemon on start was never successful for me given the fact that a lot of pre-initialization happen prior to stopping at the daemon entry point. In my case, the daemon always exited.

J or anybody, have you ever come across debugging such complex daemons and whether you have a technique to stop the debugger at daemon entry point?

Billy

Re: Debugging complex daemons from start

PostPosted: Mon Sep 19, 2016 4:19 pm
by morpheus
Simple technique: Force inject a simple library, and in its constructor for (;;) { sleep(1);}

Then attach a debugger at your leisure.

Re: Debugging complex daemons from start

PostPosted: Tue Sep 20, 2016 3:55 am
by backendbilly
Sounds like fun J. Would you mind elaborating on the force injection part please? Much appreciated.

Re: Debugging complex daemons from start

PostPosted: Tue Sep 20, 2016 2:27 pm
by TheDarkKnight
J is referring to the use of the environment variable DYLD_INSERT_LIBRARIES, which is mentioned briefly in MOXiI on p129.

By setting the environment to point to a library that you create, the dynamic linker (launchd) will load your library, allowing you to execute code in the target process.
When the library to be inserted contains a constructor, it will be invoked when loaded, giving you the ability to add the code
Code: Select all
 for(;;) {sleep(1);}
and attach the debugger.

In the case of a service, you can add the DYLD_INSERT_LIBRARIES as an Environment Variable to the service's plist.

A simple example of its usage is with the libGMalloc library that resides in /usr/lib/.
Execute the following shell command and note the output: -

Code: Select all
DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib `which ls`

Re: Debugging complex daemons from start

PostPosted: Tue Sep 20, 2016 4:10 pm
by Siguza
I found the following in "man launchd.plist":

WaitForDebugger <boolean>
This optional key specifies that launchd should launch the job in a suspended state so that a debugger can be attached to the process as early as possible (at the first instruction).


"launchctl debug" is supposed to add that to a service, too.
I didn't try it, but does that not work(on iOS), or does that wait at a later point than where inserted libraries' constructors get executed?

Re: Debugging complex daemons from start

PostPosted: Wed Sep 21, 2016 7:44 am
by TheDarkKnight
WaitForDebugger works as expected.

The problem I've found with using launchctl debug is that it doesn't often work. I think that may be due to the cache, which is described in the man pages as:

launchd maintains an in-memory cache of XPC service configuration files to minimize the disk I/O


Whilst there's an option for uncache service-name in the man pages, it returns
Command is not yet implemented

Re: Debugging complex daemons from start

PostPosted: Wed Sep 21, 2016 1:37 pm
by backendbilly
J is referring to the use of the environment variable DYLD_INSERT_LIBRARIES, which is mentioned briefly in MOXiI on p129.

That was my first thought too. I'm familiar with DYLD_INSERT_LIBRARIES but wasn't sure how to use within a launchd config. Then I came across this https://www.theiphonewiki.com/wiki/Launchd.conf_Untether. I haven't tried it yet.

WaitForDebugger <boolean>


That was my first try is to configure the /System/Library/LaunchDaemons/.. plist file and add a "WaitForDebugger". Never seemed to work on iOS

Billy

Re: Debugging complex daemons from start

PostPosted: Wed Sep 21, 2016 4:57 pm
by morpheus
As far as I can remember (it's been a while) WFD never worked for me on iOS. Hence the DYLD_INSERT_LIBRARIES suggestion. dont bother with launchd.conf - it's removed as of iOS 8.

Add to your plist:

<key>EnvironmentVariables</key>
<dict>
<key>DYLD_INSERT_LIBRARIES</key>
<string>/path/to/libname.dylib</string>
</dict>

Caveat: as of 9.2.x for some value of x launchd refuses this variable. But there's a clever workaround I'm not sure I can share here because AAPL might plug it.