我試圖在C++程序的backtrace中找到確切的調用行。現在我使用這些線(從回溯的手冊頁),以獲得跟蹤:來自addr2line的錯誤行號
void *bt_buffer[1000];
char **bt_strings;
int bt_nptrs = backtrace(bt_buffer, 1000);
bt_strings = backtrace_symbols(bt_buffer, bt_nptrs);
在bt_strings我覺得形式的線
./prog() [0x402e42]
現在我把地址(十六進制字符串)並將其提供給addr2line。這有時會導致顯然錯誤的行號。互聯網搜索使我這個post,其中表明
readelf -wl ./prog
指示了線真的是,或者說有多少行的符號已經移動到當前行。
編輯:這發生在我編譯-g -O0
,即明確沒有優化。編譯器是gcc 4.6.3
是否有另一個我錯過的編譯器標誌?
我的問題是以下幾點:我需要自動執行此操作。我需要我的程序創建一個回溯(完成),提取文件(完成)和行號(失敗)。
我當然可以調用readelf
並解析輸出,但這不太合適,因爲根據發生的事情,輸出在符號和符號之間有所不同。有時,一個符號的地址是在同一行約行中的下一行偏移量的信息...
綜上所述:
有一種優雅的方式來獲得的確切行號函數在運行時從程序內部追蹤回調?
編輯:示例代碼:
#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;
}
編譯和運行:
g++ test_unwind.cc -g -O0 -lunwind && ./a.out
輸出:
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
測試例如0x40ef0與addr2line產量
/path/to/code/test_unwind.cc:73
這是正確的文件,但錯誤的行號。在實際應用中,行號可能會因許多行而不同,向前和向後。
編輯:與-S
編譯顯示相關的部分是:
.LCFI34:
.cfi_def_cfa_register 6
.loc 2 72 0
call _Z15dummy_function2v
.loc 2 73 0
popq %rbp
什麼是addr2line
顯示,並且都爲返回地址,如圖所示call
之後的行。我想獲得「入口」行,即之前顯示的內容!
編譯時沒有進行優化是否會出錯? – Flexo 2012-07-20 12:39:25
是的,忘了提及......我將編輯這個文章 – steffen 2012-07-20 12:40:23
嘗試使用'gdb'執行並使用'l * 0x
'。它是否給出了正確的地址,還是它也給出了相同的'addr2line'? – Shahbaz 2012-07-20 12:49:30