2012-07-30 74 views
4

我正在嘗試使用dladdr。它正確定位庫,但它找不到函數名稱。我可以調用objdump,做一些小算術,並獲取我傳遞dladdr函數的地址。如果objdump可以看到它,爲什麼不能dladdr?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」?

我正在運行紅帽企業Linux服務器版本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的,雖然我不認爲調試符號有什麼做的小精靈。

謝謝!

+0

只是一個猜測 - 嘗試'的extern 「C」'你MatchRec8Cmp()? – YePhIcK 2012-07-30 23:55:56

+0

值得一試,當我做objdump和func在.c文件中時,我不認爲這些名字看起來會被破壞。 – johnnycrash 2012-07-31 00:16:54

+0

extern「C」沒有工作! :( – johnnycrash 2012-07-31 00:17:32

回答

3

如果objdump的可以看出來,爲什麼不能提供dladdr

dladdr只能看到動態符號表中導出功能。最有可能的是

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

什麼也沒有顯示。事實上,你的objdump顯示符號是本地,這證明這是原因。

符號是本地的,因爲它具有隱藏的可見性,是靜態的,或者因爲您以其他方式(例如使用鏈接器腳本)隱藏它。

更新:

標有與提供dladdr的 'U' 的工作。他們以某種方式自動「導出」。

他們的工作,因爲他們是從一些其他的共享庫出口。 U表示未解決,即在別處定義。

+0

你是正確的,當我做nm -D時,沒有出現問題的函數,實際上,當我調用nm函數時,會返回一個隨機抽樣函數,當我傳遞一個函數的地址時, dladdr的作品,我不知道如何導出函數。我不使用-fvisibility,所以默認情況下所有函數都應該導出。我嘗試使用__attribute__((visibility(「default」))),但那不起作用e ither。 – johnnycrash 2012-07-31 14:45:42

+0

我在很長一段時間內徘徊了一段時間,發現一個bash腳本在構建中被執行,該腳本設置了一個make變量,這導致了--version腳本被添加到構建中。然而,由於某些原因,在nm -D結果中顯示的許多函數未在--version-script中列出。它們看起來像這樣:「U MemInfoTransCreate」,而--version-script中標記爲「全局」的項目如下所示:「00000000001202ff T MatchRec8Cmp_th」。那些標有'U'的符號與dladdr一起工作。他們以某種方式自動「導出」。 – johnnycrash 2012-07-31 18:06:27

+0

@johnnycrash答案更新。 – 2012-08-01 04:48:53

2

添加gcc選項「-export-dynamic」爲我解決了這個問題。

1

hinesmr解決方案爲我工作。我通過gcc的確切選項是「-Wl, - export-dynamic」,所有功能對dladdr都可見

1

我向我的LDFLAGS添加了-rdynamic

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.