dladdr不返回函数名称

joh*_*ash 5 c linux elf

我正在尝试使用dladdr。它可以正确找到该库,但是找不到函数名称。我可以调用objdump,做一些数学运算,然后获取传递dladdr的函数的地址。如果objdump可以看到它,为什么不能dladdr?

这是我的功能:

const char *FuncName(const void *pFunc)
{
Dl_info  DlInfo;
int  nRet;

    // Lookup the name of the function given the function pointer
    if ((nRet = dladdr(pFunc, &DlInfo)) != 0)
        return DlInfo.dli_sname;
    return NULL;
}
Run Code Online (Sandbox Code Playgroud)

这是显示我得到的gdb成绩单。

Program received signal SIGINT, Interrupt.
[Switching to Thread 0xf7f4c6c0 (LWP 28365)]
0xffffe410 in __kernel_vsyscall ()
(gdb) p MatchRec8Cmp
$2 = {void (TCmp *, TWork *, TThread *)} 0xf1b62e73 <MatchRec8Cmp>
(gdb) call FuncName(MatchRec8Cmp)
$3 = 0x0
(gdb) call FuncName(0xf1b62e73)
$4 = 0x0
(gdb) b FuncName
Breakpoint 1 at 0xf44bdddb: file threads.c, line 3420.
(gdb) call FuncName(MatchRec8Cmp)

Breakpoint 1, FuncName (pFunc=0xf1b62e73) at threads.c:3420
3420    {
The program being debugged stopped while in a function called from GDB.
When the function (FuncName) is done executing, GDB will silently
stop (instead of continuing to evaluate the expression containing
the function call).
(gdb) s
3426            if ((nRet = dladdr(pFunc, &DlInfo)) != 0)
(gdb) 
3427                    return DlInfo.dli_sname;
(gdb) p DlInfo 
$5 = {dli_fname = 0x8302e08 "/xxx/libdata.so", dli_fbase = 0xf1a43000, dli_sname = 0x0, dli_saddr = 0x0}
(gdb) p nRet
$6 = 1
(gdb) p MatchRec8Cmp - 0xf1a43000
$7 = (void (*)(TCmp *, TWork *, TThread *)) 0x11fe73
(gdb) q
The program is running.  Exit anyway? (y or n) y
Run Code Online (Sandbox Code Playgroud)

这是我从objdmp得到的

$ objdump --syms /xxx/libdata.so | grep MatchRec8Cmp
0011fe73 l     F .text  00000a98              MatchRec8Cmp
Run Code Online (Sandbox Code Playgroud)

果然0011fe73 = MatchRec8Cmp-0xf1a43000。任何人都知道为什么dladdr无法返回dli_sname =“ MatchRec8Cmp” ???

我正在运行Red Hat Enterprise Linux Server 5.4(Tikanga)。我以前看过这项工作。也许是我的编译开关:

CFLAGS = -m32 -march=i686 -msse3 -ggdb3 -pipe -fno-common -fomit-frame-pointer \
        -Ispio -fms-extensions  -Wmissing-declarations -Wstrict-prototypes -Wunused  -Wall \
        -Wno-multichar -Wdisabled-optimization -Wmissing-prototypes -Wnested-externs \
        -Wpointer-arith -Wextra -Wno-sign-compare -Wno-sequence-point \
        -I../../../include -I/usr/local/include -fPIC \
        -D$(Uname) -D_REENTRANT -D_GNU_SOURCE 
Run Code Online (Sandbox Code Playgroud)

尽管我认为调试符号与elf没有任何关系,但我已使用-g而不是-ggdb3进行了尝试。

谢谢!

Emp*_*ian 5

如果objdump可以看到,为什么dladdr看不到

dladdr只能看到动态符号表中导出的函数。最有可能的

 nm -D /xxx/libdata.so | grep MatchRec8Cmp
Run Code Online (Sandbox Code Playgroud)

什么都不显示。确实,您的 objdump 显示该符号是local,这证明这是原因。

符号是局部的,要么是因为它具有隐藏的可见性,要么是静态的,要么是因为您以某种其他方式(例如,使用链接描述文件)隐藏了它。

更新:

标有“U”的那些与 dladdr 一起工作。它们以某种方式自动“导出”。

它们工作是因为它们是从其他一些共享库导出的。该U代表还没有解决,即别处定义。


The*_*eJJ 5

我添加-rdynamic到我的 LDFLAGS。

man gcc 说:

-rdynamic
    Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the
    dynamic symbol table. This option is needed for some uses of "dlopen" or to allow obtaining backtraces from within a program.
Run Code Online (Sandbox Code Playgroud)