etiqueta definicion body c linux debugging backtrace

definicion - ¿Cómo hacer que backtrace()/backtrace_symbols() imprima los nombres de las funciones?



etiqueta title html5 (4)

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

El backtrace() específico de Linux backtrace() y backtrace_symbols() permiten 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 debajo simplemente imprime esto:

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

Me gustaría que los primeros 2 elementos también muestren los nombres de las 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; }


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

(Consulte la página Opciones de enlace del manual de GCC y / o la página Backtraces del manual de glibc ).


Utilice el comando addr2line para asignar direcciones ejecutables al código fuente nombrearchivo + número de línea. Proporcione la opción -f para obtener nombres de funciones también.

Alternativamente, pruebe libunwind .


la respuesta en la parte superior tiene un error si ret == -1 y errno es EINTER debes intentarlo de nuevo, pero no contar con ret como copiado (no va a hacer una cuenta solo por esto, si no te gusta)

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; } }