#!/usr/sbin/dtrace -s #pragma D option quiet /* The output of this should be put in side an OPML wrapper by the caller ... Then, it can be loaded into OmniOutliner 3. */ /* Catch nil messages; won't hit the actual implementations. Also, we don't know if these are being sent to nil or Nil. */ pid$target::objc_msgSend:entry /arg0 == 0/ { printf("\n", copyinstr(arg1)); } pid$target::objc_msgSend_stret:entry /arg0 == 0/ { /* In the stret version, the first argument is the pointer to the 'returned' struct on the stack; hence, the selector is in arg2 here */ printf("\n", copyinstr(arg2)); } pid$target::objc_msgSend_fpret:entry /arg0 == 0/ { printf("\n", copyinstr(arg1)); } /* Catch actual method implementations */ objc$target:*:*:entry { /* This could be a normal, fpret or stret method. We can't depend on where the receiver or _cmd are. It would be more convenient (and portable) if the objc provider would handle the stret calling convention for us somehow. Maybe it could drop the return pointer; though I'd hate to lose information... */ /* TEST: Does this work with dynamically registered selectors? Maybe depends on when they are registered. */ /* TEST: Does this catch calls to cached method IMPs? */ /* TEST: This almost certainly doesn't work with swizzled implementations. */ /* In the stret case, arg0 is the pointer back to the stack for the output structure. It will be between the fp and sp. */ /* RADAR 5709342: R_ESP isn't correct, it looks like. R_ESP is totally whack. R_SP and R_UESP seem right, though. */ this->is_stret = (uregs[R_SP] < arg0 && arg0 < uregs[R_EBP]); this->object = this->is_stret ? arg1 : arg0; /* We could split up the probes by matching '+' vs '-' in the name and then assume that 'this->object' is a 'Class'; as is we get to the metaclass instead. Whatever. */ this->isaptr = *(uintptr_t*)copyin(this->object, sizeof(uintptr_t)); this->classnameptr = *(uintptr_t*)copyin(this->isaptr+(2*sizeof(uintptr_t)), sizeof(uintptr_t)); this->classname = copyinstr(this->classnameptr); printf("\n", probemod, probefunc, this->classname, this->object); } objc$target:*:*:return { printf("\n"); }