2011-09-26 10 views
27

バックトレース関数関数名/ファイル名/行番号でマップする方法は?関数アドレスを* .soファイルの関数にマップする方法

for ex:- 
backtrace() returned 8 addresses 
./libtst.so(myfunc5+0x2b) [0xb7767767] 
./libtst.so(fun4+0x4a) [0xb7767831] 
./libtst.so(fun3+0x48) [0xb776787f] 
./libtst.so(fun2+0x35) [0xb77678ba] 
./libtst.so(fun1+0x35) [0xb77678f5] 
./a.out() [0x80485b9] 
/lib/libc.so.6(__libc_start_main+0xe5) [0xb75e9be5] 
./a.out() [0x80484f1] 

ファイル名と行番号はどのように取得できますか? 私は物事に従いましたが、運はありません。私が間違っているなら、私を修正してください:)

ので
for ex:- 
./libtst.so(fun2+0x35) [0xb77dc887] 

0xb77dc887(fun2 addr+offset)-0xb77b6000 (lib starting addr) = 0x26887 (result) 
result is no way related to function in nm output. 

I used addr2line command:- 
addr2line -f -e libtst.so 0xb77dc887 
?? 
??:0 

を、どのように私はどちらか、実行時または郵便実行時に解決することができますか?事前に おかげで...

nm:- 
00000574 T _init 
00000680 t __do_global_dtors_aux 
00000700 t frame_dummy 
00000737 t __i686.get_pc_thunk.bx 
0000073c T myfunc5 
000007e7 T fun4 
00000837 T fun3 
00000885 T fun2 
000008c0 T fun1 
00000900 t __do_global_ctors_aux 
00000938 T _fini 
000009b4 r __FRAME_END__ 
00001efc d __CTOR_LIST__ 
00001f00 d __CTOR_END__ 
00001f04 d __DTOR_LIST__ 
00001f08 d __DTOR_END__ 
00001f0c d __JCR_END__ 
00001f0c d __JCR_LIST__ 
00001f10 a _DYNAMIC 
00001ff4 a _GLOBAL_OFFSET_TABLE_ 
00002030 d __dso_handle 
00002034 A __bss_start 
00002034 A _edata 
00002034 b completed.5773 
00002038 b dtor_idx.5775 
0000203c B funptr 
00002040 A _end 
    U [email protected]@GLIBC_2.1 
    U [email protected]@GLIBC_2.1 
    U [email protected]@GLIBC_2.0 
    U [email protected]@GLIBC_2.7 
    U [email protected]@GLIBC_2.0 
    U [email protected]@GLIBC_2.0 
    U [email protected]@GLIBC_2.0 
    w [email protected]@GLIBC_2.1.3 
    w __gmon_start__ 
    w _Jv_RegisterClasses 

pmap:- 
START  SIZE  RSS  PSS DIRTY SWAP PERM MAPPING 
08048000  4K  4K  4K  0K  0K r-xp /home/test/libtofun/a.out 
08049000  4K  4K  4K  4K  0K r--p /home/test/libtofun/a.out 
0804a000  4K  4K  4K  4K  0K rw-p /home/test/libtofun/a.out 
... 
b7767000  4K  4K  4K  0K  0K r-xp /home/test/libtofun/libtst.so 
b7768000  4K  4K  4K  4K  0K r--p /home/test/libtofun/libtst.so 
b7769000  4K  4K  4K  4K  0K rw-p /home/test/libtofun/libtst.so 
.... 
Total:  1688K 376K  82K  72K  0K 

128Kの書き込み可能なプライベートは、1560Kの読み取り専用プライベート、0Kは、共有、および376Kは

libtst.c:- 

void myfunc5(void){ 
int j, nptrs; 
#define SIZE 100 
void *buffer[100]; 
char **strings; 

nptrs = backtrace(buffer, SIZE); 
printf("backtrace() returned %d addresses\n", nptrs); 

strings = backtrace_symbols(buffer, nptrs); 
if (strings == NULL) { 
    perror("backtrace_symbols"); 
} 

for (j = 0; j < nptrs; j++) 
    printf("%s\n", strings[j]); 

free(strings); 
} 

void fun4(){ 
char ip; 
char *fun = "fun4\0"; 
printf("Fun name %s\n",fun); 
scanf("%c",&ip); 
myfunc5(); 
} 


void fun3(){ 
char *fun = "fun3\0"; 
printf("Fun name %s\n",fun); 
funptr = fun4; 
funptr(); 
} 


void fun2(){ 
char *fun = "fun2\0"; 
printf("Fun name %s\n",fun); 
fun3(); 
} 


void fun1(){ 
char *fun = "fun1\0"; 
printf("Fun name %s\n",fun); 
fun2(); 
} 

main.c:- 

int main(){ 
char ip; 
funptr = &fun1; 
scanf("%c",&ip); 
funptr(); 
return 0; 
} 

+1

デバッグ情報( '-g')でコンパイルしましたか? – qrdl

+0

@qrdl yes(-g)でコンパイルgcc -shared -ldl -fPIC libtst.c -o libtst.so -g – Thangaraj

+0

