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.
dladdrcan only see functions exported in the dynamic symbol table. Most likelyshows 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:
They work because they are exported from some other shared library. The
Ustands for unresolved, i.e. defined elsewhere.Update 2023/05/14:
I see that there are a few "answers" below which tell you to add
-rdynamicor--export-dynamicto "solve" the problem.These answers don’t explain the "why" (i.e. they aren’t an actual answer to the question that was asked), and also don’t explain the cost of the solution, which could be significant.
First, adding
-rdynamicflag is preferable, because that is a the compiler front-end flag, which gets translated into appropriate linker flag (some linkers understand-E, some understand--export-dynamic, some understand both).Second, if you are going to add a linker-specific flag, you should do it correctly:
-Wl,--export-dynamic. Adding--export-dynamicwithout-Wl,prefix happens to work by accident — GCC doesn’t understand that flag and passes it to the linker. But it may do something else in the future.What are the costs of
-rdynamic? It slows down your executable loading. How much of a slowdown you’ll get depends on how largenm -D a.outbecomes, compared to the same without the flag.All the additional symbols are entered into the loader scope, and are searched whenever a symbol in a shared library needs to be resolved.
This can also break your executable if the symbol you didn’t want to be exported becomes exported.
Are there better solutions than
-rdynamic?Glad you asked. There probably are.
Newer versions of the linker have
--export-dynamic-symbol SYMBOLand--export-dynamic-symbol-list FILEoptions (do use-Wl,prefix if you are going to pass these flags to GCC), which allow you to control exactly which symbols are exported.That is a much more precise solution (compared to
-rdynamicwhich exports everything), and the cost is (usually) significantly lower.