我正在编写一个程序,它使用ptrace(singlestep,getregs,pick_text,opcodes比较等)跟踪二进制文件(elf)的所有系统调用和调用。
到目前为止,我已成功跟踪系统调用和用户定义函数等简单调用。
但是由于ptrace,我没能从我选择的地址中获取printf符号的名称。
我的问题是:对于printf,strlen等动态链接函数,如何在elf文件中检索地址中符号的名称?
通过简单的调用,它很简单,我运行.strtab部分,当地址匹配时,我返回相应的str。
但对于printf,符号在.strtab中已知,但地址为" 0"。
objdump -d以某种方式成功将对printf的调用与其地址相关联。
你有什么想法吗?
答案 0 :(得分:3)
我认为您可能需要阅读更多关于动态链接的内容。我们以strlen
作为示例符号,因为printf
有点特殊(强化的东西)。
您的问题是(我认为)您想要获取符号的地址并将其转换回地址。您正在尝试通过解析正在调试的程序的ELF文件来执行此操作。这适用于程序中的符号,但不适用于动态链接的符号,例如strlen
。你想知道如何解决这个问题。
原因是strlen
等符号的地址不在您的ELF程序中。它们是未解析的引用,在程序加载时动态解析 。事实上,现代Linux将(我相信)以随机顺序和随机地址加载动态库(包含可重定位的aka位置无关代码),因此在程序加载之前,这些符号的位置不会被知道。
对于使用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.
我相信这对你有用。
有关详细信息,建议您查看跟踪库调用的source到ltrace
,以及backtrace_symbols
(和here)的工作原理;请注意,特别是对于非全局符号,这将是不可靠的,请注意评论重新添加-r dynamic
到链接行。