addr2line工具是一個(gè)可以將指令的地址和可執(zhí)行映像轉(zhuǎn)換為文件名、函數(shù)名和源代碼行數(shù)的工具丁屎。這在內(nèi)核執(zhí)行過(guò)程中出現(xiàn)崩潰時(shí)荠锭,可用于快速定位出出錯(cuò)的位置,進(jìn)而找出代碼的bug晨川。
用法
addr2line [-a| --addresses ] [-b bfdname | --target=bfdname] [-C | --demangle[=style]] [-e filename | --exe=filename] [-f | --function] [-s | --basename] [-i | --inlines] [-p | --pretty-print] [-j | --section=name] [-H | --help] [-V | --version] [addr addr ...]
參數(shù)
-a --addresses:在函數(shù)名证九、文件和行號(hào)信息之前,顯示地址共虑,以十六進(jìn)制形式愧怜。
-b --target=<bfdname>:指定目標(biāo)文件的格式為bfdname。
-e --exe=<executable>:指定需要轉(zhuǎn)換地址的可執(zhí)行文件名妈拌。
-i --inlines : 如果需要轉(zhuǎn)換的地址是一個(gè)內(nèi)聯(lián)函數(shù)拥坛,則輸出的信息包括其最近范圍內(nèi)的一個(gè)非內(nèi)聯(lián)函數(shù)的信息。
-j --section=<name>:給出的地址代表指定section的偏移尘分,而非絕對(duì)地址猜惋。
-p --pretty-print:使得該函數(shù)的輸出信息更加人性化:每一個(gè)地址的信息占一行。
-s --basenames:僅僅顯示每個(gè)文件名的基址(即不顯示文件的具體路徑培愁,只顯示文件名)惨奕。
-f --functions:在顯示文件名、行號(hào)輸出信息的同時(shí)顯示函數(shù)名信息竭钝。
-C --demangle[=style]:將低級(jí)別的符號(hào)名解碼為用戶級(jí)別的名字梨撞。
-h --help:輸出幫助信息。
-v --version:輸出版本號(hào)香罐。
使用
1.自己查找一個(gè)地址卧波,然后來(lái)定位
#include<stdio.h>
int divide(int x, int y)
{
return x/y;
}
int main()
{
printf("hello world\n");
int x = 3;
int y = 0;
int div = divide(x, y);
printf("%d / %d = %d\n", x, y, div);
return 0;
}
編譯:
g++ -Wl,-Map=test.map -g test.cpp -o test
查找divide函數(shù)的地址
grep divide test.map
0x00000000004005e7 divide(int, int)
使用addr2line定位
addr2line 0x00000000004005e7 -e test -f -C -s
divide(int, int)
test.cpp:3
如果不加-C選項(xiàng),輸出如下(是未經(jīng)過(guò)demangle的)
_Z6divideii
test.cpp:3
2.查找系統(tǒng)信息庇茫,然后定位代碼
dmesg
[150100.451504] traps: test[7593] trap divide error ip:4005f5 sp:7ffeebd4ba70 error:0 in test[400000+1000]
這條信息里港粱,ip(指令指針寄存器)字段后面的數(shù)字就是test程序出錯(cuò)時(shí)程序執(zhí)行的位置。使用addr2line就可以將4005f5定位到代碼的位置:
addr2line 4005f5 -e test -f -s -C
divide(int, int)
test.cpp:4
第4行也就是除以0的位置:return x/y。
原理
addr2line如何找到的這一行呢查坪。在可執(zhí)行程序中都包含有調(diào)試信息(所以編譯的時(shí)候需要加-g選項(xiàng))寸宏,其中很重要的一份數(shù)據(jù)就是程序源程序的行號(hào)和編譯后的機(jī)器代碼之間的對(duì)應(yīng)關(guān)系Line Number Table。Line Number Table存儲(chǔ)在可執(zhí)行程序的.debug_line域偿曙。
使用如下命令
readelf -w test | grep "advance Address"
[0x000000ca] Special opcode 7: advance Address by 0 to 0x4005e7 and Line by 2 to 3
[0x000000cb] Special opcode 146: advance Address by 10 to 0x4005f1 and Line by 1 to 4
[0x000000cc] Special opcode 104: advance Address by 7 to 0x4005f8 and Line by 1 to 5
[0x000000cd] Special opcode 36: advance Address by 2 to 0x4005fa and Line by 3 to 8
[0x000000ce] Special opcode 118: advance Address by 8 to 0x400602 and Line by 1 to 9
[0x000000cf] Special opcode 146: advance Address by 10 to 0x40060c and Line by 1 to 10
[0x000000d0] Special opcode 104: advance Address by 7 to 0x400613 and Line by 1 to 11
[0x000000d1] Special opcode 104: advance Address by 7 to 0x40061a and Line by 1 to 12
[0x000000d3] Special opcode 20: advance Address by 1 to 0x40062c and Line by 1 to 13
[0x000000d5] Special opcode 132: advance Address by 9 to 0x400646 and Line by 1 to 14
[0x000000d6] Special opcode 76: advance Address by 5 to 0x40064b and Line by 1 to 15
觀察第二行和第三行氮凝,源代碼的第4行的指令起始地址是0x4005f1, 第5行的起始地址是0x4005f8望忆,可以知道0x4005f5位置的指令是屬于第4行代碼的罩阵。