如何在 Objective-C 中使用符号断点获取参数

Posted

技术标签:

【中文标题】如何在 Objective-C 中使用符号断点获取参数【英文标题】:How to get parameters using symbolic breakpoints in Objective-C 【发布时间】:2013-03-08 22:15:37 【问题描述】:

我有一个看起来像这样的断点

-[UITableViewCell setSelected:]

它可以工作,但我不知道如何获取传入的值。

我尝试过-[UITableViewCell setSelected:(BOOL)what]-[UITableViewCell setSelected:what],它们根本不起作用。

如何访问参数?

如果这不起作用,我将不得不创建一个DebugUITableViewCell 以查看发生了什么,这很麻烦并且涉及很多代码。

【问题讨论】:

我没有足够的勇气发布这个真正的答案,因为我只是在猜测,但我相信调试器无法使用需要。你没有得到 UIKit 的符号,所以调试器不知道该方法的参数名称是什么。运行时可能能够确定它的类型,但它与拥有真正的符号信息不同。我猜你的子类技巧有效,因为你还提供该符号信息到调试器。 我以完全相同的方法得出了这个问题——甚至没有在搜索查询中包含方法名称。表视图确实是一个谜,5 年后更是如此! ???? 【参考方案1】:

如果您在设备上调试代码,当您遇到断点时的参数将始终位于寄存器 r0、r1 和 r2 中。如果您使用po $r0,您将看到对象接收setSelected。如果您使用po $r1,您将得到“没有可用的Objective-C 描述”,因为那是选择器。检查 $r2 以查看 selected 是否设置为 YES 或 NO。在 i386 上也有类似的故事,但我不记得使用了哪些寄存器。

【讨论】:

@darren 我在发布我的答案之前用 lldb 对此进行了测试,但是是什么让你认为它不起作用? 它可以与 lldb 一起正常工作。事实上,在 lldb 中它甚至更好,因为(对于在寄存器中传递参数的架构,如 arm 和 x86_64)$arg0$arg1 等提供了该架构的正确寄存器的别名。 在 lldb 中访问以 $arg1 开头的参数。对于方法调用,第一个用户参数是 $arg3;因此,如果第一个方法参数是 NSString,只需 po $arg3 即可显示它。 尝试记录 CGPoint 参数,但 p (CGPoint)$arg3 不起作用。 我也无法让po $arg0 在 lldb 中工作。在 x86_64 和 arm64 上都试过了。【参考方案2】:

在模拟器上的 LLDB 中使用

p $arg3

为第一个参数。

【讨论】:

【参考方案3】:

您可以将-[UITableViewCell setSelected:] 替换为您自己的实现以进行调试。下面,UITableViewCellSetSelected 将被调用,而不是 UIKit 的方法。

static void (*__originalUITableViewCellSetSelected)( UITableViewCell *, SEL, BOOL ) ;
static void UITableViewCellSetSelected( UITableViewCell * self, SEL _cmd, BOOL b )

    // your code here... (or set a breakpoint here)
    NSLog(@"%@<%p> b=%s\n", [ self class ], self, b ? "YES" : "NO" ) ;

    (*__originalUITableViewCellSetSelected)( self, _cmd, b ) ; // call original implementation:


@implementation UITableViewCell (DebugIt)

+(void)load

    Method m = class_getInstanceMethod( [ self class ], @selector( setSelected: ) ) ;
    __originalUITableViewCellSetSelected = (void(*)(id, SEL, BOOL))method_getImplementation( m ) ;
    method_setImplementation( m, (IMP)UITableViewCellSetSelected ) ;


@end

【讨论】:

尽管对于快速解决方案@aaron 的回答很好。我将把它留在这里以供参考...... 我想我可能会接受 Aaron 的回答,因为它更准确,但这也很棒。谢谢!【参考方案4】:

对于没有源代码的方法,以下工作: 放置一个符号断点,以便调试器在方法的第一行停止。确保选择了顶部堆栈帧。那么:

在 Objectice-C 方法中

po $arg1 打印自我 po $arg3 打印第一个参数,$arg4$arg5 等中的剩余参数。

在 C 函数中,参数从 $arg1 开始

这适用于 ios 设备和模拟器。

【讨论】:

$arg1 等仅适用于 64 位模拟器。对于将转换为 x/x $esp4x/x $esp+8 等的旧版 x86 32 位,请参阅 ***.com/a/48734614/5329717【参考方案5】:

基于-[UIApplication sendAction:toTarget:fromSender:forEvent:]符号我们可以添加符号断点来检查哪个发送者向哪个目标发送了一个动作。

我们创建符号断点:

符号:-[UIApplication sendAction:toTarget:fromSender:forEvent:] 调试器命令行操作: po "Target" po $arg4 po "Sender" po $arg5

输出将是: "Target" <project.TargetViewController: 0x14ddb1470> "Sender" <UIButton: 0x14de86000; frame = (331 7; 49 30); opaque = NO; layer = <CALayer: 0x174237020>>

正如@Dan 所说,方法参数以参数 3 (po $arg3) 开头。

【讨论】:

【参考方案6】:

你可以使用 lldb 命令:

“图片查找-rn关键字”

关键字等于您要搜索的功能,例如,显示

然后,你会看到如下输出,

总结:ApplSlate`closure #2 (__C.UIBarButtonItem) -> () in ApplSlate.BaseTableViewController.showLoading(includeTabBar: Swift.Bool) -> () at BaseTableViewController.swift:98 地址:FullSlate[0x0000000100154a60] (FullSlate .__TEXT.__文本 + 1378752)

你得到的符号名称是:closure #2 (__C.UIBarButtonItem) -&gt; () in ApplSlate.BaseTableViewController.showLoading(includeTabBar: Swift.Bool) -&gt; ()

【讨论】:

以上是关于如何在 Objective-C 中使用符号断点获取参数的主要内容,如果未能解决你的问题,请参考以下文章

Objective-c中的点符号

如何解决“当前不会命中断点。没有为此文档加载任何符号。”警告?

Ruby 符号的 Objective-C 等价物

如何在 Objective-C 中获取用户的语言环境?

在 Xcode 中对子类使用符号断点?

使用 Objective-C++ 时单元测试未解析的符号