Intento encontrar la línea exacta de una llamada en el backtrace en el programa C++. En este momento estoy usando estas líneas (desde la página del manual de traza inversa) para obtener la traza:Números de línea incorrectos de addr2line
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 (el hexágono cadena) y alimentarlo a addr2line. Eso a veces resulta en números de línea aparentemente incorrectos. búsqueda en Internet me llevó a este post, en el que se demuestra que
readelf -wl ./prog
indica que la línea realmente es, o más bien el número de líneas en el símbolo se ha movido a la línea actual.
Editar: Esto ocurre cuando compilo con -g -O0
, es decir, explícitamente sin optimizaciones. El compilador es gcc 4.6.3
¿Hay otra bandera del compilador que extraño?
Mi problema es el siguiente: Necesito automatizar esto. Necesito que mi programa cree una traza inversa (hecho), extraiga el archivo (hecho) y el número de línea (fallido).
Podría, por supuesto, llamar al readelf
y analizar la salida, pero eso no es realmente adecuado, ya que la salida difiere de un símbolo a otro en función de lo que sucedió exactamente. A veces, la dirección de un símbolo se encuentra en una línea y la información acerca de la línea de desplazamiento en la línea siguiente ...
Para resumir:
¿Hay una manera elegante de obtener el número exacto de una línea de Llamada de función en el backtrace desde dentro del programa durante el tiempo de ejecución?
edit: código 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 incorrecta. En 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 pertinente 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 por igual es la dirección de retorno, como se muestra en la línea después del call
. Me gustaría obtener la línea de "entrada", es decir, ¡lo que se muestra antes!
¿Se equivoca al compilar sin optimizaciones? – Flexo
Sí, olvidé mencionar que ... editaré la publicación – steffen
Pruebe 'gdb'ing el ejecutable y use' l * 0x
'. ¿Le da la dirección correcta, o también da lo mismo que 'addr2line'? – Shahbaz