2011-08-03 13 views
67

El específico de Linux backtrace() y backtrace_symbols() le permite generar un seguimiento de llamadas del programa. Sin embargo, solo imprime direcciones de función, no sus nombres para mi programa. ¿Cómo puedo hacer que impriman los nombres de las funciones también? Intenté compilar el programa con -g y -ggdb. El caso de prueba a continuación sólo imprime esto:Cómo hacer que backtrace()/backtrace_symbols() imprima los nombres de las funciones?

 

    BACKTRACE ------------ 
    ./a.out() [0x8048616] 
    ./a.out() [0x8048623] 
    /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413] 
    ./a.out() [0x8048421] 
    ---------------------- 

me gustaría que los 2 primeros elementos para mostrar también los nombres de funciones, foo y main

Código:

#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; 
} 
+0

posible duplicado de [Cómo llegar traza más detallada] (http://stackoverflow.com/questions/5945775/how-to-get-more-detailed-backtrace) – Nemo

+0

http://stackoverflow.com/questions/105659/how-can-one-grab-a-stack-trace-in-c –

Respuesta

46

se toman los símbolos de la tabla de símbolos dinámicos; necesita la opción -rdynamic para gcc, que hace que pase una bandera al vinculador que asegura que todos los símbolos se colocan en la tabla.

(Véase la página Link Options del GCC manual, y/o en la página de la Backtracesglibc manual.)

+8

Esto no funciona para símbolos estáticos, sin embargo. 'libunwind' que @Nemo menciona, funciona para funciones estáticas. –

25

Uso del addr2line command para asignar direcciones ejecutables en el código fuente de nombre de archivo + número de línea. Proporcione la opción -f para obtener nombres de funciones también.

Alternativamente, intente libunwind.

+3

La línea addr2 es agradable porque incluye el nombre del archivo y el número de línea en la salida, pero falla tan pronto como el cargador realiza las reubicaciones. –

+0

... y con las reubicaciones de ASLR son más comunes que nunca. –

+0

@ErwanLegrand: Antes de ASLR, pensaba que las reubicaciones eran predecibles y 'addr2line' funcionaba de manera confiable incluso para direcciones en objetos compartidos (?) Pero sí, en las plataformas modernas necesitabas saber la dirección de carga real del objeto reubicable incluso para hacer esta operación en principio. – Nemo

9

La excelente Libbacktrace de Ian Lance Taylor resuelve este problema. Maneja el desenrollado de la pila y admite símbolos ELF ordinarios y símbolos de depuración DWARF.

Libbacktrace no requiere exportar todos los símbolos, lo que sería feo, y ASLR no lo rompe.

Libbacktrace fue originalmente parte de la distribución de GCC. Ahora, una versión independiente se puede encontrar en Github:

https://github.com/ianlancetaylor/libbacktrace

1

la respuesta en la parte superior tiene un error si ret == -1 y errno es EINTER usted debe tratar de nuevo, pero no cuenta como ret copiado (no va a hacer una cuenta sólo para esto, si no te gusta que sea difícil)

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) { 
         if (errno != EINTR)) 
           break; 
         //else 
         continue; 
       } 
       buf += (size_t) ret; 
       len -= (size_t) ret; 
     } 
} 
Cuestiones relacionadas