假設我們在gdb中遇到了符号0x0000555555555190
我們可以x/20g $rsp來觀察目前函數中的return address(有rbp的基位址,也有return address, 可以通過info line大概猜出來是什麼格式)。拿到這個return address - 0x0000555555555190之後,假設我們現在沒有符号,我們怎麼才能猜出他大概的位置,這個時候我們就需要借助addr2line
上面提到的關閉ASR可以通過setarch -R來進行關閉
但是addr2line他不針對運作位址,他隻針對偏移量,這個情況下,我們就遇到一個問題 - 怎麼把這個0x0000555555555190轉成相對位置。這個情況下我們可以通過info proc m或者直接cat /proc/pid/maps來檢視base address
當有了這個base address之後,我們把上面的符号位址減去這個base address,就拿到他的相對位置了,即0x0000555555555190 - 0x0x0000555555554000 = 1190
當我們拿到了這個相對offset之後,我們就可以去讓addr2line輸出了,即
addr2line -e a.out 1190
我們得到的結果如下
咦,奇怪,我們都已經到了這一步了,怎麼仍然沒有行号。聰明的你也想到了。因為我們此時的a.out仍然是沒有debug symbols的,我們需要重新編一個具有debug symbols的elf,比如app,然後我們重新運作
然後我們來看一下真正的源檔案,是否是在調用add_numbers()的傳回位址
可以看到解析是成功的,幫我們定位到了這個函數的傳回位址,也就是這裡的第十五行
PS:
你也可以直接編譯有symbols的ELF, 隻要保證在同樣的一台機器上,然後直接運作info line *address即可
可以看到,通過這個方式我們也能列印出對應的行号。但是因為位址随機化的問題,最好是在同一台機器上,否則這裡的Base Address會有出入
addr2line通過-f選項可以列印function name
其實還有更快的辦法,我們并不一定一定要去找return address, 其實對我們來說最有用的就是rip以及pc,都表示下一個要運作的位址
我們可以直接通過這個位址減去base address,就可以直接通過addr2line去定位crash的問題
同時如果你的程式本身是開了優化,為了精準定位,你在出debug symbols的時候也盡量帶上優化,這樣可以保證你的行号是正确的
比如我們這裡在不開優化的情況下是15号,但是如果跟原程式一樣開了優化,就變成了正确的第14行
PS:
當gdb沒有運作的時候,如果直接file a.out,此時檢視info functions得到的位址都是相對位址
當程式運作起來之後會把這些相對位址加上start address成為最終的符号位址