Solaris进程如何读取自己的符号表?

时间:2011-08-11 18:26:09

标签: c++ solaris loader ld dlopen

我有一个Solaris进程,它是一个C ++应用程序,由ld加载了几个.so库。该应用程序有一个函数,它在调用函数中获取一个返回地址,然后尝试确定所述调用函数的名称。

如果我使用dladdr(3),那么它并不总是放在我希望在Dl_info :: dli_sname中看到的内容。它看起来像是返回一个函数的名称,该函数不是最接近下方或指针值。如果我获取指针值并查看nm的输出,我可以将该值与我期望的确切函数匹配。

我想知道是否有办法为流程检索符号映射,并让它在不使用dladdr(3)的情况下搜索函数名称。我特别感兴趣的是获得一个符号映射,不仅可以用于可执行文件本身,还可以用于已加载的所有.so库。

我在Solaris10 / SPARC上运行,我正在使用gcc 4.2.x。

谢谢!

2 个答案:

答案 0 :(得分:4)

我在Solaris 10 / SPARC上使用dladdr()尝试了一个简单的测试(但需要注意:GCC 3.4,直接C),这对我来说很好用:

#include <dlfcn.h>
#include <stdio.h>

void print_name(char *name, void *addr);
void print_name_by_dladdr(void *addr);

int main(int argc, const char *argv[])
{
    print_name("main", (void *)&main);
    print_name("print_name", (void *)&print_name);
    print_name("printf", (void *)&printf);
    return 0;
}

void print_name(char *name, void *addr)
{
    (void)printf("Getting name of function %s() at 0x%x\n", name, addr);
    print_name_by_dladdr(addr);
}

void print_name_by_dladdr(void *addr)
{
    Dl_info dli;
    if(!dladdr(addr, &dli)) {
        perror("dladdr()");
        exit(1);
    }
    (void)printf("  %s\n", dli.dli_sname);
}

输出:

Getting name of function main() at 0x10714
  main
Getting name of function print_name() at 0x10778
  print_name
Getting name of function printf() at 0x209b8
  _PROCEDURE_LINKAGE_TABLE_

如果我写(例如)

,这也可以正常工作
    print_name("main", (void *)&main + 4);

你说你可以正确地解决nm的输出,所以可能性似乎有限......你确定返回地址正在派生或正确传递给你的解析器功能吗?我猜你正在使用GCC builtins吗?我测试了__builtin_return_address(0),这对我来说也很好。如果您使用的是GCC内置版,您是否致电__builtin_extract_return_address()(有关详细信息,请参见上页,明确提及SPARC)?你可以发布你的代码吗?

你可以略微延伸到“处理重新读取它自己的二进制/共享对象文件”吗?如果是这样,那么libelf可能是一种前进的方式。这正是您提到的一些实用程序正在使用的内容,例如nmhttp://cr.opensolaris.org/~devnull/6515400/usr/src/cmd/sgs/nm/common/nm.c.html

来自sun.com的introductory article可能有用(警告:文章是10年)。

这不如做本机内省那么好,dladdr(3C)不起作用很奇怪:(

替代中间人:您是否尝试过RTLD_DL_SYMENT标志dladdr1(3C)(然后可能在返回的ELF sym上从nm.c借用)?

答案 1 :(得分:3)

有点晚了,但也许还是一个帮助: 在elf-object文件中,通常有2个符号表: .symtab和.dynsym nm默认读取.symtab,使用nm -D读取.dynsym 表。 dladdr(以及动态加载器)确实使用了 .dynsym表。 .symtab表更完整。 你可以强制所有符号在.dynsym表中 好好使用-rdynamic链接器标志。然而,这种情况变慢了 显着降低链接(例如,在我目前的项目中) aprox的。 200毫秒)。 (nb:上面说的是对linux的引用,但符号处理 在sunos上工作原理相同。命令行选项可能 不同)