c++ c callstack backtrace binutils

c++ - Números de línea incorrectos de addr2line



callstack backtrace (2)

Intento encontrar la línea exacta de una llamada en el backtrace en el programa C ++. Ahora mismo estoy usando estas líneas (de la página del manual de backtrace) para obtener el rastreo:

void *bt_buffer[1000]; char **bt_strings; int bt_nptrs = backtrace(bt_buffer, 1000); bt_strings = backtrace_symbols(bt_buffer, bt_nptrs);

En bt_strings encuentro líneas de la forma.

./prog() [0x402e42]

Ahora tomo la dirección (la cadena hexadecimal) y la paso a addr2line. Eso a veces resulta en números de línea aparentemente incorrectos. La búsqueda en internet me llevó a este post , en el que se muestra que

readelf -wl ./prog

indica dónde está realmente la línea, o más bien cuántas líneas se ha movido el símbolo a la línea actual.

edición: esto sucede cuando compilo con -g -O0 , es decir, explícitamente sin optimizaciones. El compilador es gcc 4.6.3 ¿Hay otro indicador del compilador que echo de menos?

Mi problema es el siguiente: Necesito automatizar esto. Necesito mi programa para crear un seguimiento (hecho), extraer el archivo (hecho) y el número de línea (fallar).

Por supuesto, podría llamar a readelf y analizar la salida, pero eso no es realmente adecuado, ya que la salida difiere de un símbolo a otro dependiendo de lo que sucedió exactamente. A veces, la dirección de un símbolo está en una línea y la información sobre el desplazamiento de línea en la siguiente línea ...

Para resumir:

¿Existe una manera elegante de obtener el número de línea exacto de una llamada de función en el backtrace desde el programa durante el tiempo de ejecución?

editar: código de ejemplo:

#define UNW_LOCAL_ONLY #include <libunwind.h> #include <execinfo.h> #include <iostream> #include <stdlib.h> void show_backtrace() { // get current address void* p = __builtin_return_address(0); std::cout << std::hex << p << std::endl; // get callee addresses p = __builtin_return_address(1); std::cout << std::hex << p << std::endl; p = __builtin_return_address(2); std::cout << std::hex << p << std::endl; } void show_backtrace2() { void *array[10]; size_t size; char **strings; int i; size = backtrace (array, 10); strings = backtrace_symbols ((void *const *)array, size); for (i = 0; i < size; i++) { std::cout << strings[i] << std::endl; } free (strings); } void show_backtrace3 (void) { char name[256]; unw_cursor_t cursor; unw_context_t uc; unw_word_t ip, sp, offp; unw_getcontext (&uc); unw_init_local (&cursor, &uc); while (unw_step(&cursor) > 0) { char file[256]; int line = 0; name[0] = ''/0''; unw_get_proc_name (&cursor, name, 256, &offp); unw_get_reg (&cursor, UNW_REG_IP, &ip); unw_get_reg (&cursor, UNW_REG_SP, &sp); std::cout << std:: hex << name << " ip = " << (long) ip << " , sp = " << (long) sp << std::endl; } } void dummy_function2() { show_backtrace(); show_backtrace2(); show_backtrace3(); } void dummy_function1() { dummy_function2 (); } // line 73 int main(int argc, char **argv) { dummy_function1 (); return 0; }

compilar y ejecutar:

g++ test_unwind.cc -g -O0 -lunwind && ./a.out

salida:

0x400edb 0x400ef0 0x400f06 ./a.out() [0x400cfb] ./a.out() [0x400ee0] ./a.out() [0x400ef0] ./a.out() [0x400f06] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f2f044ae76d] ./a.out() [0x400b79] _Z15dummy_function2v ip = 400ee5 , sp = 7fffdb564580 _Z15dummy_function1v ip = 400ef0 , sp = 7fffdb564590 main ip = 400f06 , sp = 7fffdb5645a0 __libc_start_main ip = 7f2f044ae76d , sp = 7fffdb5645c0 _start ip = 400b79 , sp = 7fffdb564680

pruebas, por ejemplo, 0x400ef0 con rendimientos addr2line

/path/to/code/test_unwind.cc:73

que es el archivo correcto, pero el número de línea equivocado En las aplicaciones de la vida real, el número de línea puede diferir en muchas líneas, hacia adelante y hacia atrás.

edición: compilar con -S muestra que la parte relevante es:

.LCFI34: .cfi_def_cfa_register 6 .loc 2 72 0 call _Z15dummy_function2v .loc 2 73 0 popq %rbp

Lo que se muestra por addr2line y similar es la dirección de retorno, como se muestra en la línea después de la call . Me gustaría obtener la línea de "entrada", es decir, lo que se muestra antes!


¡Seguro que puedes hacer! Sé de una implementación de ejemplo que utiliza libunwind . Vea esta publicación del blog: http://blog.bigpixel.ro/stack-unwinding-stack-trace-with-gcc/

Se trata de este fragmento de código (literalmente copiado del artículo):

void show_backtrace (void) { char name[256]; unw_cursor_t cursor; unw_context_t uc; unw_word_t ip, sp, offp; unw_getcontext(&uc); unw_init_local(&cursor, &uc); while (unw_step(&cursor) > 0) { char file[256]; int line = 0; name[0] = ''/0''; unw_get_proc_name(&cursor, name, 256, &offp); unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); //printf ("%s ip = %lx, sp = %lx/n", name, (long) ip, (long) sp); getFileAndLine((long)ip, file, 256, &line); printf("%s in file %s line %d/n", name, file, line); } }


Has probado

__LINE__

Es un símbolo de preprocesador, pero puede compilarlo en.