69 votes

Trace de pile pour C ++ en utilisant gcc

Nous utilisons les traces de pile propriétaires assert comme macro pour attraper développeur erreurs - quand l'erreur est capturé, trace de la pile est imprimé.

- Je trouver du ccg paire backtrace()/backtrace_symbols() méthodes insuffisante:

  1. Les noms sont déformés
  2. Pas d'information en ligne

1er problème peut être résolu par abi::__cxa_demangle.

Cependant 2ème problème est plus difficile. J'ai trouvé de remplacement pour backtrace_symbols(). C'est mieux que de gcc backtrace_symbols(), car il peut récupérer les numéros de ligne (si compilé avec-g) et vous n'avez pas besoin de compiler avec -rdynamic.

Hoverer le code est GNU homologuée, donc à mon humble avis, je ne peux pas l'utiliser dans le code de commerce.

Toute proposition?

P. S.

gdb est capable d'imprimer les arguments passés aux fonctions. Probablement, il est déjà trop demander :)

PS 2

Question similaire (merci nobar)

47voto

nobar Points 5849

Donc, vous voulez un stand-alone, fonction qui imprime une trace de la pile avec toutes les fonctionnalités que gdb traces de pile et que ne pas mettre fin à votre application. La réponse est d'automatiser le lancement de gdb dans un mode non-interactif pour exécuter les tâches que vous souhaitez.

Ceci est fait par l'exécution de gdb dans un enfant de processus avec fork(), et un script pour afficher un stack-trace pendant que votre application attend pour la mener à bien. Cela peut être effectué sans l'utilisation d'un core dump et sans l'abandon de la demande. J'ai appris à le faire à partir de cette question: Comment il est préférable d'appeler les gdb de programme pour imprimer c'est stacktrace?

L'exemple posté cette question n'a pas fonctionné pour moi, exactement comme c'est écrit, donc voici mon "fixe" version (j'ai couru ce sur Ubuntu 9.04).

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

void print_trace() {
    char pid_buf[30];
    sprintf(pid_buf, "%d", getpid());
    char name_buf[512];
    name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
    int child_pid = fork();
    if (!child_pid) {           
        dup2(2,1); // redirect output to stderr
        fprintf(stdout,"stack trace for %s pid=%s\n",name_buf,pid_buf);
        execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf, pid_buf, NULL);
        abort(); /* If gdb failed to start */
    } else {
        waitpid(child_pid,NULL,0);
    }
}

Comme indiqué dans le référencés question, gdb offre des options supplémentaires que vous pouvez utiliser. Par exemple, à l'aide de "bt full" au lieu de "bt" génère un même rapport plus détaillé (les variables locales sont inclus dans la sortie). Les pages de manuel pour gdb sont une sorte de lumière, mais la documentation complète est disponible ici.

Depuis ceci est basé sur gdb, la sortie inclut demangled noms, line-numbers, les arguments de la fonction, et éventuellement même des variables locales. Aussi, gdb est thread-conscient, de sorte que vous devriez être en mesure d'extraire certains thread spécifique de métadonnées.

Voici un exemple du genre de traces de pile que je vois avec cette méthode.

0x00007f97e1fc2925 in waitpid () from /lib/libc.so.6
[Current thread is 0 (process 15573)]
#0  0x00007f97e1fc2925 in waitpid () from /lib/libc.so.6
#1  0x0000000000400bd5 in print_trace () at ./demo3b.cpp:496
2  0x0000000000400c09 in recursive (i=2) at ./demo3b.cpp:636
3  0x0000000000400c1a in recursive (i=1) at ./demo3b.cpp:646
4  0x0000000000400c1a in recursive (i=0) at ./demo3b.cpp:646
5  0x0000000000400c46 in main (argc=1, argv=0x7fffe3b2b5b8) at ./demo3b.cpp:70

