我使用以下算法来计算它:
slide
+ stack address
- load address
=symbol address
和
stack address
是我从堆栈转储崩溃报告中获得的十六进制值(不是 .crash 文件,只是堆栈转储)。
和
slide
是运行时 LC_SEGMENT cmd 的 vmaddr otool -arch armv7 -l APP_BINARY_PATH
。我的通常最终是 0x00001000。
和
load address
是复杂的部分。它实际上是主线程的最底部堆栈地址与运行时包含符号的二进制文件部分的第一个地址之间的差异dwarfdump --arch armv7 --all DSYM_BINARY_PATH
。这只是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) 主要
0x00000098:[0x00003b50 - 0x00003d8c)-[MyAppDelegate 应用程序:didFinishLaunchingWithOptions:]
...垃圾场的其余部分
最困难的部分是意识到我包含的 2 个静态库之一在链接到我的应用程序二进制文件之前已经剥离了它们的符号!这留下了巨大的符号地址差距,所以我只得到了 dSYM 中所需符号的三分之二。
确保在您的静态库 xcode 项目中将以下标志设置为 NO,以便当您链接它时,您可以将符号拉入应用程序的二进制文件(稍后可以剥离):COPY_PHASE_STRIP
、DEAD_CODE_STRIPPING
和STRIP_INSTALLED_PRODUCT
.
现在你可能会问,“如果堆栈转储不包含主函数,因为它不在主线程上,所以我无法获取主函数的堆栈地址,我该怎么办?”。对此我会回答,“我没有一个该死的线索!”。只需交叉手指,希望您可以获得包含符号地址的堆栈跟踪,或使用模仿 Apple 崩溃日志的崩溃报告系统,如 PLCrashReporter。
[编辑 2013 年 5 月 26 日] -
我注意到这load address
实际上是 mach-o 二进制文件的地址。虽然我上面描述的通常可以工作 - 它实际上并不正确。这可以通过崩溃报告获得,但是这个答案的重点是在您没有崩溃报告时提供崩溃的符号。我弄清楚load address
何时想要象征性的最好方法是确保我load address
使用stack addresses
.
我亲自创建了一个用于记录崩溃(不是崩溃报告)并将它们发送到 S3 存储桶的系统,以便稍后我可以检索它们以进行调试。当我启动我的应用程序时slide
,如果我的应用程序崩溃load 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