我的C代码如何在运行时找到与地址对应的符号(在Linux中)?

Sor*_*puc 4 c linux elf debug-symbols binutils

给定函数或变量运行时地址,我的代码需要找出名称,如果是变量,则键入符号的信息.或至少提供足够的信息,以便以后离线提取名称(和类型信息).

这是Linux代码,假设调试信息可用.

我试着研究ELF文件格式,binutils以及除了主题之外的所有内容都是巨大的,所以我希望有人可以帮我缩小范围.

我可以看到以下类型的解决方案:

  • 找到当前加载到内存中的模块的代码/数据段的范围 - 怎么做?将地址的模块和段名称和偏移量保存在其段中.离线然后使用binutils在模块的调试信息中找到符号 - 再次,如何做?

  • 使用一些我不知道的API /系统服务在运行时找到符号和信息 - 如何?

先感谢您.

o11*_*11c 6

GNU libc 为此目的提供了一个dladdr函数.但是,它只适用于函数,而不适用于变量.

   #define _GNU_SOURCE         /* See feature_test_macros(7) */
   #include <dlfcn.h>

   int dladdr(void *addr, Dl_info *info);

   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 symbol whose definition
                                      overlaps 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.
Run Code Online (Sandbox Code Playgroud)

当然,通常我会从gdb做这种事情,而不是程序本身.


Lee*_*ker 0

C 是一种完全编译语言。变量的名称和类型以及其他信息通常在编译过程中被丢弃。

一个例外是,大多数编译器将生成包含调试信息的可执行文件,以便实时调试器可以访问此信息。这些信息完全是特定于操作系统的,甚至是特定于编译器的,甚至可能位于程序无法访问的内存部分中。

  • @LeeDanielCrocker 没有法律限制调试器使用调试信息并禁止程序检查自己的调试信息。一种用例是程序打印自己的崩溃堆栈跟踪,其中包含符号、文件和行信息(通常在集群环境中,获取核心转储不方便)。 (3认同)
  • OP说调试信息是可用的,所以我想这是可能的一种或另一种方式。毕竟,这就是调试信息的用途。 (2认同)