提问



我通过AirBrake.io收到了一个没有象征意义的崩溃报告。由于崩溃报告与Apple崩溃日志的格式不完全相同,我不能像往常一样将它放在XCode上,所以我采用了完全相同的构建方式。我的XCode存档尝试在命令行上对其进行符号化。结果如下:


$ atos -o kidsapp.app/kidsapp 0x0002fc4c
0x0002fc4c (in kidsapp)


我绝对相信我使用的是与崩溃报告相同的版本。所以我也尝试过使用dwarfdump:


$ dwarfdump --lookup 0x0002fc4c --arch armv7 kidsapp.app.dSYM
----------------------------------------------------------------------
 File: kidsapp.app.dSYM/Contents/Resources/DWARF/kidsapp (armv7)
----------------------------------------------------------------------
Looking up address: 0x000000000002fc4c in .debug_info... not found.
Looking up address: 0x000000000002fc4c in .debug_frame... not found.


也没有结果。除了使用错误的dSYM文件还有什么我可以做错的吗?我知道这是正确的,因为这是AirBrake崩溃报告中提到的版本,它在我的XCode档案中。


欢迎任何想法/提示!

最佳参考


首先检查dSYM是否真的是该应用程序的正确版本:


dwarfdump --uuid kidsapp.app/kidsapp
dwarfdump --uuid kidsapp.app.dSYM


两者都应该返回相同的结果。


接下来检查dSYM是否包含任何有效内容


dwarfdump --all kidsapp.app.dSYM


除了not found之外,这至少应该给出一些信息。


我猜dSYM已经腐败了。通常,您可能希望使用崩溃报告器,该报告器为您提供包含所有线程和最后异常回溯信息的完整崩溃报告。我建议使用基于PLCrashReporter的东西,例如QuincyKit(Mac上的开源SDK +服务器+符号)或HockeyApp(开源SDK +付费服务+服务器端符号)(注意:我是开发人员之一!)

其它参考1


我使用以下算法来弄清楚:


slide + stack address - load address=symbol address





stack address是我从堆栈转储崩溃报告中获得的十六进制值(不是.crash文件,只是堆栈转储)。





slide是运行otool -arch armv7 -l APP_BINARY_PATH时LC_SEGMENT cmd的vmaddr。我的通常最终是0x00001000。





load address是复杂的一部分。它实际上是主线程的最底层堆栈地址与运行dwarfdump --arch armv7 --all DSYM_BINARY_PATH时包含符号的二进制部分的FIRST地址之间的差异。这只是main函数的符号地址。因此,如果您最底部的崩溃地址为0x8000且主函数的符号地址为0x2000,那么您的load address为0x6000。


现在有了所有这些部分,我可以计算符号地址并将其放入atos或dwarfdump:dwarfdump --lookup SYM_ADDR --arch armv7 APP_BINARY_PATH


转储示例(您可以看到load address是0x00003af4):



  ----------------------------------------------------------------------

  
  文件:/Users/user/Desktop/MyApp.xcarchive/dSYMs/MyApp.app.dSYM/Contents/Resources/DWARF/MyApp(armv7)

  
  ----------------------------------------------------------------------

  
  0x00000024:[[0x00003af4 - 0x00003b4e)main

  
  0x00000098:[[0x00003b50 - 0x00003d8c) - [[MyAppDelegate application:didFinishLaunchingWithOptions:]]

  
  ...转储的其余部分



最困难的部分是意识到我所包含的2个静态库中的一个在链接到我的应用程序的二进制文件之前已经剥离了它们的符号!这留下了巨大的符号地址空间,所以我只得到了我在dSYM中需要的符号的三分之二。


确保在静态库xcode项目中将以下标志设置为NO,这样当您链接它时,您可以将符号拉入应用程序的二进制文件(以后可以删除):COPY_PHASE_STRIPDEAD_CODE_STRIPPINGSTRIP_INSTALLED_PRODUCT


现在您可能会问,如果堆栈转储不包含主函数,我该怎么办,因为它不在主线程上,因此我无法获得主函数的堆栈地址?。对此,我会回答:我还没有一个线索!。只需交叉手指,希望您可以获得包含符号地址的堆栈跟踪,或使用模拟Apple崩溃日志的崩溃报告系统,如PLCrashReporter。


[[编辑2013年5月26日]] -


我注意到load address实际上是mach-o二进制文件的地址。虽然我上面描述的内容经常可以工作 - 但实际上并不正确。这可以通过CRASH REPORT获得,但是这个答案的重点是当你没有崩溃报告时提供崩溃的符号。我想在符号化的时候找出load address的最好方法是确保用stack addresses记录load address


我亲自创建了一个用于记录崩溃(不是崩溃报告)的系统,并将它们发送到S3存储桶,我可以在以后检索它们进行调试。当我启动应用程序时,我缓存slideload address]]和main function address如果我的应用程序崩溃并且我发送了stack addresses


