我写了一个动作,当任何 objc 方法返回时触发(objc:::return)。现在,我需要获取返回值。可能吗?
1 回答
总而言之:不,您无法在 DTrace 探测器中获取 Objective-C 方法的返回值。
Bill Bumgarner 有一篇关于将消息追踪到 nil的帖子,其中他说:
Aside:
objc_msgSend()
的返回目前无法通过 dtrace 进行跟踪。鉴于该函数实际上并没有返回,这并不奇怪——就 dtrace 而言,它只不过是序言。
博客文章相当旧(2008 年 1 月),它使用 pid 提供程序,而不是 objc 提供程序。也就是说,它从 Mac OS X v10.7.1 开始仍然有效,并且也适用于 objc 提供程序。
有趣的是,它似乎有时会起作用,但这取决于 DTrace 何时读取 RAX 寄存器。由于objc_msgSend()
不返回,DTrace 最终使用 RAX 中由代码存储的值,这些代码不一定是被跟踪方法的返回值。
考虑以下代码:
NSNumber *n = [NSNumber numberWithInt:1234];
printf("n has address %p\n", n);
和以下探测:
objc$target:NSPlaceholderNumber:-initWithInt?:return
{
printf("Returning from -[NSPlaceholderNumber initWithInt:]\n");
printf("\treturn value = 0x%p\n", (void *)arg1);
}
使用 DTrace 运行时,我得到以下输出:
n has address 0x4d283
Returning from -[NSPlaceholderNumber initWithInt:]
return value = 0x4d283
所以看起来探测器能够捕获-initWithInt:
. 不过这只是运气,可能是由调用的函数(例如CFNumberCreate()
or CFMakeCollectable()
)引起的-initWithInt:
,最终将预期值放入 RAX 中。
现在考虑以下代码:
char *c = "hello";
NSData *data = [NSData dataWithBytes:c length:strlen(c)];
NSString *s = [[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding];
printf("s has address %p\n", s);
和以下探测:
objc$target:NSPlaceholderString:-initWithData?encoding?:return
{
printf("Returning from -[NSPlaceholderString initWithData:encoding:]\n");
printf("\treturn value = 0x%p\n", (void *)arg1);
}
使用 DTrace 运行时,我得到以下输出:
s has address 0x7fcd92414ea0
Returning from -[NSPlaceholderString initWithData:encoding:]
return value = 0x600
如您所见,地址(即返回值)不匹配。事实上,0x600 是 .Core kCFStringEncodingASCII
Foundation 对应的值NSASCIIStringEncoding
。在某些时候,方法或方法调用的函数将 0x600 移动到 RAX,这就是 DTrace错误地认为是返回值的值。