2015-07-11 53 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