Linux下的調試工具

來源:互聯網
上載者:User
隨著XP的流行,人們越來越注重軟體的前期設計、後期的實現,以及貫穿於其中的測試工作,經過這個過程出來的自然是高品質的軟體。甚至有人聲稱XP會淘汰調試器!這當然是有一定道理的,然而就目前的現實來看,這還是一種理想。在日常工作中,調試工具還是必不可少的。在Linux下,調試工具並非只有gdb,還有很多其它調試工具,它們都各有所長,側重方面也有所不同。本文介紹幾種筆者常用的調試工具:

1. mtrace
在linux下開發應用程式,用C/C++語言的居多。記憶體泄露和記憶體越界等記憶體錯誤,無疑是其中最頭疼的問題之一。glibc為解決記憶體錯誤提供了兩種方案:

一種是hook記憶體管理函數。hook記憶體管理函數後,你可以通過記下記憶體配置的記錄,在程式終止時查看是否有記憶體泄露,這樣就可以找出記憶體泄露的地方了。你也可以通過在所分配記憶體的首尾寫入特殊的標誌,在釋放記憶體時檢查該標誌是否被破壞了,這樣就可以達到檢查記憶體越界問題的目的。

另外一種方法更簡單,glibc已經為第一種方案提供了預設的實現,你要做的只是在特定的位置調用mtrace/muntrace兩個函數,它們的函數原型如下:
#include <mcheck.h>
void mtrace(void);
void muntrace(void);
你可能會問,在哪裡調這兩種函數最好?這沒有固定的答案,要視具體情況而定。對於小程式來說,在進入main時調用mtrace,在退出main函數時調用muntrace。對於大型軟體,這樣做可能會記錄過多的資訊,分析這些記錄會比較慢,這時可以在你所懷疑代碼的兩端調用。

另外,還需要設定一個環境變數MALLOC_TRACE,它是一個檔案名稱,要保證目前使用者有許可權建立和寫入該檔案。glibc的記憶體管理器會把記憶體配置的曆史資訊寫入到MALLOC_TRACE指定的檔案中。

程式運行完畢後,使用mtrace工具分析這些記憶體配置曆史資訊,可以查出記憶體錯誤的位置(mtrace在glibc-utils軟體包裡)。

2. strace
在編程時,檢查函數的傳回值是一種好習慣。對於像glibc等標準C的函數,光檢查傳回值是不夠的,還需要檢查errno的值。這樣的程式往往顯得冗長,不夠簡潔。同時也可能是出於偷懶的原因,大多數程式裡並沒有做這樣的檢查。

這樣的程式,一旦出現錯誤,用調試器一步一步定位錯誤,然後想法查出錯誤的原因,也是可以的,不過比較麻煩,對調試器來說有些大材小用,不太可取。這時,用strace命令可能會更方便一點。它可以顯示各個系統調用/訊號的執行過程和結果。比如檔案開啟出錯,一眼就看出來了,連錯誤的原因(errno)都知道。

3. binutil
binutil是一系列的工具,你可能根本不知道它們的存在,但是沒有它們你卻寸步難行。Binutil包括下列工具:
ld - the GNU linker.
as - the GNU assembler.
addr2line - Converts addresses into filenames and line numbers.
ar - A utility for creating, modifying and extracting from archives.
c++filt - Filter to demangle encoded C++ symbols.
gprof - Displays profiling information.
nlmconv - Converts object code into an NLM.
nm - Lists symbols from object files.
objcopy - Copys and translates object files.
objdump - Displays information from object files.
ranlib - Generates an index to the contents of an archive.
readelf - Displays information from any ELF format object file.
size - Lists the section sizes of an object or archive file.
strings - Lists printable strings from files.
strip - Discards symbols.
windres - A compiler for Windows resource files.
其中部分工具對調試極有協助,如:
你可以用objdump反組譯碼,查看目標檔案或可執行檔內部資訊。
你可以用addr2line把機器地址轉換到代碼對應的位置。
你可以用nm查看目標檔案或可執行檔中的各種符號。
你可以用gprof分析各個函數的使用方式,找出效能的瓶頸所在(這需要加編譯選項)。

4. ld-linux
現在載入ELF可執行檔的工作,已經落到ld-linux.so.2頭上了。你可能會問,這與有偵錯工具有關係嗎?有的。比如,在linux中,共用庫裡所有非static的函數/全域變數都是export的,更糟的是C語言中沒有名字空間這個概念,導致函數名極易衝突。在多個共用庫中,名字衝突引起的BUG是比較難查的。這時,你可以通過設定LD_
DEBUG環境變數,來觀察ld-linux.so載入可執行檔的過程,從中可以得到不少協助資訊。LD_
DEBUG的取值如下:
libs display library search paths
reloc display relocation processing
files display progress for input file
symbols display symbol table processing
bindings display information about symbol binding
versions display version dependencies
all all previous options combined
statistics display relocation statistics
unused determined unused DSOs
help display this help message and exit
5. gdb
對於真正意義的調試器來說,gdb在linux下是獨一無二的。它有多種封裝,有字元介面的,也有圖形介面的,有單獨啟動並執行,也有整合到IDE中的。gdb功能強大,圖形介面的gdb容易上手一點,但功能無疑受到了一些限制,相信大部分高手還是願意使用字元介面的。Gdb太常用了,這裡不再多說。

6. gcc/boundschecker
相信很多人用過win32下的BoundsChecker(Compuware公司)和Purify(IBM公司)兩個工具吧。它們的功能實在太強大了,絕非能通過重載記憶體管理函數就可以做到,它們在編譯時間插入了自己的調試代碼。

gcc也有個擴充,通過在編譯時間插入調試代碼,來實現更強大的檢查功能。當然這要求重新編譯gcc,你可以到http://sourceforge.net/projects/boundschecking/
下載gcc的補丁。它的可移植性非常好,筆者曾一個ARM
平台項目裡使用過,效果不錯。

7. valgrind
最好的東西往往最後才見到。Valgrind是我的最愛,用習慣了,寫的程式不在valgrind下跑一遍,就像沒有寫單元測試程式一樣,有點放心不下。它有BoundsChecker/Purify的功能,而且速度更快。
有點遺憾的是valgrind目前只支援x86平台,當然,這對大多數情況已經足夠了。
你可以到http://valgrind.org/ 下載最新版本。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.