真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Linux中堆棧的示例分析

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

為中方等地區(qū)用戶提供了全套網(wǎng)頁設計制作服務,及中方網(wǎng)站建設行業(yè)解決方案。主營業(yè)務為做網(wǎng)站、成都做網(wǎng)站、中方網(wǎng)站設計,以傳統(tǒng)方式定制建設網(wǎng)站,并提供域名空間備案等一條龍服務,秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!

用下面的程序作為例子:

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

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

* 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

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

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

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

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

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

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; };

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

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

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

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

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

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);     } }

就是這樣!以下是整個函數(shù):

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中堆棧的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!


網(wǎng)站名稱:Linux中堆棧的示例分析
網(wǎng)站網(wǎng)址:http://weahome.cn/article/ggesps.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部