So ordnen Sie die Funktionsadresse einer Funktion in *.so-Dateien zu

Lesezeit: 7 Minuten

Benutzeravatar von Thangaraj
Thangaraj

Backtrace-Funktion Geben Sie einen Backtrace-Satz an, wie Sie ihn dem Funktionsnamen / Dateinamen / der Zeilennummer zuordnen?

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]

Wie kann ich aus dem obigen Stapel den Dateinamen und die Zeilennummer erhalten? Ich habe folgende Dinge getan, aber kein Glück. Korrigiert mich, wenn ich falsch liege 🙂

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

Wie kann ich also entweder zur Laufzeit oder nach der Laufzeit auflösen? Danke im Voraus…

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

128 KB beschreibbar – privat, 1560 KB schreibgeschützt – privat, 0 KB gemeinsam genutzt und 376 KB referenziert

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;
}

Lassen Sie mich wissen, wenn Sie weitere Informationen benötigen …

  • Haben Sie mit Debug-Informationen kompiliert (-g)?

    – qrdl

    26. September 2011 um 13:57 Uhr

  • @qrdl ja kompiliert mit (-g) gcc -shared -ldl -fPIC libtst.c -o libtst.so -g

    – Thangaraj

    26. September 2011 um 13:59 Uhr

  • Dann benutze backtrace_symbols() um Funktionsnamen zu erhalten. Um Funktionsnamen und Zeilennummern von Adressen zu erhalten, können Sie Zwerginformationen verwenden – prüfen dwarfdump Dienstprogramm, das mit kommt libdwarf.

    – qrdl

    26. September 2011 um 14:05 Uhr

Benutzeravatar von tdenniston
tdenniston

Versuchen Sie, den Offset zusammen mit dem Abschnittsnamen an addr2line zu übergeben. So was:

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

Edit: Übrigens, wenn es nicht klar war, die 0x26887 kommt von dem was du angegeben hast:

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

  • addr2line -j .text -e libtst.so 0x26887 ??:0 Entschuldigung kein Glück.

    – Thangaraj

    27. September 2011 um 4:02 Uhr

  • Sind Sie sicher, dass Ihre Basisadresse korrekt ist? Stellen Sie sicher, dass Sie die Basisadresse des ausführbaren Abschnitts der Bibliothek erhalten (checken Sie /proc/pid/maps ein und finden Sie die Zeile libtst.so mit ‘r-xp’-Berechtigungen).

    – tdenniston

    27. September 2011 um 13:58 Uhr

  • Können Sie für einen kompletten Neuling bitte erklären, wie dies abgeleitet wurde: 0xb77dc887(fun2 addr+offset)

    – mdk

    2. Mai 2013 um 10:58 Uhr

  • Meine Vermutung ist das ./libtst.so(fun2+0x35) [0xb77dc887] stammt aus dem Stacktrace des leicht modifizierten Programms + libtst.so wurde an einer anderen Adresse geladen, verursacht denselben Offset in derselben Funktion (fun2+0x35) hat eine andere Adresse und der Unterschied zwischen den Adressen 0xb77dc887 – 0xb77678ba == 0x00074fcd1 ist kein Vielfaches der Seitengröße (4096 für Linux). Die Basisadresse der Bibliothek kann sich aufgrund von ASLR von Start zu Start ändern (en.wikipedia.org/wiki/Address_space_layout_randomization).

    – Andrey Starodubtsev

    31. Januar 2019 um 18:01 Uhr

  • @ch271828n Sie können einfach verwenden objdump -h libtst.so und das Feld sehen start address

    – kaixin liu

    15. November 2021 um 13:00 Uhr

Benutzeravatar von Rob
rauben

Ich habe mir die Akten angesehen backtrace.c und backtracesyms.c Dateien im glibc-Quellcode (git://sourceware.org/git/glibc.git, commit 2482ae433a4249495859343ae1fba408300f2c2e).

Vorausgesetzt, ich habe nichts falsch gelesen/missverstanden: Rückverfolgung () selbst sieht so aus, als würde es Ihnen nur Symboladressen geben, wie sie zur Laufzeit sind, was meiner Meinung nach bedeutet, dass Sie die Bibliotheksladeadresse so benötigen, wie sie von pmap oder ähnlichem war. Jedoch, backtrace_symbols() berechnet die Dinge neu, sodass die Adressen relativ zur gemeinsam genutzten Bibliothek ELF sind und nicht zum Prozess zur Laufzeit, was sehr praktisch ist. Das bedeutet, dass Sie keine Informationen von pmap benötigen.

Wenn Sie also mit -g (oder mit -rdynamic) kompiliert haben, dann haben Sie Glück. Sie sollten Folgendes können:

$ # 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

Oder mit 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)

Wenn Sie die Bibliothek entfernt, aber Debug-Symbole für die spätere Verwendung abgelegt haben, werden Sie wahrscheinlich nur ELF-Offsets von backtrace_syms() und keine Symbolnamen ausgeben (also nicht ganz der Fall in der ursprünglichen Frage): In diesem Fall ist die Verwendung von gdb wohl bequemer als die Verwendung anderer Befehlszeilentools. Angenommen, Sie haben dies getan, müssen Sie gdb wie folgt aufrufen (zum Beispiel):

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

Gehen Sie dann eine ähnliche Sequenz wie oben durch und verwenden Sie „Info-Zeile“ und „Info-Adresse“, je nachdem, ob Sie nur ELF-Symbol-Offsets oder Symbolnamen plus Offsets haben.

  • Seit myfunc ist bereits ein gültiges Symbol in GDB, das Sie einfach tun können info line *(myfunc+0x2b).

    – Michael Anderson

    31. Januar 2017 um 4:20 Uhr

Benutzeravatar von nmichaels
nmichaels

objdump -x --disassemble -l <objfile>

Dies sollte unter anderem jede kompilierte Anweisung des Maschinencodes mit der Zeile der C-Datei ausgeben, aus der sie stammt.

  • Ich wusste nicht, was das bedeutet. Wenn ich es mit objdump und nm versuche, ist die Symboladresse gleich. Mehr Informationen wären hilfreich.

    – Thangaraj

    26. September 2011 um 14:03 Uhr


  • Stellen Sie sicher, dass Sie Ihre Bibliothek mit Debugging-Symbolen kompilieren.

    – nmichaels

    26. September 2011 um 14:08 Uhr

Velkans Benutzeravatar
Velkan

Zur Laufzeit mit eu-addr2line (findet automatisch die Bibliotheken und berechnet Offsets):

//-------------------------------------
#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");
}

Kleben Sie a --debuginfo-path=... Option, wenn sich Ihre Debug-Dateien woanders befinden (übereinstimmend mit der Build-ID usw.).

eu-addr2line ist in dem elfutils Paket Ihrer Distribution.

1403260cookie-checkSo ordnen Sie die Funktionsadresse einer Funktion in *.so-Dateien zu

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy