#!/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");
}