4

我正在编写一个小程序,它使用 ptrace(单步、getregs、pick_text、操作码比较等)跟踪二进制文件(elf)的所有系统调用和调用。

到目前为止,我已经成功地跟踪了系统调用和简单的调用,比如用户定义的函数。

但是由于 ptrace,我无法从我选择的地址中获取 printf 符号的名称。

我的问题是:对于 printf、strlen 等动态链接函数,如何在 elf 文件中从地址中检索符号名称?

通过简单的调用,这很容易,我遍历 .strtab 部分,当地址匹配时,我返回相应的 str。

但是对于 printf,该符号在 .strtab 中是已知的,但地址为“0”。

objdump -d 以某种方式成功地将对 printf 的调用与其地址链接起来。

你有什么主意吗 ?

4

1 回答 1

3

我认为您可能需要阅读更多有关动态链接的信息。让我们以有点特殊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.

我相信这对你有用。

有关更多信息,我建议您查看跟踪库调用的来源ltrace以及backtrace_symbols(以及此处)如何工作;请注意,特别是对于非全局符号,这将是不可靠的,并注意重新添加-r dynamic到链接行的注释。

您可能还想查看addr2line及其源代码

于 2015-07-12T12:48:51.657 回答