Comment faire backtrace()/backtrace_symbols() imprimer les noms de fonction?
La spécifique à Linux backtrace()
et backtrace_symbols()
permet de produire une trace d'appel du programme. Cependant, il n'imprime que des adresses de fonction, pas leurs noms pour mon programme. Comment puis-je faire imprimer les noms de fonction en tant que bien ? J'ai essayé de compiler le programme avec -g
ainsi que -ggdb
. Le cas de test ci-dessous imprime juste ceci:
BACKTRACE ------------ ./un.out() [0x8048616] ./un.out() [0x8048623] /lib/libc.donc.6(__libc_start_principaux+0xf3) [0x4a937413] ./un.out() [0x8048421] ----------------------
Je veux les 2 premiers éléments de montrer aussi les noms de fonction, foo
et main
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;
}
- double possible de Comment obtenir plus de détails backtrace
- btw, la fonction
backtrace_symbols_fd
effectue la même opération quebacktrace_symbols()
, mais le résultat de chaînes sont immédiatement enregistrées dans le fichier descripteur defd
. - J'ai testé plusieurs méthodes de détails: stackoverflow.com/questions/3899870/print-call-stack-in-c-or-c/...
Vous devez vous connecter pour publier un commentaire.
Les symboles sont prises à partir de la dynamique de la table des symboles; vous avez besoin de la
-rdynamic
option pourgcc
, qui le fait passer d'un drapeau à l'éditeur de liens qui assure que tous symboles sont placés dans le tableau.(Voir la Options De Liaison page de la Manuel de GCC, et /ou la Backtraces page de la la glibc manuel.)
libunwind
que @Nemo mentionne, travaille pour des fonctions statiques.Utiliser le addr2line commande à la carte exécutable adresses à code source nom de fichier+le numéro de ligne. Donner la
-f
option pour obtenir les noms de fonction en tant que bien.Sinon, essayez libunwind.
addr2line
travaillé de manière fiable, même pour les adresses dans les objets partagés (?) Mais oui, sur les plateformes modernes vous besoin de connaître la véritable adresse de chargement du transférable, l'objet même de faire cette opération en principe.L'excellent Libbacktrace par Ian Lance Taylor résout ce problème. Il gère le déroulement de pile et prend en charge à la fois ordinaire ELFE symboles et les NAINS, les symboles de débogage.
Libbacktrace ne nécessite pas l'exportation de tous les symboles, ce qui serait moche, et ASLR ne pas le casser.
Libbacktrace était à l'origine partie de la GCC de distribution. Maintenant, une version autonome peut être trouvé sur Github:
https://github.com/ianlancetaylor/libbacktrace
la réponse sur le haut a un bug
si ret == -1 et errno est EINTER vous devriez essayer à nouveau, mais ne pas compter ret as copié
(ne va pas faire un compte juste pour ça, si vous ne l'aimez pas dur)