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

evo*_*vah 7 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.

谢谢!

Mar*_*ter 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);
}
Run Code Online (Sandbox Code Playgroud)

输出:

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_
Run Code Online (Sandbox Code Playgroud)

如果我写(例如),这也可以正常工作

    print_name("main", (void *)&main + 4);
Run Code Online (Sandbox Code Playgroud)

您说您可以正确解析输出,nm因此可能性似乎有限...您确定返回地址已正确导出或传递给您的解析器函数吗?我猜你正在为此使用GCC 内置函数?我已经测试过了__builtin_return_address(0),这对我来说也很有效。如果您使用的是 GCC 内置函数,您是否调用过__builtin_extract_return_address()(有关详细信息,请参阅上页,明确提到了 SPARC)?你能发布你的代码吗?

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

来自 sun.com 的这篇介绍性文章可能有用(警告:文章已有 10 年历史)。

这不像进行本机内省那么好,而且奇怪的是它dladdr(3C)不起作用:(

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