我怎样才能findiOS的LLDB堆栈跟踪的地址

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

-[ViewController myMethod:] + 47 

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

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

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

你的步骤( image lookup + p/x addr + offset )会给你的原始地址,你发现。 但是最初的崩溃报告可能在方法+偏移之前包含了一个地址—使用target modules load将二进制文件滑动到正确的地址也同样容易。 在崩溃报告结束时,程序中应该有一个二进制映像列表,包括加载地址和UUID。

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

 (lldb) so l -a `addr + offset` 

我在这里使用反向表示法来进行在线expression式评估。 对于大多数需要地址的命令来说,有一个方便的快捷方式:如果你省略空格,你可以在没有反引号的情况下编写expression式:

 (lldb) so l -a addr+offset 

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

 (lldb) im loo -v -a addr+offset 

最后 – 这不会起作用,因为你正在处理一个Objective-C方法的名字 – 但是用一个简单的C函数名,只要你把函数名转换为指针types(向函数指针添加偏移量不合法C)。 例如

 (lldb) so l -a (char*)main+10 

这是我发现的工作:

首先你需要find方法本身的地址。

 image lookup -v -F "-[ViewController myMethod:]" 

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

 ... range = [0x000708c0-0x00070c6c) ... 

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

现在添加给定的偏移量47,只需使用LLDB为你做这个math:

 (lldb) p/x 0x000708c0 + 47 (int) $0 = 0x000708ef 

你得到你的答案,有问题的行是在0x000708ef

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

 (lldb) source list -a `0x000708c0 + 47` 

编辑:根据Jason Molenda的回答改进

[注意这只适用于如果你保存在XCode存档的所有版本发布]

您需要先收集的信息:

  • APPNAME :在Archive目录中看到的应用程序的短名称(通常是XCode目标名称;当您在下面的Finder中查看Archive目录时,您将立即看到它)。
  • CRASHING_FUNCTION_NAME :在无用的苹果回溯中显示的函数的名字(在OP的例子中, -[ViewController myMethod:]
  • ARCH :崩溃的设备的体系结构。 最有可能的正确值是armv7arm64 。 如果你不知道,试试两个。

好的,这里的步骤是:

  1. 在XCode去窗口…组织者…档案
  2. 用鼠标右键单击崩溃用户所发布的存档,然后select在Finder中显示
  3. 打开一个terminalshell并cd到Finder中显示的那个目录
  4. 在shell中执行以下命令:

     lldb -arch ARCH Products/Applications/APPNAME.app/APPNAME 
  5. 在lldb里面做下面的事情:

     (lldb) add-dsym dSYMs/APPNAME.app.dSYM/Contents/Resources/DWARF/APPNAME (lldb) disassemble --name CRASHING_FUNCTION_NAME 
  6. 你现在看到一个带有符号的丰富的反汇编,你看,每行都显示与原来无用的苹果回溯相同的十进制偏移量(在OP的例子中,无用的偏移量是47 ),如下:

     APPNAME[0xf4a7c] <+47>: ldr r0, [r0, r1] 
  7. 如果反汇编有足够的符号来帮助你弄清楚你的位置,那么你可以从这些信息中找出相应的源代码行。

  8. 如果没有,还有一个很棒的窍门。 通过坠毁线路的地址:

     (lldb) image lookup -v --address 0xf4a7c 
  9. 现在, lldb向您显示了丰富的信息集合—比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 
  10. Summary下的这个例子中,我们可以看到崩溃的那一行实际上是来自myclass::myfunc()myinlinefunc()std::deque::operator[]的代码的组合。 这种混合在一起对于优化代码是很常见的。 这通常是足够的信息来find您的代码的有问题的源代码行。 在LineEntry我们看到了对于这个汇编代码最多的嵌套代码的行号,在这种情况下,这个代码位于STL std::deque代码中,但在其他情况下,可能是代码中的确切行号。

  11. 现在唯一剩下的问题是:苹果为什么不在原来的回溯中为我们做这件事? 他们显然拥有所有这些信息! 为什么他们让我们跳过这样的箍? 他们在隐藏什么?