次に、 'backtrace_symbols()'を使用して関数名を取得します。アドレスから関数名と行番号を取得するには、dwarf情報を使用することができます。 'libdwarf'に付属の' dwarfdump'ユーティリティをチェックしてください。 – qrdl

答えて

28

セクション名とともにaddr2lineにオフセットを与えてみてください。

addr2line -j .text -e libtst.so 0x26887

編集:それは明確ではなかった場合ちなみに、0x26887はあなたが提供するものから来ている:このような

0xb77dc887(fun2 addr+offset)-0xb77b6000 (lib starting addr) = 0x26887 (result)

+0

addr2line -j .text -e libtst.so 0x26887 ??:0 ごめんなさい。 – Thangaraj

+0

あなたのベースアドレスは正しいですか?ライブラリの実行可能セクションのベースアドレスを取得していることを確認します(/ proc/pid/mapsをチェックインし、libtst.so行に 'r-xp'権限があることを確認してください)。 –

+0

ありがとうございます、ありがとうございます、addr2line -e libtst.so 0x767 /home/test/libtofun/libtst.c:16 – Thangaraj

6
...より多くの情報が必要なら、私に教えてくださいを参照しました
objdump -x --disassemble -l <objfile> 

これは、とりわけ、マシンコードのコンパイルされた各命令を、それが出たCファイルの行と一緒にダンプするはずです。

+0

私はそうではありませんでした。 objdumpとnmで試してみると、シンボルアドレスは同じです。より多くの情報が役立ちます。 – Thangaraj

+0

ライブラリをデバッグシンボルでコンパイルしていることを確認してください。 – nmichaels

+0

はい私は-gオプションでコンパイルしました... – Thangaraj

16

私が持っていましたglibcソースコード内のファイルbacktrace.cbacktracesyms.cを見てください(git://sourceware.org/git/glibc.git、コミット2482ae433a4249495859343ae1fba408300f2c2e)。

backtrace()は、実行時にシンボルアドレスだけを与えるように見えます。これは、pmapなどのライブラリロードアドレスが必要だと思います。しかし、backtrace_symbols()は、アドレスが共有ライブラリELFに相対的であり、実行時のプロセスではないように物事を再計算します。これは本当に便利です。つまり、pmapからの情報は必要ありません。

-g(または-rdynamic)を指定してコンパイルした場合は、運が良いです。あなたは、次の操作を行うことができる必要があります:

$ # get the address in the ELF so using objdump or nm 
$ nm libtst.so | grep myfunc 
0000073c T myfunc5 
$ # get the (hex) address after adding the offset 
$ # from the start of the symbol (as provided by backtrace_syms()) 
$ python -c 'print hex(0x0000073c+0x2b)' 
0x767 
$ # use addr2line to get the line information, assuming any is available    
addr2line -e libtst.so 0x767 

または、GDB使用:また

$ gdb libtst.so 
(gdb) info address myfunc 
Symbol "myfunc" is at 0x073c in a file compiled without debugging. # (Faked output) 
(gdb) info line *(0x073c+0x2b) 
Line 27 of "foo.cpp" starts at address 0x767 <myfunc()+21> and ends at 0x769 <something>. # (Faked output) 

if you've stripped the library, but stashed off debug symbols for later useを、あなたはおそらく唯一のbacktrace_syms(プリントアウトELFオフセットがあるでしょう)と無記号(元の質問にはあまり意味がないので):この例では、gdbの使用は他のコマンドラインツールを使用するよりも便利です。

$ gdb -s debug/libtst.debug -e libtst.so 

をしたあと、「インフォライン」とに応じて、「情報アドレス」を使用して、上記と同様の手順を経る:あなたはこれをやったと仮定すると、あなたは、(例えば)ので、同じようにgdbを起動する必要がありますELFシンボルオフセットのみ、またはシンボル名プラスオフセットのいずれかを持っています。eu-addr2lineと実行時に

+1

'myfunc'はすでにGDBにある有効なシンボルなので、' info line *(myfunc + 0x2b) 'を実行するだけです。 –

3

(自動的にライブラリを検索し、オフセットを計算):

//------------------------------------- 
#include <sys/types.h> 
#include <unistd.h> 

int i; 
#define SIZE 100 
void *buffer[100]; 

int nptrs = backtrace(buffer, SIZE); 

for (i = 1; i < nptrs; ++i) { 
    char syscom[1024]; 
    syscom[0] = '\0'; 
    snprintf(syscom, 1024, "eu-addr2line '%p' --pid=%d > /dev/stderr\n", buffer[i], getpid()); 
    if (system(syscom) != 0) 
     fprintf(stderr, "eu-addr2line failed\n"); 
} 

スティック--debuginfo-path=...オプションあなたのデバッグファイルはどこか別の場所(ビルドID等によって一致)している場合。

eu-addr2lineは、お住まいのディストリビューションのelfutilsパッケージに含まれています。

+1

上記の編集タブの「水平ルール」アイコンにも注意してください。あなたは質問のセクションをそれで分けることができます。どうしたら?次回質問または回答を編集するときに、編集メニューバーのヘルプを使用します。シンプルからアドバンスまで、非常に役立つ編集ガイドライン。 – clearlight

関連する問題