c++ - DTracing objc_msgSend 不打印接收者类名

标签 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。

最佳答案

在搜索 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;
}

在这个记录 Obj-C 对象创建和销毁的示例脚本中,dtrace 变成了:

#!/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 .还请务必在使用此脚本时设置环境变量“DYLD_SHARED_REGION=avoid”,如说明 here .

关于c++ - DTracing objc_msgSend 不打印接收者类名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22218920/

相关文章:

c++ - ffmpeg API编码mpeg-4 Windows Media Player错误

c++ - C++如何读取特定的第一个字符并保存数据

java - "If"语句,常量相等

java - Java 和 C 应用程序之间的 IPC

c - 使用 make 命令获取字符串输入以用作 C 程序中的主要参数

c++ - 如何使用 JSON-CPP?

ios - 禁用 UISearchBar

objective-c - 更改 NSDatePicker 的默认突出显示颜色

iphone - 如何使 'int'到 'string'具有特殊格式?

c - 在 Visual Studio 2010 中编译 C WinSock 代码时出现结构重复错误