xcode 如何在 LLDB for iOS 中找到堆栈跟踪的地址
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18112842/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I find the address of a stack trace in LLDB for iOS
提问by Skotch
When I get a crash report, the offending part of my code will sometimes look like this, instead of showing me the actual line number, even though the crash report is symbolicated:
当我收到崩溃报告时,我的代码中的违规部分有时看起来像这样,而不是向我显示实际的行号,即使崩溃报告是符号化的:
-[ViewController myMethod:] + 47
In order to debug this, I need to know what line of my code this represents so that I can visually inspect it, set a breakpoint, etc.
为了调试这个,我需要知道这代表我的代码的哪一行,以便我可以直观地检查它,设置断点等。
What is a good way to get the address of a method plus offset, as shown above, using LLDB?
如上所示,使用 LLDB 获取方法地址加偏移量的好方法是什么?
NOTE: this question is NOT a duplicate of how to read a crash report. I know how to read a crash report. I am asking very specifically how to get the corresponding line using LLDB. Nothing in the other answers shows how to do that. They are quite verbose and go into all kinds of things about dealing with crash reports and debugging in general, but don't show what the specific steps on LLDB are. Please do not duplicate this bug.
注意:这个问题不是如何阅读崩溃报告的重复。我知道如何阅读崩溃报告。我非常具体地询问如何使用 LLDB 获取相应的行。其他答案中没有任何内容显示如何做到这一点。它们非常冗长,涉及处理崩溃报告和一般调试的各种事情,但没有显示 LLDB 上的具体步骤是什么。请不要复制此错误。
回答by Skotch
Here is something I found that worked:
这是我发现有效的方法:
First you need to find the address of the method itself.
首先你需要找到方法本身的地址。
image lookup -v -F "-[ViewController myMethod:]"
in the result you will see a lot of info, but the range part will give you want you want
在结果中你会看到很多信息,但范围部分会给你想要的
... range = [0x000708c0-0x00070c6c) ...
(where 0x000708c0 is address of method)
(其中 0x000708c0 是方法的地址)
Now to add the given offset of 47, just use LLDB to do that math for you:
现在要添加给定的偏移量 47,只需使用 LLDB 为您计算:
(lldb) p/x 0x000708c0 + 47
(int) (lldb) source list -a `0x000708c0 + 47`
= 0x000708ef
and you get your answer, the offending line is on 0x000708ef
然后你得到你的答案,违规行在 0x000708ef
Or better yet, based on Jason Molenda's answer, is to just go straight to the code listing, which will show the line number:
或者更好的是,根据 Jason Molenda 的回答,直接转到代码清单,它会显示行号:
(lldb) so l -a `addr + offset`
EDIT: improved based on the answer from Jason Molenda
编辑:根据 Jason Molenda 的回答进行改进
回答by Jason Molenda
Your steps (image lookup
+ p/x addr + offset
) will give you the raw address, as you found. But the original crash report probably included an address before the method + offset --- it is just as easy to slide your binary to the correct address using target modules load
. At the end of the crash report there should be a list of the binary images present in the program, including load address and UUID.
您的步骤 ( image lookup
+ p/x addr + offset
) 将为您提供原始地址,如您所见。但是最初的崩溃报告可能在方法 + 偏移量之前包含了一个地址——使用target modules load
. 在崩溃报告的末尾应该有一个程序中存在的二进制图像的列表,包括加载地址和 UUID。
But more importantly, while the address is nice what you're really after is the source location. In that case, once you've determined the correct address for the method (or slid it to the matching address via target modules load
), you can use source list
但更重要的是,虽然地址很好,但您真正想要的是源位置。在这种情况下,一旦您确定了该方法的正确地址(或通过 将其滑动到匹配的地址target modules load
),您就可以使用source list
(lldb) so l -a addr+offset
I'm using the backtick notation here which does an in-line expression evaluation. There's a handy shortcut for most commands that take an address: if you omit spaces, you can write the expression without backticks:
我在这里使用反引号表示法进行内联表达式评估。对于大多数需要地址的命令,有一个方便的快捷方式:如果省略空格,则可以编写不带反引号的表达式:
(lldb) im loo -v -a addr+offset
You can also use image lookup
with an address. If you have debug information, this will tell you what the current location of variables are at this point. Why is this useful? Because most crash reports include the register context at crash and so any variables that are currently in a register are provided to you (-v
is necessary to get all of the register location information).
您也可以使用image lookup
地址。如果您有调试信息,这将告诉您此时变量的当前位置。为什么这很有用?因为大多数崩溃报告都包含崩溃时的寄存器上下文,所以当前在寄存器中的任何变量都会提供给您(这-v
是获取所有寄存器位置信息所必需的)。
(lldb) so l -a (char*)main+10
Finally -- this isn't going to work because you're dealing with an Objective-C method name -- but with a simple C function name you can do the offset arithmetic in-line as long as you cast the function name to a pointer type (it's not legal C to add an offset to a function pointer). e.g.
最后——这不会起作用,因为您正在处理一个 Objective-C 方法名称——但是使用一个简单的 C 函数名称,只要您将函数名称转换为指针类型(将偏移量添加到函数指针是不合法的 C)。例如
lldb -arch ARCH Products/Applications/APPNAME.app/APPNAME
回答by Louis Semprini
[note this ONLY works if you save Archives in XCode of all the builds you released]
[请注意,这仅适用于将档案保存在您发布的所有构建的 XCode 中]
Information you need to collect first:
您首先需要收集的信息:
- APPNAME: the short name of your app as seen in the Archive directory (typically the XCode Target name; you will see it immediately when you look at the Archive directory in Finder below).
- CRASHING_FUNCTION_NAME: name of function shown in useless Apple backtrace (in the OP's example,
-[ViewController myMethod:]
) - ARCH: architecture of device that crashed. Most likely the right value is either
armv7
orarm64
. If you don't know, try both.
- APPNAME:在存档目录中看到的应用程序的短名称(通常是 XCode 目标名称;当您在下面的 Finder 中查看存档目录时,您会立即看到它)。
- CRASHING_FUNCTION_NAME:无用的 Apple 回溯中显示的函数名称(在 OP 的示例中,
-[ViewController myMethod:]
) - ARCH:崩溃的设备架构。最有可能的正确值是
armv7
或arm64
。如果您不知道,请尝试两者。
Ok here are the steps:
好的,这里是步骤:
- In XCode go to Window...Organizer...Archives
- Right-click on the Archive for the release the crashing user has, and choose Show in Finder
- open a Terminal shell and
cd
to that directory shown in Finder execute the following in the shell:
(lldb) add-dsym dSYMs/APPNAME.app.dSYM/Contents/Resources/DWARF/APPNAME (lldb) disassemble --name CRASHING_FUNCTION_NAME
inside lldb do the following:
APPNAME[0xf4a7c] <+47>: ldr r0, [r0, r1]
you now see a rich disassembly with symbols, and lo and behold, each line shows the same decimal offset as the original useless Apple backtrace (in the OPs example, the useless offset was
47
), as in:(lldb) image lookup -v --address 0xf4a7c
you might be able to figure out the corresponding source line just from this information, if the disassembly has enough symbols to help you figure out where you are.
if not, there is another great trick. Pass the address of the line that crashed:
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
Now
lldb
shows you a rich collection of information---much richerthan what is shown by Apple stack backtraces even when they do contain line numbers, and much richer than lldbsource list
---about all the source lines that contributed to the assembler instruction at that address. Pay close attention to both theSummary
andLineEntry
sections. Example:lldb -arch ARCH Products/Applications/APPNAME.app/APPNAME
In this example under
Summary
, we can see that the line that crashed was actually a combination of code frommyclass::myfunc()
,myinlinefunc()
andstd::deque::operator[]
. This kind of mashing together is very common for optimized code. This is often enough information to find the offending source line of your code. UnderLineEntry
we see the line number for the most-nested code contributing to that assembler line, which in this case is in the STLstd::deque
code, but in other cases might be the exact line number you want in your code.Now the only remaining question is: why on earthdoesn't Apple just do this for us in the original backtrace? They clearly have all this information themselves! Why do they make us jump through such hoops? What are they hiding?
- 在 XCode 中,转到 Window...Organizer...Archives
- 右键单击崩溃用户所拥有的版本的存档,然后选择在 Finder 中显示
- 打开终端外壳并
cd
进入 Finder 中显示的目录 在 shell 中执行以下命令:
(lldb) add-dsym dSYMs/APPNAME.app.dSYM/Contents/Resources/DWARF/APPNAME (lldb) disassemble --name CRASHING_FUNCTION_NAME
在 lldb 中执行以下操作:
APPNAME[0xf4a7c] <+47>: ldr r0, [r0, r1]
您现在可以看到带有符号的丰富反汇编,瞧,每行都显示与原始无用 Apple 回溯相同的十进制偏移量(在 OP 示例中,无用偏移量为
47
),如下所示:(lldb) image lookup -v --address 0xf4a7c
如果反汇编中有足够的符号来帮助您找出您所在的位置,您也许可以仅从这些信息中找出相应的源代码行。
如果没有,还有另一个绝妙的技巧。传递崩溃行的地址:
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
现在
##代码##lldb
向您展示丰富的信息集合——比 Apple 堆栈回溯显示的内容丰富得多,即使它们确实包含行号,也比 lldb 丰富得多source list
——关于当时对汇编指令有贡献的所有源代码行地址。密切关注Summary
和LineEntry
部分。例子:在下面的这个例子中
Summary
,我们可以看到崩溃的行实际上是来自myclass::myfunc()
,myinlinefunc()
和的代码的组合std::deque::operator[]
。这种混合在一起对于优化代码来说很常见。这通常足以找到有问题的代码行。在下面LineEntry
我们看到了对汇编行有贡献的嵌套最多的代码的行号,在这种情况下是在 STLstd::deque
代码中,但在其他情况下可能是您想要的代码中的确切行号。现在唯一剩下的问题是:为什么在地球上没有苹果只是做了我们原来的回溯?他们自己显然拥有所有这些信息!为什么他们让我们跳过这样的圈套?他们在隐瞒什么?