Pregunta

¿Qué métodos existen para automáticamente un seguimiento de pila en los sistemas Unix?No me refiero sólo a conseguir un archivo de núcleo o adjuntar de forma interactiva con GDB, pero tener un SIGSEGV controlador que vuelca una traza en un archivo de texto.

Puntos de bonificación para las siguientes características opcionales:

  • Información adicional reunión en crash time (por ejemplo.los archivos de configuración).
  • De correo electrónico de un accidente info bundle para los desarrolladores.
  • Capacidad para agregar esta en un dlopened biblioteca compartida
  • No requiere de una interfaz gráfica de usuario
¿Fue útil?

Solución

Si usted está en los sistemas con el BSD backtrace funcionalidad disponible (Linux, OSX 1.5, BSD, por supuesto), usted puede hacer esto mediante programación en el manejador de señal.

Por ejemplo (backtrace código derivados de ejemplo de IBM):

#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 obtener puntos de bonificación para las características opcionales (excepto que no requiere de una interfaz gráfica de usuario), sin embargo, tiene la ventaja de ser muy simple, y no requiere de bibliotecas adicionales o programas.

Otros consejos

FYI,

la propuesta de solución (utilizando backtrace_symbols en un manejador de señal) es peligrosamente roto.NO LA USE -

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

  1. backtrace_symbols asigna memoria usando malloc y uso gratuito de conexión - Si estás bloquea debido a daños en la memoria de su malloc arena es muy probable que esté dañado y causar una doble falta.

  2. malloc y free proteger la malloc arena con un bloqueo internamente.Usted puede tener falla en el medio de un malloc/free con el bloqueo, lo que hará que estos funcionen o cualquier cosa que les llama a los muertos de bloqueo.

  3. Utilice pone que utiliza la secuencia estándar, que también está protegido por una cerradura.Si usted falla en el medio de un printf una vez más tener un interbloqueo.

  4. En plataformas de 32 bits (por ejemplo,su PC normal de 2 años), el núcleo de la planta de una dirección de retorno interno de glibc función en lugar de su errores de la función de la pila, por lo que la pieza más importante de información que le interesa - en el que la función hice el error de programa, realmente estar dañado en los de la plataforma.

Así, el código en el ejemplo es el peor tipo de mal - PARECE que funciona, pero lo que realmente le fallan en formas inesperadas en la producción.

Por CIERTO, los interesados en hacer lo correcto?verificación este a cabo.

Saludos, Gilad.

Aquí está un ejemplo de cómo obtener algo más de información utilizando un demangler.Como se puede ver este también registra el stacktrace de 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);
}

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

Reciente versión del kernel de Linux permite a la tubería de volcados de núcleo a un script o programa.Podría escribir un script para coger el volcado de núcleo, recopilar cualquier información adicional que usted necesita y correo todo de nuevo.Esta es una configuración global, aunque, así que me gustaría aplicar a cualquier estrellarse programa en el sistema.También se requieren permisos de root para configurar.Puede ser configurado a través de /proc/sys/kernel/core_pattern archivo.Establecer que para algo como '| /home/miusuario/bin/mi-core-controlador de secuencia de comandos".

El Ubuntu personas utilizan esta característica.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top