为 Objective-C 对象定义 DTrace 兼容结构

Posted

技术标签:

【中文标题】为 Objective-C 对象定义 DTrace 兼容结构【英文标题】:Define DTrace compatible structs for Objective-C objects 【发布时间】:2013-10-27 20:01:27 【问题描述】:

我正在尝试编写一个 DTrace 脚本,该脚本将向我显示传递给 -[NSURLConnection sendSynchronousRequest:returningResponse:error:] 的参数,但我找不到可用于从传入的 NSString 参数中提取字符串的结构。这个question 有一个适用于 OS X 应用程序的答案,但它不适用于我使用 ios 模拟器的应用程序。

虽然我正在寻找这个特定示例的解决方案,但我更感兴趣的是学习为任何给定的 Objective-C 对象定义/发现底层内存结构的最佳方法。正如您从我编写的 OS X 测试应用程序中看到的那样,NSString 参数并不总是将原始字符串数据放在同一个位置。在__NSCFString 的情况下,它似乎位于(以长度为前缀)的 16 个字节处。在__NSCFConstant 字符串的情况下,它位于其他地方,查看原始内存转储时不会立即明显。

如果系统标头中定义了结构,可以向我展示我正在寻找的内容,那将是很好的第一步,但我认为 LLDB 也应该能够向我展示有用的提示。

【问题讨论】:

【参考方案1】:

理论上,Class-dump 应该能够检查 Mach-O 文件并报告您的 Objective C 类的声明。

当我上次尝试使用 Class-dump 时,我没有成功;我不记得确切的原因,但我现在看到有一个可能的替代方案,即Hopper。不管怎样,看了Abusing the Objective C runtime的文章后,我用gdb检查了地址空间;与您不同,我使用 DTrace 在进入方法时停止进程,然后检查 arg2 寻址的内存。如果在您的情况下,您看不到合理的字符串,那么我建议您寻找指针并遵循它们。

请注意,您的问题使用了“DTrace 兼容”这一短语。这提出了一个有趣的观点:dtrace(1) 是一个编译器,它没有义务以与构建受害者相同的方式来打包结构。在 Solaris 上,dtrace(1) 符合给定平台的 ABI,无论是 SPARC 还是 x86。我没有调查它在 MacOS 上的行为,但它可能会有所不同,因此请记住这一点,尤其是当 dtrace 给您带来意想不到的结果时。

【讨论】:

【参考方案2】:

只要符合目标 c 运行时的公共定义,编译器几乎可以使用 ObjC 代码生成所有内容。

我认为你选择了错误的对象来开始你的研究:NSString(连同 NSNumber)有多个版本,根据你的使用情况选择。例如。您的编译时常量 NSString 可能表示为:

struct __builtin_NSString 
    const int *isa; // point to __NSConstantStringClassReference
    const char *str; // point to some byte array under __cfstring segment
    unsigned int length; // size of that byte array
;

您还可以通过检查 __cfstring 段来找到您的常量 NSString(或 CFString),例如通过 otool otool -s __DATA __cfstring.

我不知道有什么方法可以让您将任何 ObjC 对象反编译为 C-struct 形式。我的建议是通过反汇编程序来查看对象的各个字段是如何访问的。例如。您可以向属性的设置器和获取器添加断点。

如果您觉得舒服,您还可以研究负责将高级代码转换为中间(在基于 LLVM 的编译器的情况下)表示的编译器的源代码:CGObjCMac、CGObjC、CGObjCRuntime。

【讨论】:

以上是关于为 Objective-C 对象定义 DTrace 兼容结构的主要内容,如果未能解决你的问题,请参考以下文章

在 DTrace 输出中显示 Objective-C 类

Leopard 上的 DTrace:没有指定探针,即使我指定了探针

是否可以在 dtrace 中获取 objc 方法的结果?

Dtrace 没有为 NodeJS 收集任何数据

Objective-C 确定哪些对象保留另一个对象

将objective-c自定义对象序列化为OSX的JSON?