注意:dyld函数使用#include <mach-o/dyld.h>


slide=_dyld_get_image_vmaddr_slide(0)返回的地址


load address=_dyld_get_image_header(0)返回的地址


main function address=[NSThread callStackReturnAddresses]中的最后一个地址
在主线程上调用


在崩溃时,我确定要记录[NSThread callStackReturnAddresses][NSThread callStackSymbols]以及可以通过此方法检索的体系结构:


- (NSString*) arch
{
    NSString* arch =
#ifdef _ARM_ARCH_7
        @"armv7";
#elif defined (_ARM_ARCH_6)
        @"armv6";
#else
        nil;
#endif

    return arch;
}


我还不知道如何区分armv7和armv7s。


所以这可能在将来有所帮助。我计划将我学到的所有知识转化为一个简单的崩溃工具 - 比natos工具(可能是natos v2)更好。


我已经更新了natos以支持手动提供load address:https://github.com/NSProgrammer/natos [48]

其它参考2


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


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] [Relative Address] " path appName runtimeAddress relativeAddress
loadAddress=`echo "obase=16;ibase=10;$((runtimeAddress-relativeAddress))" | bc`
atos -o $path/Payload/$appName.app/$appName -l $loadAddress $runtimeAddress -arch armv7


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

其它参考3


我认为这篇文章可能会对你有所帮助,https://stackoverflow.com/a/12559150/1773317。
乔的承诺解决了我的问题。


原因是我的.app和.dSYM文件无法通过聚光灯索引,因此我的XCode无法正确表示崩溃信息。

其它参考4


您可以尝试使用我为 atos 命令编写的用于符号的脚本:


https://github.com/IdoTene/MacosSymbolicateCrash[50]

其它参考5


所以我的情况:
我正在接收NSException.callStackSymbols中的崩溃字符串。


崩溃堆栈跟踪看起来像这样:


2   AppName                               0x00000001006c75b4 AppName + 2356660\r3   AppName                               0x00000001004f5cfc AppName + 449788\r4   UIKit                               0x000000018c0a8968 \u003credacted\u003e + 108\r5   UIKit      0x000000018c0a9328 \u003credacted\u003e + 28\r6   UIKit                               0x000000018beea250 \u003credacted\u003e + 1320\r7   UIKit                               0x000000018beede98 \u003credacted\u003e + 188\r8   UIKit                               0x000000018bcb5820 \u003credacted\u003e + 116\r9   UIKit                               0x000000018bbdec88 \u003credacted\u003e + 760\r10  UIKit                               0x000000018bbde610 \u003credacted\u003e + 312\r11  UIKit                               0x000000018bbde31c \u003credacted\u003e + 296\r12  UIKit                               0x000000018bbde3bc \u003credacted\u003e + 456\r13  QuartzCore                          0x0000000185b93b7c \u003credacted\u003e + 284\r14  libdispatch.dylib                   0x00000001811a8a2c \u003credacted\u003e + 16\r15  libdispatch.dylib                   0x00000001811b5654 \u003credacted\u003e + 1012\r16  CoreFoundation                      0x0000000181851650 \u003credacted\u003e + 12\r17  CoreFoundation                      0x000000018184f1a8 \u003credacted\u003e + 2272\r18  CoreFoundation                      0x000000018176f488 CFRunLoopRunSpecific + 552\r19  GraphicsServices                    0x0000000183735020 GSEventRunModal + 100\r20  UIKit         0x000000018bc09cc0 UIApplicationMain + 236\r21  AppName                               0x000000010048f714 AppName + 30484\r22  libdyld.dylib 0x000000018120dfc0 \u003credacted\u003e + 4


不要包含bitcode,因为Apple可以重新编译你的代码,而且你在Organizer中的存档中的dsym文件也不匹配。
[51]


运行这样的bash脚本:


#!/bin/bash
appName=AppName
runtimeAddress=0x00000001006c75b4
relativeAddress=2356660
loadAddress=`echo "obase=16;ibase=10;$((runtimeAddress-relativeAddress))" | bc`
atos -o $appName.app/$appName -l $loadAddress $runtimeAddress -arch arm64


假设你已经创建了一个test.sh(touch test.sh)。如果由于权限问题而无法运行sctipt(./test.sh):现在调用chmod + x test.sh。/test.sh应该工作。并生成结果。


[52]


同样可以使用AppName.app.dSYM文件来表示崩溃文件:


#!/bin/bash
appName=AppName
runtimeAddress=0x00000001006c75b4
relativeAddress=2356660
loadAddress=`echo "obase=16;ibase=10;$((runtimeAddress-relativeAddress))" | bc`
atos -o $appName.app.dSYM/Contents/Resources/DWARF/$appName -l $loadAddress $runtimeAddress -arch arm64