3

It's normally easy to log all messages sent to a class with DTrace, for example by using trace_msg_send.sh script from here:

#!/usr/sbin/dtrace -s
#pragma D option quiet

unsigned long long indention;
int indentation_amount;

BEGIN {
  indentation_amount = 4;
}

objc$target:$1::entry
{
    method = (string)&probefunc[1];
    type = probefunc[0];
    class = probemod;
    printf("%*s%s %c[%s %s]\n", indention * indentation_amount, "", "->", type, class, method);
    indention++;
}
objc$target:$1::return
{
    indention--;
    method = (string)&probefunc[1];
    type = probefunc[0];
    class = probemod;
    printf("%*s%s %c[%s %s]\n", indention * indentation_amount, "", "<-", type, class, method);
}

Given the code:

$ cat > test.m
#include <stdio.h>
#import <Foundation/Foundation.h>

@interface TestClass : NSObject

+ (int)randomNum;

@end

@implementation TestClass

+ (int)randomNum {
    return 4; // chosen by fair dice roll.
              // guaranteed to be random.
}

@end

int main(void) {
    printf("num: %d\n", [TestClass randomNum]);
    return 0;
}
^D

you would get the following output by using the DTrace script:

$ gcc test.m -lobjc -o test
$ ./test
num: 4
$ sudo ./trace_msg_send.d -c ./test TestClass
num: 4
-> +[TestClass randomNum]
<- +[TestClass randomNum]

However if we strip the binary:

$ strip test
$ sudo ./trace_msg_send.d -c ./test TestClass
dtrace: failed to compile script ./trace_msg_send.d: line 11: probe description objc49043:TestClass::entry does not match any probes

the script no longer works.

Is there a way of telling DTrace, where the stripped classes/message implementations are located?

Maybe using the info available from class-dump, like in the answer for Import class-dump info into GDB.


I have created a script that tries to compare the classname at runtime, however it doesn't seem to work:

#!/usr/sbin/dtrace -s
#pragma D option quiet

unsigned long long indention;
int indentation_amount;

BEGIN {
  indentation_amount = 4;
}

objc$target:::entry
{
    // Assumes 64 bit executable
    isaptr = *(uint64_t *)copyin(arg0, 8);
    class_rw = *(uint64_t *)copyin(isaptr + 4*8, 8);
    class_ro = *(uint64_t *)copyin(class_rw + 8, 8);
    classnameptr = *(uint64_t *)copyin(class_ro + 4*4 + 8, 8);
    classname = copyinstr(classnameptr);

    type = classname == $$1? (string)&probefunc[0]: "";
    method = classname == $$1? (string)&probefunc[1]: "";

    arrow = classname == $$1? "->": "";
    space = classname == $$1? " ": "";
    bracket1 = classname == $$1? "[": "";
    bracket2 = classname == $$1? "]": "";
    current_indention = classname == $$1? indention: 0;
    indention = classname == $$1? indention + 1: indention;

    newline = classname == $$1? "\n": "";

    classname = classname == $$1? classname: "";

    printf("%*s%s%s%.1s%s%s%s%s%s%s", current_indention * indentation_amount, "", arrow, space, type, bracket1, classname, space, method, bracket2, newline);
}

Running sudo ./trace_msg_send2.d -c ./test TestClass prints:

num: 4
dtrace: error on enabled probe ID 179 (ID 13922: objc3517:NSObject:+load:entry): invalid address (0x7fff8204e03e) in action #5 at DIF offset 12
dtrace: error on enabled probe ID 186 (ID 13915: objc3517:__IncompleteProtocol:+load:entry): invalid address (0x7fff8204e01f) in action #5 at DIF offset 12
dtrace: error on enabled probe ID 195 (ID 13906: objc3517:Protocol:+load:entry): invalid address (0x7fff8204e034) in action #5 at DIF offset 12
-> +[TestClass initialize]

where -> -[TestClass randomNum:] is missing.

Tyilo
  • 28,998
  • 40
  • 113
  • 198
  • Even I am trying to use dtrace with a stripped binary and dtrace is just giving objective-c runtime classes and functions. Any idea how can i get the function names implemented in stripped binary using dtrace? – Dipti Shiralkar Jan 04 '17 at 13:12

0 Answers0