c++ - DTracing objc_msgSend doesn't print the receiver class name -
i using dtrace print objc_msgsend in code. i've done far can see selector's name cannot correct class name.
this dtrace script:
#!/usr/sbin/dtrace -qs pid$target::objc_msgsend:entry { self->isa = *(long *)copyin(arg0, 8); printf("-[%s %s]\n", copyinstr(*(long *)copyin(self->isa + 16, 8)), copyinstr(arg1)); }
and assuming the id receiver object of following struct:
typedef struct objc_class { struct objc_class *isa; struct objc_class *super_class; char *name; ... }
in head, in order reach name pointer has moved 2 * sizeof(objc_class*) makes 16, , pointer of name of size 8. therefore expected see class name garbage printed instead.
any ideas of doing wrong?
my system mavericks x64.
after poking around obj-c runtime source code 64 bit architecture , "objc-private.h" file, "formula" class name class pointer:
#define rw_realized (1<<31) #define rw_future (1<<30) #define class_fast_flag_mask 3 #define tag_mask 1 #define tag_slot_shift 0 #define tag_slot_mask 0xf extern "c" class objc_debug_taggedpointer_classes[]; // available in 10.9 tagged pointers decoding static const char* classnamefrominstance(id instance) { char* ptr0 = (char*)instance; char* ptr1; if ((long)ptr0 & tag_mask) { long slot = ((long)ptr0 >> tag_slot_shift) & tag_slot_mask; ptr1 = (char*)objc_debug_taggedpointer_classes[slot]; // struct objc_class pointer } else { ptr1 = *(char**)ptr0; // struct objc_class pointer i.e. instance isa } char* ptr2 = *((char**)(((long)ptr1 + 32) & ~class_fast_flag_mask)); // struct class_ro_t or struct class_rw_t pointer uint32_t flags = *((uint32_t*)ptr2); // struct class_ro_t or struct class_rw_t flags char* ptr3; if ((flags & rw_realized) || (flags & rw_future)) { ptr3 = *((char**)((long)ptr2 + 8)); // struct class_ro_t pointer struct class_rw_t pointer } else { ptr3 = ptr2; // struct class_ro_t pointer same struct class_rw_t pointer } const char* name = *((char**)((long)ptr3 + 24)); // name string pointer struct class_ro_t pointer return name; }
which in dtrace becomes in example script logs obj-c objects creation & destruction:
#!/usr/bin/env dtrace -s #pragma d option quiet pid$target:libobjc.a.dylib:class_createinstance:entry { ptr1 = *(long*)copyin(arg0, 8); /* arg0 class pointer */ ptr2 = *(long*)copyin((ptr1 + 32) & ~3, 8); flags = *(int*)copyin(ptr2, 4); ptr3 = (flags & (1 << 31)) || (flags & (1 << 30)) ? *(long*)copyin(ptr2 + 8, 8) : ptr2; ptr4 = *(long*)copyin(ptr3 + 24, 8); self->class = copyinstr(ptr4); } pid$target:libobjc.a.dylib:class_createinstance:return { printf("[+] %s = %p\n", self->class, arg1); /* arg1 instance pointer */ self->class = 0; } pid$target:libobjc.a.dylib:object_dispose:entry /arg0 != 0/ { ptr0 = *(long*)copyin(arg0, 8); /* arg0 instance pointer */ ptr1 = *(long*)copyin(ptr0, 8); /* todo: handle tagged pointers */ ptr2 = *(long*)copyin((ptr1 + 32) & ~3, 8); ptr3 = (flags & (1 << 31)) || (flags & (1 << 30)) ? *(long*)copyin(ptr2 + 8, 8) : ptr2; ptr4 = *(long*)copyin(ptr3 + 24, 8); class = copyinstr(ptr4); printf("[-] %s = %p\n", class, arg0); }
important dtrace script not handle tagged pointers. sure set environment variable "dyld_shared_region=avoid" when using script explained here.
Comments
Post a Comment