久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Linux中堆棧的示例分析

184次閱讀
沒有評論

共計 2827 個字符,預計需要花費 8 分鐘才能閱讀完成。

這篇文章給大家分享的是有關 Linux 中堆棧的示例分析的內容。丸趣 TV 小編覺得挺實用的,因此分享給大家做個參考,一起跟隨丸趣 TV 小編過來看看吧。

用下面的程序作為例子:

void a() { //stopped here } void b() { a(); } void c() { a(); } int main() { b(); c(); }

如果調試器停在 //stopped here   這行,那么有兩種方法可以達到:main- b- a 或 main- c- a`。如果我們用 LLDB   設置一個斷點,繼續執行并請求一個回溯,那么我們將得到以下內容:

* frame #0: 0x00000000004004da a.out`a() + 4 at bt.cpp:3 frame #1: 0x00000000004004e6 a.out`b() + 9 at bt.cpp:6 frame #2: 0x00000000004004fe a.out`main + 9 at bt.cpp:14 frame #3: 0x00007ffff7a2e830 libc.so.6`__libc_start_main + 240 at libc-start.c:291 frame #4: 0x0000000000400409 a.out`_start + 41

這說明我們目前在函數 a 中,a 從函數 b 中跳轉,b 從 main 中跳轉等等。*** 兩個幀是編譯器如何引導 main 函數的。

現在的問題是我們如何在 x86_64 上實現。最穩健的方法是解析 ELF 文件的 .eh_frame   部分,并解決如何從那里展開堆棧,但這會很痛苦。你可以使用 libunwind   或類似的來做,但這很無聊。相反,我們假設編譯器以某種方式設置了堆棧,我們將手動遍歷它。為了做到這一點,我們首先需要了解堆棧的布局。

 High | ... | +---------+ | Arg 1 | +---------+ | Arg 2 | +---------+ | Return | +---------+ |Saved EBP| +---------+ | Var 1 | +---------+ | Var 2 | +---------+ | ... | Low

如你所見,*** 一個堆棧幀的幀指針存儲在當前堆棧幀的開始處,創建一個鏈接的指針列表。堆棧依據這個鏈表解開。我們可以通過查找 DWARF   信息中的返回地址來找出列表中下一幀的函數。一些編譯器將忽略跟蹤 EBP 的幀基址,因為這可以表示為 ESP   的偏移量,并可以釋放一個額外的寄存器。即使啟用了優化,傳遞 -fno-omit-frame-pointer 到 GCC 或 Clang   會強制它遵循我們依賴的約定。

我們將在 print_backtrace 函數中完成所有的工作:

void debugger::print_backtrace() {

首先要決定的是使用什么格式打印出幀信息。我用了一個 lambda 來推出這個方法:

auto output_frame = [frame_number = 0] (auto  func) mutable { std::cout    frame #    frame_number++    : 0x    dwarf::at_low_pc(func)         dwarf::at_name(func)   std::endl; };

打印輸出的 *** 幀是當前正在執行的幀。我們可以通過查找 DWARF 中的當前程序計數器來獲取此幀的信息:

auto current_func = get_function_from_pc(get_pc()); output_frame(current_func);

接下來我們需要獲取當前函數的幀指針和返回地址。幀指針存儲在 rbp 寄存器中,返回地址是從幀指針堆棧起的 8 字節。

auto frame_pointer = get_register_value(m_pid, reg::rbp); auto return_address = read_memory(frame_pointer+8);

現在我們擁有了展開堆棧所需的所有信息。我只需要繼續展開,直到調試器 *** main,但是當幀指針為 0x0 時,你也可以選擇停止,這些是你在調用 main   函數之前調用的函數。我們將從每幀抓取幀指針和返回地址,并打印出信息。

while (dwarf::at_name(current_func) !=  main ) { current_func = get_function_from_pc(return_address); output_frame(current_func); frame_pointer = read_memory(frame_pointer); return_address = read_memory(frame_pointer+8); } }

就是這樣! 以下是整個函數:

void debugger::print_backtrace() { auto output_frame = [frame_number = 0] (auto  func) mutable { std::cout    frame #    frame_number++    : 0x    dwarf::at_low_pc(func)         dwarf::at_name(func)   std::endl; }; auto current_func = get_function_from_pc(get_pc()); output_frame(current_func); auto frame_pointer = get_register_value(m_pid, reg::rbp); auto return_address = read_memory(frame_pointer+8); while (dwarf::at_name(current_func) !=  main ) { current_func = get_function_from_pc(return_address); output_frame(current_func); frame_pointer = read_memory(frame_pointer); return_address = read_memory(frame_pointer+8); } }

添加命令

當然,我們必須向用戶公開這個命令。

else if(is_prefix(command,  backtrace)) { print_backtrace(); }

感謝各位的閱讀!關于“Linux 中堆棧的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-25發表,共計2827字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 肥东县| 松滋市| 洞口县| 泰安市| 昌宁县| 邵武市| 长春市| 南宫市| 武邑县| 吕梁市| 双城市| 阿城市| 新河县| 华宁县| 沈丘县| 安国市| 淮南市| 会理县| 凤城市| 潮安县| 大厂| 扬州市| 桑日县| 怀柔区| 沾化县| 乐至县| 碌曲县| 房产| 兴国县| 电白县| 攀枝花市| 岑巩县| 富宁县| 尼玛县| 且末县| 西昌市| 苍山县| 遵化市| 澄迈县| 临朐县| 绥棱县|