如何在 DTrace 操作中打印 CFStringRef?

Posted

技术标签:

【中文标题】如何在 DTrace 操作中打印 CFStringRef?【英文标题】:How do I print a CFStringRef in a DTrace action? 【发布时间】:2009-09-11 22:46:57 【问题描述】:

我有一个 DTrace 探针来捕获对函数的调用,该函数的参数之一是 CFStringRef。这是一个私有结构,它包含一个指向 unicode 字符串的指针。但是CFStringRef 本身并不是char*,所以像copyinstr() 这样的普通DTrace 方法只会返回?cp?,这并不完全有帮助。

那么如何在 DTrace 动作中打印出字符串呢?

【问题讨论】:

【参考方案1】:

据我所知,这种东西没有内置支持。通常,图书馆会发布一个为您解码字符串的探测器(正如布拉德提到的那样)。因此,由于在您的情况下您无法修改库,因此您需要使用 pid 提供程序并挂钩到用户函数,然后自己对其进行解码。

解决方案(这与您在 C++ 中转储std::string 所使用的方法非常相似)是转储存储在距基本CFStringRef 指针2 个字偏移处的指针。请注意,由于 CFString 可以在内部以各种格式和表示形式存储字符串,这可能会发生变化。

鉴于简单的测试应用程序:

#include <CoreFoundation/CoreFoundation.h>

int mungeString(CFStringRef someString)

    const char* str = CFStringGetCStringPtr(someString, kCFStringEncodingMacRoman);
    if (str)
        return strlen(str);
    else
        return 0;


int main(int argc, char* argv[])

    CFStringRef data = CFSTR("My test data");

    printf("%u\n", mungeString(data));

    return 0;

以下dtrace 脚​​本将打印第一个参数的字符串值,假设它是CFStringRef

#!/usr/sbin/dtrace -s

/*
    Dumps a CFStringRef parameter to a function,
    assuming MacRoman or ASCII encoding.
    The C-style string is found at an offset of
    2 words past the CFStringRef pointer.
    This appears to work in 10.6 in 32- and 64-bit
    binaries, but is an implementation detail that
    is subject to change.

    Written by Gavin Baker <gavinb.antonym.org>
*/

#pragma D option quiet

/* Uncomment for LP32 */
/* typedef long ptr_t; */
/* Uncomment for LP64 */
typedef long long ptr_t;

pid$target::mungeString:entry

    printf("Called mungeString:\n");
    printf("arg0 = 0x%p\n",arg0);

    this->str = *(ptr_t*)copyin(arg0+2*sizeof(ptr_t), sizeof(ptr_t));
    printf("string addr = %p\n", this->str);
    printf("string val  = %s\n", copyinstr(this->str));


输出会是这样的:

$ sudo dtrace -s dump.d -c ./build/Debug/dtcftest 
12
Called mungeString:
arg0 = 0x2030
string addr = 1fef
string val  = My test data

根据您是针对 32 位还是 64 位二进制文​​件运行,只需取消注释右侧的 typedef。我已经在 10.6 上针对这两种架构进行了测试,效果很好。

【讨论】:

使用这个程序和这个探测文件,我得到了一个大列表:dtrace: error on enabled probe ID 1 (ID 93815: pid11402:sc:mungeString:entry): invalid address (0x7c8 ) 在 DIF 偏移量 12 处的操作 #5 取出打印字符串的行,我看到所有字符串 addrs 都有点不寻常: Called mungeString: arg0 = 0x100001068 string addr = 7c8 添加第二个不同的常量字符串和 mungeString' ing 它,我得到两个字符串的相同字符串 addr。 好的,我可以从内存地址看出您必须使用 10.6 并构建 64 位应用程序。我在 10.5 上编写了测试应用程序(很匆忙!),因为这是我当时可以访问的所有内容。我应该使用 sizeof(intptr_t) 使 DTrace 脚本中的偏移量成为中性(而不是硬编码 8,现在在 64 位应用程序中为 16)。我去看看 10.6 的机器。 @TALlama 请尝试上面的更新脚本。我在 32 位和 64 位二进制文​​件上都对其进行了测试,它运行良好。 我发现在 10.6 上运行 64 位内核时,您需要使用 'typedef int ptr_t'(int 而不是 long),因为 long 会根据 32 位和 64 位内核改变大小。 wikis.sun.com/display/DTrace/…【参考方案2】:

我相信您不能直接执行此操作,但您可以创建一个自定义静态探针,将 CFString / NSString 作为 char * 提供,您可以将其与 copyinstr() 一起使用。我在一篇文章 here 中描述了如何做到这一点。

【讨论】:

不幸的是,我正在尝试使用它来探测一些我无法控制的编译代码,因此无法更改源代码。

以上是关于如何在 DTrace 操作中打印 CFStringRef?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 dtrace 打印 libstdc++ 字符串内容

dtrace:如何从文件中获取符号链接目标

从 C 程序访问 dtrace 探针

dtrace 仅在函数返回特定模块时执行操作

将 NSString 存储在 NSDIctionary 中时,变量不是 CFString

如何在 dtrace 中找到参数的意思