學習交流加linux
- 我的qq: 1126137994
- 我的微信: liu1126137994
- 學習交流資源分享qq羣: 962535112
上一篇文章咱們學習了gcc編譯器的相關內容。點擊查看上一篇文章:gcc編譯器。本篇文章接着上一篇文章,學習GNU爲GCC提供的輔助開發工具集Binutils。Binutils工具集,主要是用於在代碼調試的時候,定位bug的一些手段。咱們主要學習如下幾個工具的使用: 微信
本篇文章先學習使用addr2line與strip工具。函數
首先咱們要知道,gcc編譯程序的時候,加上-g
選項,表示在目標文件中生成調試信息。幾乎全部調試輔助工具,都依賴於程序的調試信息。工具
addr2line工具。顧名思義,能夠將地址轉換爲行號。它經常使用於分析定位內存訪問錯誤的問題。以實際例子爲例:學習
test.c程序開發工具
#include <stdio.h>
int g_global = 0;
int g_test = 1;
extern int* g_pointer;
extern void func();
int main(int argc, char *argv[]) {
printf("&g_global = %p\n", &g_global);
printf("&g_test = %p\n", &g_test);
printf("&g_pointer = %p\n", &g_pointer);
printf("g_pointer = %p\n", g_pointer);
printf("&func = %p\n", &func);
printf("&main = %p\n", &main);
func();
return 0;
}
複製代碼
func.c程序ui
#include <stdio.h>
int* g_pointer;
void func() {
*g_pointer = (int)"D.T.Software";
return;
}
複製代碼
咱們在linux下編譯如下程序(注意我使用gcc-4.4.5版本編譯沒有警告顯示。可是使用較高版本的gcc編譯器,可能會有警告。這裏咱們忽略警告):spa
運行程序.net
顯示結果爲: debug
其實結果也在乎料之中。咱們分析程序很容易知道,func函數中 *g_pointer = (int)"D.T.Software";
這句話,使得在0地址賦值了。由於int* g_pointer;
只是定義了g_pointer
卻沒有賦值,那麼g_pointer
實際上一開始是指向0地址,後面又對它進行賦值。至關於對0地址進行操做。
可是咱們知道0地址,是不能被操做的。因此會產生段錯誤。這個程序很短,問題咱們很容易發現。可是若是這個歌程序有一千行,一萬行的話,那麼問題就很難定位到。此時addr2line工具就可以上場。
下面來講明如何使用addr2line工具。
首先開啓core dump選項。使用命令ulimit -c unlimited
。開啓這個選項後,在運行可執行程序的時候,會將程序崩潰前最後一刻的內存狀態信息,轉儲(保存)到一個core文件。這個文件叫作核心轉儲文件。咱們能夠經過讀取該文件,獲取一些用於調試的信息。
開啓core dump選項後,再次運行可執行程序,來生成core文件。
咱們能夠看到,段錯誤後面顯示核心已轉儲。此時查看當前目錄的話,就能夠看到core文件。
dmesg core
命令讀取core文件的內容,顯示內容最後部分以下:能夠看到,最後一刻IP寄存器的值爲0x080483d1
.出問題的代碼就在這個地址處。可是咱們沒法知道這個地址處究竟是個啥。可是能夠利用addr2line工具,將這個地址轉換爲代碼中對應的行號。
addr2line 0x080483d1 -f -e lyy
很明顯,已經找打緣由,是func.c程序的第7行。當從兩萬行大代碼中找到這個錯誤,也是很激動的!!!
實際上,addr2line可以正常工做,必須依賴於程序的調試信息。而咱們在編譯程序的時候,也確實讓程序生成了調試信息。如上編譯的時候帶的-g
選項。
當可執行程序裏面帶有大量的調試信息,會致使可執行程序,很是的大。若是在大型的軟件中,軟件在發佈以前,確定是要將這些調試信息去掉,好讓發佈出去的程序佔用內存空間更小,否則程序太大,對用戶來講也是很是不友好的。
其實這就是所謂的release版本的程序。在發佈以前,還須要調試的程序,咱們稱爲debug版本程序。
那麼如何剔除調試信息?使用strip工具!以下圖是release版本的程序大小爲9074:
使用strip將調試信息剔除後大小爲5512:
結果顯而易見!!!
還有其餘工具,放在下一篇文章學習!!!