日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux下利用backtrace追踪函数调用堆栈以及定位段错误

發布時間:2025/3/17 linux 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下利用backtrace追踪函数调用堆栈以及定位段错误 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一般察看函數運行時堆棧的方法是使用GDB(bt命令)之類的外部調試器,但是,有些時候為了分析程序的BUG,(主要針對長時間運行程序的分析),在程序出錯時打印出函數的調用堆棧是非常有用的。

在glibc頭文件"execinfo.h"中聲明了三個函數用于獲取當前線程的函數調用堆棧。

int backtrace(void **buffer,int size)

該函數用于獲取當前線程的調用堆棧,獲取的信息將會被存放在buffer中,它是一個指針列表。參數 size 用來指定buffer中可以保存多少個void* 元素。函數返回值是實際獲取的指針個數,最大不超過size大小。



在buffer中的指針實際是從堆棧中獲取的返回地址,每一個堆棧框架有一個返回地址。
注意:某些編譯器的優化選項對獲取正確的調用堆棧有干擾,另外內聯函數沒有堆棧框架;刪除框架指針也會導致無法正確解析堆棧內容。

char ** backtrace_symbols (void *const *buffer, int size)

backtrace_symbols將從backtrace函數獲取的信息轉化為一個字符串數組. 參數buffer應該是從backtrace函數獲取的指針數組,size是該數組中的元素個數(backtrace的返回值)。



函數返回值是一個指向字符串數組的指針,它的大小同buffer相同.每個字符串包含了一個相對于buffer中對應元素的可打印信息.它包括函數名,函數的偏移地址,和實際的返回地址。


現在,只有使用ELF二進制格式的程序才能獲取函數名稱和偏移地址.在其他系統,只有16進制的返回地址能被獲取.另外,你可能需要傳遞相應的符號給鏈接器,以能支持函數名功能(比如,在使用GNU ld鏈接器的系統中,你需要傳遞(-rdynamic), -rdynamic可用來通知鏈接器將所有符號添加到動態符號表中,如果你的鏈接器支持-rdynamic的話,建議將其加上!)


該函數的返回值是通過malloc函數申請的空間,因此調用者必須使用free函數來釋放指針。


注意:如果不能為字符串獲取足夠的空間函數的返回值將會為NULL。

void backtrace_symbols_fd (void *const *buffer, int size, int fd)

backtrace_symbols_fd與backtrace_symbols 函數具有相同的功能,不同的是它不會給調用者返回字符串數組,而是將結果寫入文件描述符為fd的文件中,每個函數對應一行.它不需要調用malloc函數,因此適用于有可能調用該函數會失敗的情況。
?

下面是glibc中的實例(稍有修改):

#include <execinfo.h> #include <stdio.h> #include <stdlib.h>/* Obtain a backtrace and print it to @code{stdout}. */ void print_trace (void) {void *array[10];int size;char **strings;int i;size = backtrace(array, 10);strings = backtrace_symbols(array, size);if(NULL == strings){perror("backtrace_synbols");exit(EXIT_FAILURE);}printf ("Obtained %zd stack frames.\n", size);for (i = 0; i < size; i++)printf ("%s\n", strings[i]);free (strings);strings = NULL; }/* A dummy function to make the backtrace more interesting. */ void dummy_function (void) {print_trace (); }int main (int argc, char *argv[]) {dummy_function ();return 0; }

輸出如下:

[root@vm userAppInit]# gcc test.c [root@vm userAppInit]# ./a.out Obtained 5 stack frames. ./a.out [0x80484dd] ./a.out [0x804856d] ./a.out [0x8048585] /lib/libc.so.6(__libc_start_main+0xdc) [0x616e9c] ./a.out [0x8048411]
只能看到地址,現在修改編譯參數:

[root@vm userAppInit]# gcc -rdynamic test.c [root@vm userAppInit]# ./a.out Obtained 5 stack frames. ./a.out(print_trace+0x19) [0x80486ad] ./a.out(dummy_function+0xb) [0x804873d] ./a.out(main+0x16) [0x8048755] /lib/libc.so.6(__libc_start_main+0xdc) [0x616e9c] ./a.out [0x80485e1]

現在可以看到函數名了,但是沒有行號,不過沒有關系addr2line提供了這個功能。

在調用 Addr2line 工具時,要使用 -e 選項來指定可執行映像是 a.out。通過使用 -f 選項,可以告訴工具輸出函數名。

然后我們試圖用addr2line來看地址對應的函數和行號:

[root@vm userAppInit]# addr2line 0x80486ad -e ./a.out f ??:0 ??:0失敗了,然后我們再次修改編譯參數:

[root@vm userAppInit]# gcc -g -rdynamic test.c [root@vm userAppInit]# ./a.out Obtained 5 stack frames. ./a.out(print_trace+0x19) [0x80486ad] ./a.out(dummy_function+0xb) [0x804873d] ./a.out(main+0x16) [0x8048755] /lib/libc.so.6(__libc_start_main+0xdc) [0x616e9c] ./a.out [0x80485e1] [root@vm userAppInit]# addr2line 0x80486ad -e ./a.out -f print_trace /home/D8135/SW_COMM/lib/SW_BPS/Terminal/D8135/CPU/userAppInit/test.c:12
這次成功了,多加了-g參數。

使用這個地址和 Addr2line 工具,就可以判斷出函數名(print_trace)、源文件(/home/D8135/SW_COMM/lib/SW_BPS/Terminal/D8135/CPU/userAppInit/test.c)以及它在源文件中的行號(12)。


backtrace和backtrace_symbols的具體說明可以參考

http://www.kernel.org/doc/man-pages/online/pages/man3/backtrace.3.html


from:

http://www.linuxidc.com/Linux/2012-11/73470.htm

http://blog.csdn.net/wind19/article/details/6105617


轉載于:https://www.cnblogs.com/hehehaha/p/6332384.html

總結

以上是生活随笔為你收集整理的Linux下利用backtrace追踪函数调用堆栈以及定位段错误的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。