Le spécifique Linux backtrace()
et backtrace_symbols()
vous permet de produire une trace d'appel du programme. Cependant, il n'imprime que les adresses de fonction, pas leurs noms pour mon programme. Comment puis-je leur faire imprimer également les noms des fonctions? J'ai essayé de compiler le programme avec -g
ainsi que -ggdb
. Le cas de test ci-dessous imprime simplement ceci:
RETOUR ------------ ./a.out () [0x8048616] ./a.out () [0x8048623] /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413] ./a.out () [0x8048421] ----------------------
Je voudrais que les 2 premiers éléments affichent également les noms des fonctions, foo
etmain
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
effectue la même opération quebacktrace_symbols()
, mais les chaînes résultantes sont immédiatement écrites dans le descripteur de fichierfd
.Réponses:
Les symboles sont tirés de la table des symboles dynamiques; vous avez besoin de l'
-rdynamic
option togcc
, qui lui fait passer un drapeau à l'éditeur de liens qui garantit que tous les symboles sont placés dans la table.(Voir la page Options de lien du manuel GCC et / ou la page Backtraces du manuel de la glibc .)
la source
libunwind
que @Nemo mentionne, fonctionne pour les fonctions statiques.ADD_COMPILE_OPTIONS(-rdynamic)
. Au lieu de cela, il doit êtreADD_LINK_OPTIONS(-rdynamic)
ou équivalent pour avoir le comportement souhaité.Utilisez la commande addr2line pour mapper les adresses exécutables sur le nom de fichier du code source + le numéro de ligne. Donner la
-f
possibilité d'obtenir des noms de fonctions.Sinon, essayez libunwind .
la source
addr2line
fonctionnaient de manière fiable même pour les adresses dans des objets partagés (?) Mais oui, sur les plates-formes modernes, vous auriez besoin de connaître l'adresse de charge réelle de l'objet déplaçable même pour effectuer cette opération en principe .L'excellent Libbacktrace d'Ian Lance Taylor résout ce problème. Il gère le déroulement de la pile et prend en charge les symboles ELF ordinaires et les symboles de débogage DWARF.
Libbacktrace ne nécessite pas d'exporter tous les symboles, ce qui serait laid, et ASLR ne le casse pas.
Libbacktrace faisait à l'origine partie de la distribution GCC. Maintenant, une version autonome peut être trouvée sur Github:
https://github.com/ianlancetaylor/libbacktrace
la source
la réponse en haut a un bogue si ret == -1 et errno est EINTER, vous devriez réessayer, mais ne comptez pas ret comme copié (vous ne ferez pas de compte juste pour cela, si vous n'aimez pas ça difficile)
la source
Boost backtrace
Très pratique car il imprime à la fois:
automatiquement pour vous.
Résumé de l'utilisation:
J'ai fourni un exemple minimal exécutable pour cela et de nombreuses autres méthodes à: print pile d'appels en C ou C ++
la source