gpt4 book ai didi

ios - dSYM 地址查找

转载 作者:塔克拉玛干 更新时间:2023-11-02 10:08:56 25 4
gpt4 key购买 nike

我已经从一个 iOS 应用程序的 dSYM 文件中解析出地址、文件名和行号。我基本上有一个将地址映射到文件名和行号的表,这对调试很有帮助。

要获取实际查找地址,我使用崩溃报告中的堆栈跟踪地址并使用此答案中指定的公式:https://stackoverflow.com/a/13576028/2758234 .所以像这样。

(actual lookup address) 
= (stack trace address) + (virtual memory slide) - (image load address)

我使用该地址并在我的表格中查找它。我得到的文件名是正确的,但行号总是指向调用的函数或方法的末尾,而不是在堆栈跟踪中调用以下函数的实际行。

我在某处读到,不记得在哪里,帧地址必须被取消标记,因为它们对齐为系统指针大小的两倍。所以对于 32 位系统,指针大小是 4 个字节,所以我们使用 8 个字节去标记,使用如下公式:

(de-tagged address) = (tagged address) & ~(sizeof(uintptr_t)*2 - 1)

其中 uintptr_t 是 Objective-C 中用于指针的数据类型。

完成此操作后,查找工作正常,但我必须执行类似查找小于或等于去标记地址的最近地址 .

问题 #1:
为什么我必须取消标记堆栈帧地址?为什么堆栈跟踪中的地址没有指向正确的位置?

问题 2:
有时在崩溃报告中似乎缺少一个框架。例如,如果 function1() 调用 function2(),而 function3() 又调用 function4(),在我的堆栈跟踪中,我会看到如下内容:

0  Exception
1 function4()
2 function3()
4 function1()

function3()(上面的第 2 帧)的堆栈跟踪地址甚至没有指向正确的行号(但它是正确的文件),即使在 de-标记。即使当我让 Xcode 符号化崩溃报告时,我也会看到这一点。

为什么会这样?

最佳答案

对于问题 #1,iOS 崩溃报告中的地址包含三个要考虑的组成部分:应用的原始加载地址、应用启动时添加到该地址的随机幻灯片值,以及二进制文件中的偏移量。在崩溃报告的末尾,应该有一行显示二进制文件的实际加载地址。

要计算幻灯片,您需要从崩溃报告中获取实际加载地址并减去原始加载地址。这会告诉您应用到应用程序的这次特定启动的随机幻灯片值。

我不确定您的表格是如何得出的 - 问题可能就在那里。您可能需要使用 lldb 仔细检查。您可以将您的应用程序加载到 lldb 并告诉 lldb 它应该加载到地址 0x140000(这将是您的崩溃报告中的实际加载地址,不要担心幻灯片和原始加载地址)

% xcrun lldb
(lldb) target create -d -a armv7 /path/to/myapp.app
(lldb) target modules load -f myapp __TEXT 0x140000

现在 lldb 已将您的二进制文件加载到此崩溃报告的实际加载地址。您可以在 lldb 中执行所有常用查询,例如

(lldb) image lookup -v -a 0x144100

对地址 0x144100(可能出现在您的崩溃报告中)进行详细查找。

您还可以使用 target modules dump line-table 在 lldb 中执行一个漂亮的“转储内部行表”命令。例如,我编译了一个 hello-world Mac 应用程序:

(lldb) tar mod dump line-table a.c
Line table for /tmp/a.c in `a.out
0x0000000100000f20: /tmp/a.c:3
0x0000000100000f2f: /tmp/a.c:4:5
0x0000000100000f39: /tmp/a.c:5:1
0x0000000100000f44: /tmp/a.c:5:1
(lldb)

我可以更改我的二进制文件的加载地址并再次尝试转储行表:

(lldb) tar mod load -f a.out __TEXT 0x200000000
section '__TEXT' loaded at 0x200000000
(lldb) tar mod dump line-table a.c
Line table for /tmp/a.c in `a.out
0x0000000200000f20: /tmp/a.c:3
0x0000000200000f2f: /tmp/a.c:4:5
0x0000000200000f39: /tmp/a.c:5:1
0x0000000200000f44: /tmp/a.c:5:1
(lldb)

我不确定我是否理解您对地址的去标记所做的工作。调用堆栈上的地址是这些函数的返回地址,而不是调用指令——因此这些地址可能指向实际方法调用/调度源代码行之后的行,但是当您查看源代码时,这通常很容易理解。如果您所有的查找都指向方法的末尾,我认为您的查找方案可能有问题。

至于问题 #2,如果帧 #0(当前正在执行的帧)是一个没有设置堆栈帧的叶函数,或者在建立栈帧的过程。在这些情况下,可以跳过第 1 帧。但是一旦你超过了第 1 帧,尤其是在 ARM 上,放松就不应错过任何帧。

当标记为 noreturn 的函数调用另一个函数时,有一个非常棘手的问题,该函数的最后一条指令可能是一个调用——没有函数尾声——因为它知道它会再也无法控制。很不常见。但在那种情况下,一个头脑简单的符号会给你一个指向内存中下一个函数的第一条指令的指针。调试器等人使用了一个技巧,他们在进行符号/源代码行查找时从返回地址中减去 1 来回避这个问题,但这不是随意的符号器通常需要担心的事情。并且您必须小心不要对当前正在执行的函数(第 0 帧)执行 decr-pc 技巧,因为函数可能刚刚开始执行并且您不想将 pc 备份到上一个函数并错误地符号化.

关于ios - dSYM 地址查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18680744/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com