10

I'm trying to use dladdr. It correctly locates the library, but it does not find the function name. I can call objdump, do a little math, and get the address of the function that I pass dladdr. If objdump can see it, why can't dladdr?

Here is my function:

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;
}

Here is a gdb transcript showing what I get.

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

Here is what I get from objdmp

$ objdump --syms /xxx/libdata.so | grep MatchRec8Cmp
0011fe73 l     F .text  00000a98              MatchRec8Cmp

Sure enough, 0011fe73 = MatchRec8Cmp - 0xf1a43000. Anyone know why dladdr can't return dli_sname = "MatchRec8Cmp" ???

I'm running Red Hat Enterprise Linux Server release 5.4 (Tikanga). I have seen this work before. Maybe it's my compile switches:

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 

I have tried it with -g instead of -ggdb3 although I don't think debugging symbols have anything to do with elf.

4

4 回答 4

8

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

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

 nm -D /xxx/libdata.so | grep MatchRec8Cmp

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

该符号是本地的,因为它具有隐藏的可见性,是静态的,或者因为您以其他方式隐藏它(例如使用链接器脚本)。

更新:

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

它们之所以起作用,是因为它们是从其他一些共享库中导出的。U代表未解决,即在别处定义。

于 2012-07-31T04:00:04.047 回答
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.
于 2016-05-25T10:08:26.330 回答
4

添加 gcc 选项“-export-dynamic”为我解决了这个问题。

于 2012-08-15T21:50:01.853 回答
1

hinesmr 解决方案对我有用。我通过 gcc 的确切选项是“-Wl,--export-dynamic”,所有函数都对 dladdr 可见

于 2013-02-09T03:48:04.763 回答