我正在使用dtrace在我的代码中打印所有objc_msgSend。到目前为止我已经完成了我可以看到选择器的名称,但我无法获得正确的类名。
这是我的dtrace脚本:
#!/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));
}
我假设 id 接收者对象属于以下结构:
typedef struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
char *name;
...
}
在我的脑海中,为了达到名称,必须移动指针2 * sizeof(objc_class *),它使得16,并且我们得到大小为8的名称的指针。因此我希望看到类名但是我得到了一些垃圾。
我做错了什么想法?
我的系统是Mavericks x64。
答案 0 :(得分:3)
围绕Obj-C runtime source code for 64 bit architecture和" objc-private.h"文件,这是"公式"从类指针获取类名:
#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 for 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 from struct class_rw_t pointer
} else {
ptr3 = ptr2; // struct class_ro_t pointer same as struct class_rw_t pointer
}
const char* name = *((char**)((long)ptr3 + 24)); // Name string pointer from struct class_ro_t pointer
return name;
}
在dtrace中,在此示例脚本中记录Obj-C对象创建&amp;破坏:
#!/usr/bin/env dtrace -s
#pragma D option quiet
pid$target:libobjc.A.dylib:class_createInstance:entry
{
ptr1 = *(long*)copyin(arg0, 8); /* arg0 is 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 is instance pointer */
self->class = 0;
}
pid$target:libobjc.A.dylib:object_dispose:entry
/arg0 != 0/
{
ptr0 = *(long*)copyin(arg0, 8); /* arg0 is 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);
}
重要此dtrace脚本无法处理tagged pointers。还要确保设置环境变量&#34; DYLD_SHARED_REGION = avoid&#34;在使用此脚本时,如here所述。