一、 符号化流程以及地址之间的关系
符号化流程:第一步:从内存地址回溯到文件(macho文件中的地址) 第二步:还原运行时调试信息
- 第一步的关键在于回溯到macho文件,找到对应的地址(这个好理解)
- 第二步关键,如何根据macho文件的地址,找到对应的符号
地址间的关系如下:
运行时候的image地址 = macho文件中的image地址 + aslr
运行时候的函数地址 = macho文件中函数的地址(函数地址=所在image + offset) + aslr
ASLR Slide + Linker address = Load address
其中:运行时候的image地址可以从crash文件中获得 Binary Images,macho文件中的image地址可以通过dsym获得
二、 举例感受如何符号化的
崩溃地址:0x000000010a107eb4(运行时候的函数符号地址) xxxxx + 3764,(前大后小)
第一步:回溯到文件,得到0x100000EB4(文件地址)
-
macho文件中的函数符号地址=0x000000010a107eb4 - ALSR:算出ALSR即可 -
计算ALSR如下(原理:运行的image地址 - macho文件中image地址):
运行的image地址:敲出image list命令,0x000000010a107000 或者 crash文件中的image地址。
macho文件中image地址:查看dsym文件,0x0000000100000000 (objdump --macho --private-headers)
根据ASLR = 0x000000010a107eb4 - 0x0000000100000000 = 0x00000000a107000
编译出来的函数符号地址=0x000000010a107eb4 - 0x00000000a107000 = 0x100000EB4(文件地址)
第二步:还原信息,得到函数名称
- dwarfdump --lookup 0x100000EB4 得到:"-[ViewController warfTest]"
三、 符号化原理,即dwarfdump --lookup 0xxxxx 如何找到符号
debuf-info 比如再举个例子:崩溃文件链接地址=0x52846
1.解析debuginfo:
$ dwarfdump -e --debug-info YourPath/YourApp.dSYM/Contents/Resources/DWARF > info-e.txt ,0x52846确定在哪个文件和函数中,在showOilPricePickerView函数中
`0x00062112: ``function` `[99] *`
` ``low pc( 0x000502e0 )`
` ``high pc( 0x00053730 )`
` ``frame base( r7 )`
` ``object pointer( {0x0006212a} )`
` ``name( ``"-[OBDFirstConnectViewController showOilPricePickerView]"` `)`
` ``decl file( ``"/YourSourcePath/OBDFirstConnectViewController.m"` `)`
` ``decl line( 870 )`
` ``prototyped( 0x01 )`
` ``APPLE instruction set architecture( 0x01 )`
2.解析debug_line:$ dwarfdump -e --debug-line YourPath/YourApp.dSYM/Contents/Resources/DWARF > line-e.txt ,知道在哪一行,可以看到0x52846在882行
0x00000000000502e0 870 /YourSourcePath/OBDFirstConnectViewController.m
`0x0000000000052812 880`
`0x000000000005283e 881`
`0x0000000000052846 882`
`0x00000000000528c8 883`
四、知识点
1)strip style三种
- all symbols:剥离所有符号
- Non Global:剥离非全局符号
- Debugging Symbols:移除debug nlist符号,保留直接符号
2)调试信息类型
- function starts(缺方法名)
- nlist(有名缺行)
struct nlist_64{
uint8_t n_type:告诉我们类型,是不是直接符号
}
- DWARF
3) DWARF详解:
相较于地址、函数名,多了关系信息。三个数据流:debug_info,debug_abbrev,debug_line
debug_info 包含了原始数据:文件名、类型、地址范围
debug_abbrev 为原始数据进行了结构化处理:解释debug_info各个字段意义
debug_line 包含了文件名和行号:关键点,它定义了一个行表程序,可以让文件地址映射到源码文件中的具体行数
每个 swift 文件都会有一个编译单元
总结: 1.DWARF 一个编译单元,包含N个子程序(文件内定义的各个函数),子程序包含地址范围。通过debug-info得到 2.查找流程:遍历编译单元,遍历子节点(子程序)