<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          嵌入式C代碼調(diào)試利器——backtrace

          共 5055字,需瀏覽 11分鐘

           ·

          2024-04-17 08:00



          1

          backtrace基本原理

          大家好,我是bug菌~

          backtrace英譯為回溯的意思,這聽起來有點專業(yè)了,其實大部分搞嵌入式的朋友都有聽說過函數(shù)調(diào)用棧callstack。而backtrace說白了就是我們呈現(xiàn)函數(shù)調(diào)用關(guān)系的一項功能。

          所以backtrace調(diào)試功能的實現(xiàn)原理基于函數(shù)調(diào)用棧的概念。

          那什么是函數(shù)調(diào)用棧呢?

          函數(shù)調(diào)用棧是一個記錄程序中函數(shù)調(diào)用關(guān)系的數(shù)據(jù)結(jié)構(gòu),它在程序運行時動態(tài)生成和維護。當程序執(zhí)行函數(shù)調(diào)用時,它將當前函數(shù)的返回地址和一些其他信息壓入堆棧中,并跳轉(zhuǎn)到被調(diào)用的函數(shù)執(zhí)行。當被調(diào)用函數(shù)執(zhí)行完畢后,它將返回地址彈出堆棧,并跳回到調(diào)用函數(shù)繼續(xù)執(zhí)行。

          backtrace調(diào)試功能的實現(xiàn)原理就是利用函數(shù)調(diào)用棧中的信息來追蹤程序執(zhí)行的路徑和調(diào)用關(guān)系。當程序出現(xiàn)錯誤或崩潰時,backtrace可以通過分析函數(shù)調(diào)用棧信息來確定出錯的位置和原因。

          在Linux系統(tǒng)中,backtrace通常是通過使用調(diào)試器比如我們常用的gdb來實現(xiàn)的。調(diào)試器會在程序執(zhí)行時,動態(tài)地獲取函數(shù)調(diào)用棧信息,并將其保存在調(diào)試器的內(nèi)部數(shù)據(jù)結(jié)構(gòu)中。當程序出現(xiàn)錯誤或崩潰時,調(diào)試器就可以利用保存的函數(shù)調(diào)用棧信息來進行backtrace操作。

          2

          backtrace功能

          而對于backtrace這個功能在不同的平臺和開發(fā)環(huán)境中的使用是不同的.

          比如在我們平時的linux環(huán)境中:可以使用glibc提供的backtrace()函數(shù)實現(xiàn)backtrace功能。該函數(shù)通過解析函數(shù)調(diào)用棧息獲取函數(shù)名、參數(shù)和返回地址等信息,并將其打印到標準輸出或指定的文件中。

          此外,還可以使用gdb或libunwind庫來實現(xiàn)backtrace功能。gdb是一個強大的調(diào)試器,可以實時追蹤程序的執(zhí)行,獲取程序的調(diào)用棧信息,并提供各種調(diào)試工具和命令。

          而其中的libunwind則是一個開源的C/C++庫,也可以用于在運行時獲取當前程序的調(diào)用棧信息,并且在不同的平臺和架構(gòu)上運行,并提供了簡單易用的API接口,同樣也是非常方便的。

          3

          glibc下的backtrace功能使用

          glibc提供了backtrace函數(shù),可以用來獲取當前程序的調(diào)用棧信息,使用方法如下:

          1. 包含頭文件:

          #include <execinfo.h>
          1. 定義一個數(shù)組,用于存儲回溯信息:

          #define BT_BUF_SIZE 100
          void *bt_buffer[BT_BUF_SIZE];

          該數(shù)組用于存儲backtrace信息,數(shù)組大小可以根據(jù)需要進行調(diào)整。

          3. 調(diào)用backtrace函數(shù):

          int bt_size = backtrace(bt_buffer, BT_BUF_SIZE);

          該函數(shù)會獲取當前程序的調(diào)用棧信息,并將其存儲在bt_buffer數(shù)組中。bt_size表示實際獲取到的調(diào)用棧信息的條數(shù),該值不會超過BT_BUF_SIZE。

          4. 使用backtrace_symbols函數(shù)將backtrace信息轉(zhuǎn)換成字符串:

          char **bt_strings = backtrace_symbols(bt_buffer, bt_size);

          該函數(shù)將backtrace信息轉(zhuǎn)換成字符串數(shù)組,每個字符串表示一個調(diào)用棧信息。bt_strings指向字符串數(shù)組的首地址,需要在使用完畢后手動釋放內(nèi)存。

          5. 打印回溯信息:

          for (int i = 0; i bt_sizei++) {
              printf("%!s(MISSING)\n", bt_strings[i]);
          }

          該代碼會將回溯信息打印到標準輸出中,可以根據(jù)需要進行調(diào)整。完整的使用示例代碼如下:

          #include <execinfo.h>
          #include <stdio.h>
          #include <stdlib.h>
          #define BT_BUF_SIZE 100
          void print_backtrace() {
              void *bt_buffer[BT_BUF_SIZE];
              int bt_size = backtrace(bt_buffer, BT_BUF_SIZE);
              char **bt_strings = backtrace_symbols(bt_buffer, bt_size);
              printf("backtrace:\n");
              for (int i = 0; i < bt_size; i++) {
                  printf("%!s(MISSING)\n", bt_strings[i]);
              }
              free(bt_strings);
          }
          int func_c() {
              print_backtrace();
              return 0;
          }
          int func_b() {
              return func_c();
          }
          int func_a() {
              return func_b();
          }
          int main() {
              return func_a();
          }

          該程序會輸出調(diào)用棧信息,格式如下:

          backtrace:
          ./backtrace_demo(func_c+0x16) [0x40069a]
          ./backtrace_demo(func_b+0xd) [0x4006c5]
          ./backtrace_demo(func_a+0xd) [0x4006e0]
          ./backtrace_demo(main+0xe) [0x4006f6]
          /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1) [0x7f6a69e2b1c1]
          ./backtrace_demo(_start+0x2a) [0x400529]

          其中每一行表示一個調(diào)用棧信息,格式為"函數(shù)名+偏移量+[地址]"。

          4

          gdb的backtrace功能

          在Linux下進行嵌入式開發(fā),backtrace通常是通過使用調(diào)試器來實現(xiàn)的,這樣的話,gdb都跟你封裝成了相應(yīng)的命令,使用起來也簡單很多。

          下面以gdb為例來介紹如何使用backtrace:

          1、編譯程序時添加-g選項,以在可執(zhí)行文件中包含調(diào)試信息。因為backtrace函數(shù)需要獲取調(diào)用棧信息,因此需要包含符號信息。如果使用了-g選項進行編譯,則可以保證符號信息的完整性,如果沒有使用-g選項編譯程序,則可能會出現(xiàn)獲取不到符號信息的情況,導(dǎo)致backtrace函數(shù)無法正常工作。

          例如,使用gcc編譯時可以添加-g選項:

          gcc -g -o program program.c

          2、使用gdb啟動程序并暫停程序的執(zhí)行。例如,可以使用以下命令啟動程序:然后使用以下命令在程序執(zhí)行時暫停程序的執(zhí)行:這將在程序的main函數(shù)處設(shè)置斷點,并啟動程序的執(zhí)行。
          gdb program
          (gdb) break main
          (gdb) run

          3、當程序崩潰或出現(xiàn)錯誤時,gdb會自動暫停程序的執(zhí)行,并顯示當前程序的調(diào)用棧信息。可以使用以下命令查看調(diào)用棧信息:這將顯示當前程序的調(diào)用棧信息,包括每個函數(shù)的名稱、參數(shù)和返回值等信息,以及每個函數(shù)在調(diào)用棧中的位置。
          (gdb) backtrace

          4、最后可以使用其他gdb命令來查看每個函數(shù)的參數(shù)和局部變量等信息,以幫助定位代碼崩潰或錯誤的原因。

          5

          跟蹤的準確性

          在實現(xiàn)backtrace功能時,還需要注意一些細節(jié)問題。例如,需要注意函數(shù)調(diào)用棧的深度和堆棧溢出等問題,以及需要保證backtrace操作的可靠性和準確性,下面簡單聊聊如下三個值得注意的方面:

          1. 優(yōu)化選項:程序使用了-O選項進行優(yōu)化時,可能會改變函數(shù)調(diào)用棧的結(jié)構(gòu),從而使backtrace函數(shù)獲取到的信息不完整或不準確。因此,在使用backtrace函數(shù)時,建議關(guān)閉優(yōu)化選項,以保證其可靠性。
          2. 棧溢出:如果程序發(fā)生棧溢出,可能會破壞調(diào)用棧信息,導(dǎo)致backtrace函數(shù)獲取到的信息不完整或不準確。因此,在程序中應(yīng)該避免出現(xiàn)棧溢出的情況,以保證backtrace函數(shù)的可靠性。
          3. 線程安全:如果程序使用多線程,每個線程都有自己的調(diào)用棧,因此需要在每個線程中分別調(diào)用backtrace函數(shù)來獲取相應(yīng)的調(diào)用棧信息。此外,在多線程環(huán)境下,需要注意避免競爭條件的出現(xiàn),以保證backtrace函數(shù)的可靠性。

          總之,在使用glibc提供的backtrace函數(shù)時,需要注意編譯選項、優(yōu)化選項、棧溢出和線程安全等因素,以保證其可靠性。此外,不同的硬件平臺和操作系統(tǒng)可能有不同的backtrace實現(xiàn)方式和接口,需要使用相應(yīng)的工具和API來實現(xiàn)。


          瀏覽 200
          10點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          10點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  五月丁香啪啪啪 | 国产肉体XXX137大胆 | 看黄在线免费 | 日韩高清无码三级 | 久久国模吧 |