如何在 Xcode 中的方法调用的最开始设置断点,以便我可以检查 $rdi $rsi 等?

How to set breakpoint at the very beginning of a method call in Xcode so that I can check $rdi $rsi etc?

我想在方法调用的最开始设置断点,以便我可以检查它是 $rdi $rsi 等

在Xcode中,当我在方法调用say -[HelperClass doThingWithBlock:]处设置符号断点时,它停在方法体的第一行,这已经是开始后的几条指令了方法调用,如下面方法调用的反汇编所示。

DebugBlock`-[HelperClass doThingWithBlock:]:
        0x109844aa0 <+0>:  pushq  %rbp
        0x109844aa1 <+1>:  movq   %rsp, %rbp
        0x109844aa4 <+4>:  subq   [=11=]x30, %rsp
        0x109844aa8 <+8>:  leaq   -0x18(%rbp), %rax
        0x109844aac <+12>: movq   %rdi, -0x8(%rbp)
        0x109844ab0 <+16>: movq   %rsi, -0x10(%rbp)
        0x109844ab4 <+20>: movq   [=11=]x0, -0x18(%rbp)
        0x109844abc <+28>: movq   %rax, %rdi
        0x109844abf <+31>: movq   %rdx, %rsi
        0x109844ac2 <+34>: callq  0x109844c74               ; symbol stub for: objc_storeStrong
        0x109844ac7 <+39>: leaq   0x15a2(%rip), %rax        ; @"hi"
        0x109844ace <+46>: movl   [=11=]x16, %ecx
        0x109844ad3 <+51>: movl   %ecx, %edx
    ->  0x109844ad5 <+53>: movq   -0x18(%rbp), %rsi
        0x109844ad9 <+57>: movq   %rsi, %rdi
        0x109844adc <+60>: movq   %rsi, -0x20(%rbp)
        0x109844ae0 <+64>: movq   %rax, %rsi
        0x109844ae3 <+67>: movq   -0x20(%rbp), %rax
        0x109844ae7 <+71>: callq  *0x10(%rax)
        0x109844aea <+74>: xorl   %ecx, %ecx
        0x109844aec <+76>: movl   %ecx, %esi
        0x109844aee <+78>: leaq   -0x18(%rbp), %rdx
        0x109844af2 <+82>: movq   %rdx, %rdi
        0x109844af5 <+85>: movb   %al, -0x21(%rbp)
        0x109844af8 <+88>: callq  0x109844c74               ; symbol stub for: objc_storeStrong
        0x109844afd <+93>: addq   [=11=]x30, %rsp
        0x109844b01 <+97>: popq   %rbp
        0x109844b02 <+98>: retq

lldb 会在您有调试信息时将断点位置推进到函数中的第一个源代码行。这个想法是,大多数拥有源代码级别信息的人更感兴趣的是用他们的名字打印参数,而不是查看用于传递它们的寄存器。

如果您正在使用一个简单的 C 函数,您可以设置一个地址断点,将函数名计算为一个地址,例如

(lldb) br s -n main
Breakpoint 1: where = a.out`main + 11 at a.c:3, address = 0x0000000100000f8b
(lldb) br s -a `main`
Breakpoint 2: address = 0x0000000100000f80
(lldb) 

反引号 `` 将反引号中的表达式计算为 address/value。 breakpoint set --address 的工作方式与您预期的一样。

甚至还有一些内置的特殊魔法,您不需要反引号来处理需要地址的内容,例如 br s -a。您可以执行 br s -a main 并且它会起作用——作为一个非常特别的奖励,您可以在此处向函数添加偏移量,例如 br s -a main+5 通常不是有效的 C 表达式。

不幸的是,我们正在使用 objc 方法 -[HelperClass doThingWithBlock:],您不能像我对 main 那样将其作为表达式放入。我认为在这种情况下你需要自己找到它的地址,例如您可能会在开始时反汇编一条指令,例如 dis -c 1 -n '-[ViewController setRepresentedObject:]',然后将该地址输入 br s -a.

Jason 的建议适用于更复杂的问题,但这是一个很常见的要求,因此 break set 有一个选项专门用于控制将断点推过序言:

(lldb) break set -n main --skip-prologue 0