5

When running an iOS app in the simulator, there's an environment variable NSObjCMessageLoggingEnabled that causes all objc_msgSend calls to be logged out to a file. (Detailed explanation).

I'm trying to trace out all the messages that are being sent in my app, but I can't run it in the simulator. It has to be on a physical device because I'm interacting with hardware through the lightning connector. For the same reason, I can't attach a debugger to the process.

It would be helpful to write a log to disk like the one created with NSObjCMessageLoggingEnabled, but write it locally in my app's Documents directory, or similar.

Is this possible?

funroll
  • 35,925
  • 7
  • 54
  • 59
  • 2
    I'd highly recommend you approach this from a different perspective. The amount of log spew will be overwhelming, it is going to log about a zillion irrelevant messages, and the end result is going to be highly implementation dependent. – bbum Aug 26 '14 at 22:26
  • @bbum: It's worth noting that when I turned this on (without configuring logging) and attempted to run in the debugger, my computer suddenly lost connection to the iOS device; I had to unplug it, reboot it, and quit and relaunch Xcode before they'd talk to each other again. Not sure if that's because there were a zillion messages being sent over the wire rather than saved locally on the device (I can't see them anywhere visible… I need to try this on a jailbroken device…), but it seems at least possible. – abarnert Aug 27 '14 at 00:20
  • @bbum: More importantly: Even in OS X, where I've used message send instrumenting, I've done it by turning `instrumentObjcMessageSends` on and quickly off again around a certain block of code, and/or using a conditional breakpoint. I can't imagine dumping out and then searching through the whole mess of every message send in my program, especially without filtering as the OP seems to want to do… – abarnert Aug 27 '14 at 00:22
  • @abarnert Yeah -- I suspect that saturating the link between device and computer might result in the behavior your describe. abarnert's suggestion may work and, if so, redirecting log output might be tricky, but probably doable using similar shenanigans to either discover the write location or otherwise redirect it. – bbum Aug 27 '14 at 17:32
  • I have tried enabling the enviromental variable and the amount of the log is overwhelming in the output file /tmp/msgSends-. Is there any way to filter out the user/developer defined methods and ignore the system calls? – ramo Aug 27 '14 at 20:46
  • 1
    @funroll as explained in the blog you need to write a custom "MyLogObjCMessageSend" method ... https://github.com/pkjmesra/SCBUTube/blob/master/SCBUTube/Components/PeerFun/Classes/Logger/Main/LoggerAppDelegate.m – ramo Aug 27 '14 at 20:59

1 Answers1

5

All NSObjCMessageLoggingEnabled does is cause CoreFoundation to automatically call instrumentObjcMessageSends at startup and shutdown.

The problem is that Apple has intentionally hidden that function in the native iOS SDK, so you can't just call it.

But it still exists in the dylib at runtime, so you can always do this:

#include <dlfcn.h>

typedef void functype(BOOL);
void *libobjc = dlopen("/usr/lib/libobjc.dylib", RTLD_LAZY);
functype *instrumentObjcMessageSends = dlsym(libobjc, "instrumentObjcMessageSends");
if (!instrumentObjcMessageSends) {
    NSLog(@"Couldn't get instrumentObjcMessageSends");
    exit(1);
}
instrumentObjcMessageSends(YES);
NSLog(@"Did it");

I have no idea where, if anywhere, the logs are being written to. I assume you're going to want to call logObjcMessageSends to register your own ObjCLogProc, as explained in the post you linked to.

Alexander
  • 59,041
  • 12
  • 98
  • 151
abarnert
  • 354,177
  • 51
  • 601
  • 671