iOS 崩溃报告:atos 不如预期工作

64

我正在查看由苹果提供的崩溃报告。

Hardware Model:      iPhone4,1
Version:         ??? (???)
Code Type:       ARM (Native)
Parent Process:  launchd [1]

Date/Time:       2012-11-18 16:03:44.951 -0600
OS Version:      iOS 6.0.1 (10A523)
Report Version:  104

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x51fe5264
Crashed Thread:  0

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x352925b0 objc_msgSend + 16
1   MYAPP                           0x0006573a -[MyViewController(Images) didReceiveImage:context:etag:expires:] + 42
2   MYAPP                           0x0004fb26 -[MyImageTask didReceiveImage:] + 98
3   Foundation                      0x361ac8e8 __NSThreadPerformPerform
4   CoreFoundation                  0x3b37d680 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
5   CoreFoundation                  0x3b37cee4 __CFRunLoopDoSources0
6   CoreFoundation                  0x3b37bcb2 __CFRunLoopRun
7   CoreFoundation                  0x3b2eeeb8 CFRunLoopRunSpecific
8   CoreFoundation                  0x3b2eed44 CFRunLoopRunInMode
9   GraphicsServices                0x396bc2e6 GSEventRunModal
10  UIKit                           0x3452e2f4 UIApplicationMain
11  MYAPP                           0x0004934a main + 70
12  MYAPP                           0x000492fc start + 36

有趣的是,当我使用atos查找对应于地址位置0x0006573a0x0004fb26的代码行时,我得到完全不同的匹配结果。atos输出甚至不来自崩溃日志中提到的同一个类(MyViewController,MyImageTask)。相反,atos将我指向完全不相关类别的完全无害的代码行。我再次验证,我正在使用完全相同的dSYM和IPA,这些文件是我提交给Apple的。

我的atos命令

/Applications/Xcode.app/Contents/Developer/usr/bin/atos -arch armv7 -o MYAPP.app/MYAPP 0x0004fb26

/usr/bin/atos和armv7s都会得到相同的结果。

还有其他人遇到过这个问题吗?能否提供建议?谢谢。

4个回答

111

一个更简单的选择:你可以使用atos -l标志来让它为你做数学计算。

假设你有以下行在你的崩溃日志中,你想要符号化:

5   MyApp                   0x0044e89a 0x29000 + 4348058

第一个十六进制数是堆栈地址,第二个十六进制数是加载地址。您可以忽略最后一个数字。您也不需要担心滑动地址。

要进行符号化,请执行以下操作:

atos -o MyApp.app/MyApp -arch armv7 -l 0x29000 0x0044e89a
如果您找不到您的MyApp.app / MyApp文件,请将您的“.ipa”文件重命名为“.zip”,解压缩它,然后它会出现在Payload文件夹中。
如果您不确定要使用哪个架构(例如,armv7或armv7s),请滚动到崩溃文件的“二进制图像”部分,您可以在其中找到它。
祝福。

2
今天我在解析一个来自OS X应用程序的.crash日志时遇到了很多麻烦——显然,即使你有一个.dSYM,Xcode也已经很长时间没有支持OS X应用程序的符号化了。而你的答案让我终于得到了崩溃的行号。谢谢! - Shaggy Frog
在这段代码中有一个小错误:atos -o MyApp.app/MyApp -arch armv7 -l 0x29000 0x0044e89a。 - malex
12
请注意,如果您的应用程序不包含调试符号,您可以将-o部分替换为.dSYM文件中的符号 (MyApp.app.dSYM/Contents/Resources/DWARF/MyApp)。 - jasongregori
2
+号后面的数字是一个十进制数,它代表了“栈地址-加载地址”的结果。因此,你会发现第一个十六进制数是后两个数字的和。 - Xiao
3
@chris 你是天才。 - ViruMax
这对于调试一个模糊的崩溃日志截图非常有帮助。 - shane

98

你需要计算与atos一起使用的地址,不能仅仅使用堆栈跟踪中的地址。

symbol address = slide + stack address - load address
  1. slide值是LC_SEGMENT cmdvmaddr的值(通常为0x1000)。运行以下命令以获取它:

otool -arch ARCHITECTURE -l "APP_BUNDLE/APP_EXECUTABLE" | grep -B 3 -A 8 -m 2 "__TEXT"

ARCHITECTURE替换为崩溃报告显示的实际架构,例如armv7。 将APP_BUNDLE/APP_EXECUTABLE替换为实际可执行文件的路径。

  • stack address是来自崩溃报告的十六进制值。

  • load address可以是包含您的可执行文件的行的最前面显示的第一个地址在Binary Images部分中。(通常是第一个条目)。

  • 由于过去slide的值等于load address的值,因此这总是有效的。但自从苹果从iOS 4.3开始引入地址空间布局随机化(以不同的方式),应用程序加载地址由于安全原因而被随机化。


    你能举个例子告诉我如何使用符号地址=幻灯片地址+堆栈地址-加载地址吗?我无法理解它。 - pengwang
    10
    你可以使用 atos -l 命令,让它为你计算。我相信“slide”指的是名义地址和实际加载地址之间的差异,而不是加载地址本身。 - tc.
    您太棒了!非常感谢您!我刚刚给您的几个答案点了赞! - Shai Almog
    我使用你的计算方法得到了一个负值的 符号地址,这是出了什么大问题吗? - Tim Arnold
    1
    @TimArnold 如果崩溃报告已经被符号化,那么地址已经被Xcode的符号化脚本标准化了。因此,请检查堆栈地址>加载地址并确保您正在正确地检查二进制图像部分下的元素。 - Kerni
    显示剩余4条评论

    12

    这个方法还适用于iOS 6-7的崩溃日志吗?这是我以前在Mac崩溃日志中使用的方法,但在Lion时代它停止工作了。 - Peter Hosey
    是的,我刚在 Mountain Lion 上使用它处理了两份 iOS 6.1.3 的崩溃报告。 - CpnCrunch
    2
    就我个人而言,对于armv7s架构,dwarfdump无法正常工作,但使用atos进行数学计算可以解决问题。 - Scott Corscadden
    刚刚尝试使用dwarfdump,然后按照@Kerni的说明进行计算。数学是正确的,但dwarfdump没有成功,就像Scott一样,这是针对armv7s架构的。 - Rob Segal

    4

    对于那些特定时间没有像这样的负载地址值的人:

    Jan 14 11:02:39 Dennins-iPhone AppName[584] <Critical>: Stack Trace: (
        0   CoreFoundation                      0x2c3084b7 <redacted> + 150
        1   libobjc.A.dylib                     0x39abec8b objc_exception_throw + 38
        2   CoreFoundation                      0x2c21cc35 CFRunLoopRemoveTimer + 0
        3   AppName                             0x0005a7db AppName + 272347  
    

    我编写了一个简单的Bash脚本来帮助我进行调试:

    #! /bin/bash
    read -p "[Path] [App Name] [Stack Address] [DecimalSum] " path appName stackAddress decimalSum
    loadAddress=`echo "obase=16;ibase=10;$((stackAddress-decimalSum))" | bc`
    atos -o $path/Payload/$appName.app/$appName -l $loadAddress $stackAddress -arch armv7
    

    它只是读取应用程序的路径、应用程序名称、堆栈地址和加号信号后面的值(十进制值),然后找到负载地址的值以运行atos命令。


    这个解决方案对于一个测试人员发送给我的异常(来自Console.app),它没有生成崩溃报告,完美地起作用了。谢谢! - Andrew

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接