Remarque: j'ai trouvé ceci pour être incompatible avec l'utilisation de valgrind (probablement en raison de Valgrind de l'utilisation d'une machine virtuelle). Il ne fonctionne pas lorsque vous exécutez le programme à l'intérieur d'une session gdb (ne peut pas appliquer une deuxième instance de "ptrace" à un processus).

35voto

karlphillip Points 46502

Il n'y a pas si longtemps, j'ai répondu à une question similaire . Vous devriez jeter un coup d'œil au code source disponible dans la méthode n ° 4, qui affiche également les numéros de ligne et les noms de fichiers.

11voto

nobar Points 5849

Il y a un examen approfondi des essentiellement la même question: Comment générer une stacktrace quand mon gcc C++ application se bloque. De nombreuses suggestions sont fournis, y compris beaucoup de discussions sur la façon de générer les traces de pile au moment de l'exécution.

Mon favori personnel à répondre à partir de ce thread est de permettre core dumps qui vous permet de visualiser la totalité de l'application de l'état au moment de l'accident (y compris les arguments de la fonction, les numéros de ligne, et unmangled noms). Un autre avantage de cette approche est qu'elle ne travaille pas seulement pour l'affirme, mais aussi pour la segmentation défauts et les exceptions non gérées.

Linux coquilles d'utiliser les différentes commandes pour activer core dumps, mais vous pouvez le faire à partir de votre code d'application avec quelque chose comme ça...

#include <sys/resource.h>
...
rlimit core_limit = { RLIM_INFINITY, RLIM_INFINITY };
assert( setrlimit( RLIMIT_CORE, &core_limit ) == 0 ); // enable core dumps for debug builds

Après un crash, exécuter votre favori débogueur pour examiner le programme de l'état.

$ kdbg executable core

Voici un exemple de sortie...

alt text

Il est également possible d'extraire la trace de la pile d'un core dump sur la ligne de commande.

$ ( CMDFILE=$(mktemp); echo "bt" >${CMDFILE}; gdb 2>/dev/null --batch -x ${CMDFILE} temp.exe core )
Core was generated by `./temp.exe'.
Program terminated with signal 6, Aborted.
[New process 22857]
#0  0x00007f4189be5fb5 in raise () from /lib/libc.so.6
#0  0x00007f4189be5fb5 in raise () from /lib/libc.so.6
#1  0x00007f4189be7bc3 in abort () from /lib/libc.so.6
#2  0x00007f4189bdef09 in __assert_fail () from /lib/libc.so.6
#3  0x00000000004007e8 in recursive (i=5) at ./demo1.cpp:18
#4  0x00000000004007f3 in recursive (i=4) at ./demo1.cpp:19
#5  0x00000000004007f3 in recursive (i=3) at ./demo1.cpp:19
#6  0x00000000004007f3 in recursive (i=2) at ./demo1.cpp:19
#7  0x00000000004007f3 in recursive (i=1) at ./demo1.cpp:19
#8  0x00000000004007f3 in recursive (i=0) at ./demo1.cpp:19
#9  0x0000000000400849 in main (argc=1, argv=0x7fff2483bd98) at ./demo1.cpp:26

6voto

Utilisez le google glog bibliothèque pour elle. Il a une nouvelle licence BSD.

Il contient un GetStackTrace fonction dans la stacktrace.h fichier.

MODIFIER

J'ai trouvé ici http://blog.bigpixel.ro/2010/09/09/stack-unwinding-stack-trace-with-gcc/ qu'il s'agit d'un utilitaire appelé addr2line qui traduit programme d'adresses dans le fichier des noms et des numéros de ligne.

http://linuxcommand.org/man_pages/addr2line1.html

6voto

KeithB Points 9459

Étant donné que le code sous licence GPL est conçu pour vous aider pendant le développement, vous pouvez simplement ne pas l'inclure dans le produit final. La GPL vous interdit de distribuer du code de licence GPL associé à un code non compatible GPL. Tant que vous n'utilisez que le code GPL en interne, ça devrait aller.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X