dladdr doesn't return the function name

12,855

Solution 1

If objdump can see it, why can't dladdr

dladdr can only see functions exported in the dynamic symbol table. Most likely

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

shows nothing. Indeed your objdump shows that the symbol is local, which proves that this is the cause.

The symbol is local either because it has a hidden visibility, is static, or because you hide it in some other way (e.g. with a linker script).

Update:

Those marked with the 'U' work with dladdr. They get "exported" automatically somehow.

They work because they are exported from some other shared library. The U stands for unresolved, i.e. defined elsewhere.

Solution 2

I added -rdynamic to my LDFLAGS.

man gcc says:

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

Solution 3

Adding the gcc option "-export-dynamic" solved this for me.

Solution 4

hinesmr solution worked for me. The exact option I passed gcc was "-Wl,--export-dynamic" and all the functions became visible to dladdr

Share:
12,855
johnnycrash
Author by

johnnycrash

Updated on July 17, 2022

Comments

  • johnnycrash
    johnnycrash almost 2 years

    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.

  • johnnycrash
    johnnycrash almost 12 years
    You are correct in that the function in question does not show up when I do nm -D. In fact a small random sampling of my functions is returned when I call nm. When I pass the address of a function that does show up, dladdr works. What I can't figure out is how to export the function. I don't use -fvisibility, so by default all functions should be exported. I tried using attribute ((visibility("default"))), but that doesn't work either.
  • johnnycrash
    johnnycrash almost 12 years
    I hunted around for a long time and found a bash script being executed in the build which set a make variable which resulted in a --version-script being added to the build. However for some reason, there are a number of functions that show up in the nm -D result that are not listed in the --version-script. They all look like this: " U MemInfoTransCreate", whereas the items in the --version-script that are marked as "global", look like this: "00000000001202ff T MatchRec8Cmp_th". Those marked with the 'U' work with dladdr. They get "exported" automatically somehow.