Obtention automatique des traces de pile sur les systèmes Unix


7

Quelles sont les méthodes permettant d'obtenir automatiquement une trace de pile sur les systèmes Unix? Je ne veux pas simplement obtenir un fichier core ou l'attacher interactivement avec GDB, mais avoir un gestionnaire SIGSEGV qui sauvegarde une trace arrière dans un fichier texte.

points de bonus pour les fonctions optionnelles suivantes: (par exemple les fichiers. Config)

  • Informations supplémentaires collecte au moment de l'accident.
  • Envoyez un lot d'informations de plantage aux développeurs.
  • Possibilité d'ajouter ceci dans une bibliothèque partagée ed dlopen
  • Ne nécessitant pas une interface graphique
7

Si vous êtes sur des systèmes avec la fonctionnalité BSD backtrace disponibles (Linux, Mac OS X 1.5, BSD bien sûr), vous pouvez Faites-le par programmation dans votre gestionnaire de signal.

Par exemple (backtrace code derived from IBM example):

#include <execinfo.h> 
#include <signal.h> 
#include <stdio.h> 
#include <stdlib.h> 

void sig_handler(int sig) 
{ 
    void * array[25]; 
    int nSize = backtrace(array, 25); 
    char ** symbols = backtrace_symbols(array, nSize); 

    for (int i = 0; i < nSize; i++) 
    { 
     puts(symbols[i]);; 
    } 

    free(symbols); 

    signal(sig, &sig_handler); 
} 

void h() 
{ 
    kill(0, SIGSEGV); 
} 

void g() 
{ 
    h(); 
} 

void f() 
{ 
    g(); 
} 

int main(int argc, char ** argv) 
{ 
    signal(SIGSEGV, &sig_handler); 
    f(); 
} 

Sortie:

0 a.out        0x00001f2d sig_handler + 35 
1 libSystem.B.dylib     0x95f8f09b _sigtramp + 43 
2 ???         0xffffffff 0x0 + 4294967295 
3 a.out        0x00001fb1 h + 26 
4 a.out        0x00001fbe g + 11 
5 a.out        0x00001fcb f + 11 
6 a.out        0x00001ff5 main + 40 
7 a.out        0x00001ede start + 54 

Cela ne reçoit pas des points de bonus pour les fonctions optionnelles (sauf ne nécessitant pas une interface graphique), cependant, elle a l'avantage d'être très simple, et ne nécessitant pas de bibliothèques ou de programmes supplémentaires.


2

solution Dereks est probablement le meilleur, mais voici une alternative quand même:

récente version du noyau Linux vous permettent de noyau de tuyau dépotoirs à un script ou un programme. Vous pouvez écrire un script pour récupérer le core dump, collecter toutes les informations supplémentaires dont vous avez besoin et tout renvoyer. Il s'agit d'un paramètre global, il s'applique donc à tout programme qui plante sur le système. Cela nécessitera également la création de droits root. Il peut être configuré via le fichier/proc/sys/kernel/core_pattern. Réglez cela à quelque chose comme '|/home/monutilisateur/bin/mon-core-handler-script '.

Les utilisateurs d'Ubuntu utilisent également cette fonctionnalité.


4

Voici un exemple de la façon d'obtenir plus d'informations à l'aide d'un démangeur. Comme vous pouvez le voir, celui-ci enregistre également la pile dans le fichier.

#include <iostream> 
#include <sstream> 
#include <string> 
#include <fstream> 
#include <cxxabi.h> 

void sig_handler(int sig) 
{ 
    std::stringstream stream; 
    void * array[25]; 
    int nSize = backtrace(array, 25); 
    char ** symbols = backtrace_symbols(array, nSize); 
    for (unsigned int i = 0; i < size; i++) { 
     int status; 
     char *realname; 
     std::string current = symbols[i]; 
     size_t start = current.find("("); 
     size_t end = current.find("+"); 
     realname = NULL; 
     if (start != std::string::npos && end != std::string::npos) { 
      std::string symbol = current.substr(start+1, end-start-1); 
      realname = abi::__cxa_demangle(symbol.c_str(), 0, 0, &status); 
     } 
     if (realname != NULL) 
      stream << realname << std::endl; 
     else 
      stream << symbols[i] << std::endl; 
     free(realname); 
    } 
    free(symbols); 
    std::cerr << stream.str(); 
    std::ofstream file("/tmp/error.log"); 
    if (file.is_open()) { 
     if (file.good()) 
      file << stream.str(); 
     file.close(); 
    } 
    signal(sig, &sig_handler); 
} 
+1

en utilisant C++ dans les gestionnaires de signaux - bug dans le génome. 05 janv.. 102010-01-05 08:54:40


15

FYI,

la solution proposée (en utilisant backtrace_symbols dans un gestionnaire de signaux) est dangereusement rompu. NE PAS UTILISER -

Oui, backtrace et backtrace_symbols produiront un backtrace et traduire les noms symboliques, cependant:

  1. backtrace_symbols alloue de la mémoire à l'aide malloc et que vous utilisez sans pour le libérer - Si vous crash à cause de la corruption de la mémoire de votre arène malloc est très susceptible d'être corrompu et causer une double faute. Malloc et gratuitement protègent l'arène de malloc avec une serrure intérieurement.Vous pourriez avoir blâmé au milieu d'un malloc/libre avec le verrou pris, ce qui causera ces fonctions ou tout ce qui les appelle à un verrouillage mort.

  2. Vous utilisez puts qui utilise le flux standard, qui est également protégé par un verrou. Si vous avez failli au milieu d'un printf vous avez encore une fois une impasse. Sur les plates-formes 32 bits (par exemple, votre PC normal d'il y a 2 ans), le noyau plantera une adresse de retour vers une fonction de glibc interne au lieu de votre fonction de défaut dans votre pile, donc l'information la plus importante intéressé par - dans quelle fonction a le défaut du programme, sera effectivement corrompu sur ces plate-forme.

Ainsi, le code dans l'exemple est le pire des mauvais - il semble que cela fonctionne, mais il va vraiment vous manquer de façon inattendue dans la production.

BTW, intéressé à le faire correctement? vérifier this sur.

Cheers, Gilad.

+3

Le lien fourni est mort. 27 mai. 102010-05-27 13:23:39

  0

Je ne suis pas très versé dans la région. Mais si vous bifurquez et exécutez le backtracing dans le processus enfant, vous pourriez vous en sortir, non? 26 févr.. 182018-02-26 21:40:10