El específico de Linux backtrace()
y le backtrace_symbols()
permite producir un seguimiento de llamadas del programa. Sin embargo, solo imprime direcciones de funciones, no sus nombres para mi programa. ¿Cómo puedo hacer que impriman también los nombres de las funciones? He intentado compilar el programa con -g
, así como -ggdb
. El caso de prueba a continuación simplemente imprime esto:
RETROCESO ------------ ./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 mostraran los nombres de las funciones, foo
ymain
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;
}
backtrace_symbols_fd
realiza la misma operación quebacktrace_symbols()
, pero las cadenas resultantes se escriben inmediatamente en el descriptor de archivofd
.Respuestas:
Los símbolos se toman de la tabla de símbolos dinámicos; necesita la
-rdynamic
opcióngcc
, lo que hace que pase una bandera al enlazador que garantiza que todos los símbolos se coloquen en la tabla.(Consulte la página de Opciones de enlace del manual de GCC y / o la página de Backtraces del manual de glibc ).
fuente
libunwind
que @Nemo menciona, funciona para funciones estáticas.ADD_COMPILE_OPTIONS(-rdynamic)
. En cambio, debe serADD_LINK_OPTIONS(-rdynamic)
o equivalente para tener el comportamiento deseado.Utilice el comando addr2line para asignar direcciones ejecutables al código fuente nombre de archivo + número de línea. Dé la
-f
opción de obtener también nombres de funciones.Alternativamente, pruebe libunwind .
fuente
addr2line
funcionaban de manera confiable incluso para direcciones en objetos compartidos (?) Pero sí, en las plataformas modernas necesitaría saber la dirección de carga real del objeto reubicable incluso para hacer esta operación en principio .El excelente Libbacktrace de Ian Lance Taylor resuelve este problema. Maneja el desenrollado de la pila y admite tanto los símbolos ELF ordinarios como los 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 era originalmente parte de la distribución de GCC. Ahora, se puede encontrar una versión independiente en Github:
https://github.com/ianlancetaylor/libbacktrace
fuente
la respuesta en la parte superior tiene un error si ret == -1 y errno es EINTER, debería intentarlo de nuevo, pero no contar ret como copiado (no va a crear una cuenta solo para esto, si no le gusta)
fuente
Impulsar el seguimiento
Muy conveniente porque imprime ambos:
automáticamente para usted.
Resumen de uso:
He proporcionado un ejemplo mínimo ejecutable para él y muchos otros métodos en: print call stack en C o C ++
fuente