2008-08-20 17 views
7

¿Qué métodos existen para obtener automáticamente un seguimiento de pila en sistemas Unix? No me refiero solo a obtener un archivo central o adjuntar de forma interactiva con GDB, sino tener un controlador SIGSEGV que vuelca una traza inversa a un archivo de texto.Obteniendo rastros de pila en sistemas Unix, automáticamente

puntos de bonificación para las siguientes funciones opcionales: (ej.) Archivos de configuración Las

  • recopilación de información adicional en el momento del accidente.
  • Envíe por correo electrónico un paquete de información de bloqueo a los desarrolladores.
  • Posibilidad de añadir esto en una biblioteca compartida dlopen ed
  • que no requieren una interfaz gráfica de usuario

Respuesta

7

Si se encuentra en los sistemas con la funcionalidad BSD backtrace disponible (Linux, OS X 1.5, BSD, por supuesto), se puede haz esto programáticamente en tu manejador de señal.

Por ejemplo (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(); 
} 

Salida:

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 

esto no consigue puntos de bonificación para las características opcionales (excepto que no requiere una interfaz gráfica de usuario), sin embargo, sí tiene la ventaja de ser muy simple y no requerir bibliotecas o programas adicionales.

2

solución Dereks es probablemente la mejor, pero aquí es una alternativa de todos modos:

reciente versión del núcleo de Linux que permite al núcleo de la tubería vuelca a un script o programa. Podría escribir un script para atrapar el volcado principal, recopilar cualquier información adicional que necesite y enviarlo por correo. Sin embargo, esta es una configuración global, por lo que se aplicaría a cualquier programa bloqueado en el sistema. También requerirá derechos de root para configurar. Se puede configurar a través del archivo/proc/sys/kernel/core_pattern. Ponlo en algo como '|/home/myuser/bin/my-core-handler-script '.

Las personas de Ubuntu también usan esta característica.

4

Aquí hay un ejemplo de cómo obtener más información usando un demandedor. Como puede ver, este también registra stacktrace en el archivo.

#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

usando C++ en manejadores de señales - bug en el genoma. –

15

FYI,

la solución sugerida (usando backtrace_symbols en un controlador de señal) es peligrosamente roto. No lo utilice -

Sí, traza y backtrace_symbols producirán una traza inversa y sin embargo, un traducirlo a nombres simbólicos,:

  1. backtrace_symbols asigna memoria usando malloc y uso gratuito para liberarla - Si Estás fallando debido a la corrupción de la memoria. Es muy probable que tu malloc arena esté corrupta y cause un doble error.

  2. malloc y protegen libremente la arena malloc con un bloqueo interno.Es posible que haya fallo en el medio de un malloc/libre con la cerradura tomada, lo que hará que estas funciones o cualquier cosa que les llama a bloqueo de la muerte.

  3. Se utilizan pone que utiliza la corriente estándar, que también está protegido por una cerradura. Si cometió una falla en el medio de una impresión, una vez más tiene un punto muerto.

  4. En plataformas de 32 bits (por ejemplo, tu PC normal de hace 2 años), el kernel establecerá una dirección de retorno para una función Glibc interna en lugar de tu función de fallas en tu pila, por lo que la información más importante eres interesado - en qué función falló el programa, en realidad estará dañado en esa plataforma.

Por lo tanto, el código del ejemplo es la peor clase de mal - parece que está funcionando, pero realmente le fallar de forma inesperada en la producción.

Por cierto, interesados ​​en hacer las cosas bien? verifique this fuera.

Cheers, Gilad.

+3

Siempre que el enlace esté muerto. – bltxd

+0

No estoy terriblemente versado en la zona. Pero si el tenedor y ejecutar un rastreo en el proceso hijo que podría salirse con, ¿no? – LiquidityC

Cuestiones relacionadas