dladdr没有返回函数名称

时间:2012-07-30 23:41:35

标签: 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;
}

这是一个显示我得到的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

以下是我从objdmp

获得的内容
$ objdump --syms /xxx/libdata.so | grep MatchRec8Cmp
0011fe73 l     F .text  00000a98              MatchRec8Cmp

果然,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 

我用-g代替-ggdb3尝试了它,虽然我不认为调试符号与elf有任何关系。

谢谢!

4 个答案:

答案 0 :(得分:3)

  

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

dladdr只能在动态符号表中看到导出的函数。很可能是

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

什么都没有。实际上你的objdump表明符号是 local ,这证明了这就是原因。

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

更新

  

标有'U'的人与dladdr合作。它们会以某种方式自动“导出”。

它们可以工作,因为它们是从其他共享库导出的。 U代表未解决,即在别处定义。

答案 1 :(得分:3)

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

我将-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.