2015-07-11 50 views
2

我正在寫一個使用ptrace(singlestep,getregs,pick_text,opcodes比較等)跟蹤所有系統調用和二進制文件(elf)調用的小程序。Printf Symbol Resolution

到目前爲止,我已經成功跟蹤系統調用和簡單的調用,如用戶定義的函數。

但是我沒有從我選擇的地址獲取printf符號的名稱,這要感謝ptrace。

我的問題是:對於像printf,strlen等動態鏈接函數,我如何從elf文件中檢索地址中的符號名稱?

簡單的調用很簡單,我運行.strtab部分,當地址匹配時返回相應的str。

但是對於printf,該符號在.strtab中已知,但地址爲「0」。

objdump -d以某種方式成功地將呼叫鏈接到printf及其地址。

你有什麼想法嗎?

+0

是否涉及動態鏈接? – fuz

+1

在glibc中,由於設防補丁,'printf'的符號實際上被稱爲'__printf_chk'。在調用'printf'的目標文件上運行'nm',你會看到。一般來說,看看如何解析精靈文件的libelf。我建議你不要手動解析它們。 – fuz

+0

我已經在使用libelf。而實際上,如果我使用nm,我可以看到「printf」符號,但沒有看到它的地址,符號標有「未定義」的「U」字母。這是我的問題,我使用該函數的地址來檢索其名稱。但是如果該地址沒有儲存在精靈中,我無法檢索該名稱。是的,libc是動態鏈接的我猜 –

回答

2

我想你可能需要閱讀更多有關動態鏈接的內容。我們以strlen作爲示例符號,因爲printf有點特別(設防的東西)。

你的問題是(我認爲)你想採取一個符號的地址,並將其翻譯回地址。你正在試圖通過解析你正在調試的程序的ELF文件來做到這一點。這適用於程序中的符號,但不適用於動態鏈接的符號,如strlen。你想知道如何解決這個問題。

其原因是,諸如strlen等符號的地址不在您的ELF程序中。他們是相反的未解決的參考,當程序加載時,動態解析。事實上,現代Linux將(我相信)以隨機順序和隨機地址加載動態庫(其中包含可重新定位的位置獨立代碼),因此只有在程序加載之前,這些符號的位置纔會知道。

對於使用dlopen()打開的庫(即,在自己在程序中進行加載的位置),可以使用dlsym()檢索此類符號的地址;如果它們在編譯/鏈接時鏈接到程序中,那就不太好了。

在gcc上,要解析一般符號的位置,請使用gcc擴展dladdr()。從手冊頁:

The function dladdr() takes a function pointer and tries to 
    resolve name and file where it is located. Information is 
    stored in the Dl_info structure: 

     typedef struct { 
      const char *dli_fname; /* Pathname of shared object that 
             contains address */ 
      void  *dli_fbase; /* Address at which shared object 
             is loaded */ 
      const char *dli_sname; /* Name of nearest symbol with address 
             lower than addr */ 
      void  *dli_saddr; /* Exact address of symbol named 
             in dli_sname */ 
     } Dl_info; 

    If no symbol matching addr could be found, then dli_sname and 
    dli_saddr are set to NULL. 

    dladdr() returns 0 on error, and nonzero on success. 

我相信這會對你有用。

如需進一步信息,我建議你看看sourceltrace它跟蹤庫調用,以及如何backtrace_symbols(和here)的作品;請注意,特別是對於非全局符號,這將變得不可靠,並且請注意添加-r dynamic到鏈接行的註釋。

你可能也想看看addr2line及其source