[英]Linux: using backtrace(), /proc/self/maps and addr2line together results in invalid result
我正在嘗試實現一種將程序的調用堆棧記錄到文件中然后稍后顯示的方法。 以下是步驟:
00400000-05cdc000 r-xp 00000000 00:51 12974779926 helloworld
helloworld
程序的基地址是0x400000。backtrace()
獲取調用堆棧的地址,然后寫入日志文件。 假設這個例子中的調用堆棧是:
0x400001 - 0x400000 = 1
addr2line -fCe hellowork 0x1
???
結果,即無效的偏移量。addr2line -fCe hellowork 0x400001
,然后返回正確的文件和行號。問題是如果地址在共享對象中,那么絕對地址將不起作用,而扣除的偏移量將起作用。
為什么主可執行文件和共享對象的地址映射方式存在如此大的差異? 或者這可能是特定於backtrace
實現的,以便它始終返回主可執行文件中函數的絕對地址?
為什么主可執行文件和共享對象的地址映射方式存在如此大的差異?
共享庫通常在地址 0 處鏈接並重新定位。 非位置可執行文件通常在x86_64
Linux 上的地址 0x400000 處鏈接,並且不得重定位(否則將不起作用)。
要找出給定的 ELF 二進制文件鏈接的位置,請查看第一個PT_LOAD
段的p_vaddr
地址( readelf -Wl foo
會告訴你)。 此外,只有ET_DYN
ELF 二進制文件可以重定位,而ET_EXEC
二進制文件則不能。
請注意,存在與位置無關的可執行文件,對於它們,您需要進行減法運算。
請注意,共享庫通常在地址0(等作品減法)聯系在一起,但他們沒有。 運行prelink
上的共享庫將導致在非0地址鏈接的共享庫,然后減去你的使用將不能工作。
實際上,您需要做的是從鏈接地址中減去運行時加載地址以獲得重定位(對於非 PIE 可執行文件為 0,對於共享庫為非 0),然后從程序中減去該重定位通過backtrace
記錄的 counter 來獲取符號值。
最后,如果您使用dl_iterate_phdr迭代所有加載的 ELF 圖像,它提供的dlpi_addr
正是您需要減去的重定位。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.