DTracing objc_msgSend不会打印接收器类名

时间:2014-03-06 08:27:00

标签: c++ objective-c c debugging dtrace

我正在使用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。

1 个答案:

答案 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所述。