Das Linux-spezifische backtrace()
und backtrace_symbols()
ermöglicht es Ihnen, eine Aufrufverfolgung des Programms zu erstellen. Es werden jedoch nur Funktionsadressen gedruckt, nicht deren Namen für mein Programm. Wie kann ich sie dazu bringen, auch die Funktionsnamen zu drucken? Ich habe versucht , mit dem Programm zusammenzustellen -g
sowie -ggdb
. Der folgende Testfall druckt nur Folgendes:
HINTERGRUND ------------ ./a.out () [0x8048616] ./a.out () [0x8048623] /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413] ./a.out () [0x8048421] ----------------------
Ich würde die ersten 2 Artikel wollen auch die Funktionsnamen zeigen, foo
undmain
Code:
#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
static void full_write(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) && (errno != EINTR))
break;
buf += (size_t) ret;
len -= (size_t) ret;
}
}
void print_backtrace(void)
{
static const char start[] = "BACKTRACE ------------\n";
static const char end[] = "----------------------\n";
void *bt[1024];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 1024);
bt_syms = backtrace_symbols(bt, bt_size);
full_write(STDERR_FILENO, start, strlen(start));
for (i = 1; i < bt_size; i++) {
size_t len = strlen(bt_syms[i]);
full_write(STDERR_FILENO, bt_syms[i], len);
full_write(STDERR_FILENO, "\n", 1);
}
full_write(STDERR_FILENO, end, strlen(end));
free(bt_syms);
}
void foo()
{
print_backtrace();
}
int main()
{
foo();
return 0;
}
backtrace_symbols_fd
führt die Funktion dieselbe Operation aus wiebacktrace_symbols()
, aber die resultierenden Zeichenfolgen werden sofort in den Dateideskriptor geschriebenfd
.Antworten:
Die Symbole stammen aus der dynamischen Symboltabelle. Sie benötigen die
-rdynamic
Option togcc
, wodurch ein Flag an den Linker übergeben wird, der sicherstellt, dass alle Symbole in der Tabelle platziert werden.(Siehe die Seite Link Options des GCC-Handbuchs und / oder die Backtraces- Seite des glibc-Handbuchs .)
quelle
libunwind
dass @Nemo erwähnt, funktioniert für statische Funktionen.ADD_COMPILE_OPTIONS(-rdynamic)
. Stattdessen muss esADD_LINK_OPTIONS(-rdynamic)
gleichwertig sein, um das gewünschte Verhalten zu erzielen.Verwenden Sie den Befehl addr2line , um ausführbare Adressen dem Quellcode-Dateinamen + der Zeilennummer zuzuordnen. Geben Sie die
-f
Option an, auch Funktionsnamen abzurufen.Alternativ können Sie auch libunwind ausprobieren .
quelle
addr2line
auch für Adressen in gemeinsam genutzten Objekten zuverlässig funktionieren (?). Aber ja, auf modernen Plattformen müssten Sie die tatsächliche Ladeadresse des verschiebbaren Objekts kennen, um diesen Vorgang im Prinzip ausführen zu können .Die exzellente Libbacktrace von Ian Lance Taylor löst dieses Problem. Es behandelt das Abwickeln von Stapeln und unterstützt sowohl normale ELF-Symbole als auch DWARF-Debugging-Symbole.
Libbacktrace erfordert nicht das Exportieren aller Symbole, was hässlich wäre, und ASLR bricht es nicht.
Libbacktrace war ursprünglich Teil der GCC-Distribution. Jetzt kann eine eigenständige Version auf Github gefunden werden:
https://github.com/ianlancetaylor/libbacktrace
quelle
Die Antwort oben hat einen Fehler, wenn ret == -1 und errno EINTER ist. Sie sollten es erneut versuchen, aber ret nicht als kopiert zählen (Sie werden kein Konto nur dafür erstellen, wenn Sie es nicht schwer mögen).
quelle
Boost Backtrace
Sehr praktisch, da beide gedruckt werden:
automatisch für Sie.
Nutzungsübersicht:
Ich habe ein minimales ausführbares Beispiel dafür und viele andere Methoden bereitgestellt: Druckaufrufstapel in C oder C ++
quelle