如何在LLDB for iOS中找到堆栈跟踪的地址

Sko*_*tch 11 xcode ios lldb

当我收到崩溃报告时,我的代码中有问题的部分有时看起来像这样,而不是向我显示实际的行号,即使崩溃报告是象征性的:

-[ViewController myMethod:] + 47  
Run Code Online (Sandbox Code Playgroud)

为了调试这个,我需要知道我代码的代码行,以便我可以直观地检查它,设置断点等.

如上所示,使用LLDB获取方法地址加偏移的好方法是什么?

注意:此问题与如何阅读崩溃报告不重复.我知道如何阅读崩溃报告.我非常具体地询问如何使用LLDB获取相应的行.其他答案中没有任何内容显示如何做到这一点.它们非常冗长,并且涉及一般处理崩溃报告和调试的各种事情,但没有说明LLDB的具体步骤是什么.请不要复制此错误.

Jas*_*nda 7

您找到的步骤(image lookup+ p/x addr + offset)将为您提供原始地址.但是原始的崩溃报告可能包含了方法+偏移之前的地址---将二进制文件滑动到正确的地址同样容易target modules load.在崩溃报告结束时,应该有一个程序中存在的二进制映像列表,包括加载地址和UUID.

但更重要的是,虽然地址很好,但你真正追求的是源位置.在这种情况下,一旦您确定了方法的正确地址(或通过它将其滑动到匹配的地址target modules load),您就可以使用source list

(lldb) so l -a `addr + offset`
Run Code Online (Sandbox Code Playgroud)

我在这里使用反引号表示法进行内联表达式评估.对于大多数带有地址的命令,有一个方便的快捷方式:如果省略空格,则可以编写没有反引号的表达式:

(lldb) so l -a addr+offset
Run Code Online (Sandbox Code Playgroud)

您也可以使用image lookup地址.如果您有调试信息,这将告诉您此时变量的当前位置.为什么这有用?因为大多数崩溃报告都包含崩溃时的寄存器上下文,因此当前在寄存器中的任何变量都会提供给您(这-v是获取所有寄存器位置信息所必需的).

(lldb) im loo -v -a addr+offset
Run Code Online (Sandbox Code Playgroud)

最后 - 这不会起作用,因为你正在处理一个Objective-C方法名称 - 但是只要你将函数名称强制转换为一个简单的C函数名,就可以在线进行偏移算术运算.指针类型(向函数指针添加偏移量不是合法的C).例如

(lldb) so l -a (char*)main+10
Run Code Online (Sandbox Code Playgroud)


Sko*_*tch 6

以下是我发现的有效方法:

首先,您需要找到方法本身的地址.

image lookup -v -F "-[ViewController myMethod:]"
Run Code Online (Sandbox Code Playgroud)

在结果中你会看到很多信息,但范围部分会给你想要的

... range = [0x000708c0-0x00070c6c) ...
Run Code Online (Sandbox Code Playgroud)

(其中0x000708c0是方法的地址)

现在要添加47的给定偏移量,只需使用LLDB为您做数学运算:

(lldb) p/x 0x000708c0 + 47
(int) $0 = 0x000708ef
Run Code Online (Sandbox Code Playgroud)

你得到答案,违规行在0x000708ef

或者更好的是,基于Jason Molenda的答案,就是直接进入代码清单,它将显示行号:

(lldb) source list -a `0x000708c0 + 47`
Run Code Online (Sandbox Code Playgroud)

编辑:基于杰森莫伦达的答案改进


Lou*_*ini 5

[请注意,仅当您将发布的所有内部版本的存档保存在XCode中时,此选项才有效]

您需要首先收集的信息:

  • APPNAME:在“存档”目录中看到的应用程序的简称(通常是XCode目标名称;当您在下面的Finder中查看“存档”目录时,会立即看到它)。
  • CRASHING_FUNCTION_NAME:在无用的Apple backtrace中显示的功能名称(在OP的示例中为-[ViewController myMethod:]
  • ARCH:崩溃的设备的体系结构。正确的值很可能是armv7arm64。如果您不知道,请同时尝试。

好的,这里是步骤:

  1. 在XCode中,转到Window ... Organizer ... Archives
  2. 右键单击“存档”以获取崩溃用户拥有的版本,然后选择“在Finder中显示”
  3. 打开终端外壳并cd转到Finder中显示的目录
  4. 在shell中执行以下命令:

    lldb -arch ARCH Products/Applications/APPNAME.app/APPNAME
    
    Run Code Online (Sandbox Code Playgroud)
  5. 在lldb中执行以下操作:

    (lldb) add-dsym dSYMs/APPNAME.app.dSYM/Contents/Resources/DWARF/APPNAME
    
    (lldb) disassemble --name CRASHING_FUNCTION_NAME
    
    Run Code Online (Sandbox Code Playgroud)
  6. 现在,您将看到带有符号以及lo和beshed的丰富反汇编,每一行显示的小数偏移量与原始的无用Apple回溯记录相同(在OPs示例中,无用偏移量为47),如下所示:

    APPNAME[0xf4a7c] <+47>:  ldr    r0, [r0, r1]
    
    Run Code Online (Sandbox Code Playgroud)
  7. 如果反汇编有足够的符号来帮助您确定您的位置,则您可能可以仅从此信息中找到相应的源代码行。

  8. 如果没有,那还有另一个绝招。传递崩溃的行的地址:

    (lldb) image lookup -v --address 0xf4a7c
    
    Run Code Online (Sandbox Code Playgroud)
  9. 现在lldb向您展示丰富的信息集-关于Apple堆栈回溯所显示的内容,即使它们确实包含行号,也要比Apple堆栈回溯所显示的信息要丰富得多,并且比lldb还要丰富source list-关于该处汇编程序指令的所有源代码行地址。请同时注意SummaryLineEntry部分。例:

    Address: APPNAME[0x000f4a7c] (APPNAME.__TEXT.__text + 963740)
    Summary: APPNAME`myclass::myfunc(bool, bool) + 904 [inlined] std::__1::deque<mystruct, std::__1::allocator<mystruct> >::operator[](unsigned long) + 22 at myfile.cpp:37945
             APPNAME`myclass::myfunc(bool, bool) + 882 [inlined] myinlinefunc(int) + 14 at myfile.cpp:65498
             APPNAME`myclass::myfunc(bool, bool) + 868 at myfile.cpp:65498
    Module: file = "/Users/myuser/mydir/arch/Products/Applications/APPNAME.app/APPNAME", arch = "armv7"
    CompileUnit: id = {0x000483a4}, file = "/Users/myuser/mydir/myfile.cpp", language = "objective-c++"
    Function: id = {0x0045edde}, name = "myfunc", range = [0x000f46f4-0x000f572a)
    FuncType: id = {0x0045edde}, decl = myfile.cpp:65291, compiler_type = "void (_Bool, _Bool)"
    Blocks: id = {0x0045edde}, range = [0x000f46f4-0x000f572a)
            id = {0x0045f7d8}, ranges = [0x000f4936-0x000f51c0)[0x000f544c-0x000f5566)[0x000f5570-0x000f5698)
            id = {0x0046044c}, ranges = [0x000f49c6-0x000f49ce)[0x000f49d6-0x000f49d8)[0x000f4a2e-0x000f4a38)[0x000f4a58-0x000f4a82), name = "myinlinefunc", decl = myfile.cpp:37938, mangled = _Z11myinlinefunci, demangled = myinlinefunc(int)
            id = {0x00460460}, ranges = [0x000f4a58-0x000f4a64)[0x000f4a66-0x000f4a82), name = "operator[]", decl = deque:1675, mangled = _ZNSt3__15dequeI12mystructNS_9allocatorIS1_EEEixEm, demangled = std::__1::deque<mystruct, std::__1::allocator<mystruct> >::operator[](unsigned long)
    LineEntry: [0x000f4a7c-0x000f4a82): /Applications/Xcode7.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/deque:1678:14
    Symbol: id = {0x00000805}, range = [0x000f46f4-0x000f572a), name="myclass::myfunc(bool, bool)", mangled="_ZN7myclass7myfuncEbb"
    Variable: id = {0x00460459}, name = "myvar1", type = "int", location =     , decl = myfile.cpp:37938
    Variable: id = {0x0045f7dd}, name = "myvar2", type = "bool", location =  , decl = myfile.cpp:65583
    Variable: id = {0x0045edf2}, name = "this", type = "myclass *", location =  [sp+56], decl =
    Variable: id = {0x0045ee01}, name = "myvar3", type = "bool", location = , decl = myfile.cpp:65291
    Variable: id = {0x0045ee0e}, name = "myvar4", type = "bool", location = , decl = myfile.cpp:65292
    
    Run Code Online (Sandbox Code Playgroud)
  10. 在这个例子中下Summary,我们可以看到失事线实际上是从代码组合myclass::myfunc()myinlinefunc()std::deque::operator[]。这种混在一起对于优化代码非常普遍。通常,这些信息足以找到您的代码中有问题的源代码行。在下面,LineEntry我们看到了最有助于该汇编程序行的代码的行号,在这种情况下,此std::deque行号在STL 代码中,但在其他情况下,可能是您想要的代码中的确切行号。

  11. 现在唯一剩下的问题是:为什么在地球上没有苹果只是做了我们原来的回溯?他们自己显然拥有所有这些信息!为什么它们使我们跳入这种困境?他们隐藏了什么?

  • 这是非常有用的答案!谢谢你!我怎样才能快速使用它?`disassemble —name SwiftClass.foo()` 表示“无法找到名称为 ... 的符号” (3认同)