linux下的程序調試方法匯總


  轉載自:

      https://blog.csdn.net/guochaoxxl/article/details/51878051

 

搞電子都知道,電路不是焊接出來的,是調試出來的。程序員也一定認同,程序不是寫出來的,是調試出來的。那么調試工具就顯得尤為重要,linux作為筆者重要的開發平台,在linux中討論調試工具主要是為那些入門者提供一些幫助。調試工具能讓我們能夠監測、控制和糾正正在運行的程序。我們在運行一些程序的時候,可能被卡住或出現錯誤,或者運行過程或結果,沒能如我們預期,此時,最迫切需要明白究竟發生了什么。為了修復程序,剖析和了解程序運行的細節, 調試工具就成為了我們的必備工具,工於善其事,必先利其器。在Linux下的用戶空間調試工具主要有系統工具和專門調試工具:'print' 打印語句,這是新手最常用的,也是最不提倡使用的;查詢 (/proc, /sys 等)系統的虛擬文件查看,這個方法有局限性;跟蹤 (strace/ltrace)工具使用這個比較普遍,值得提倡;Valgrind (memwatch)內存排除工具,在內存排除方面比較獨到,是內存排錯的法寶;GDB大名鼎鼎的程序調試工具,這個是個全能的工具,沒有完不成的,只有你不知道的。

 

1.'print' 語句

       這是一個基本的調試問題的方法。 我們在程序中懷疑的地方插入print語句來了解程序的運行流程控制流和變量值的改變。 這是一個最簡單的技術, 它的缺點。 需要進行程序編輯,添加'print'語句,必須重新編譯,重新運行來獲得輸出。若需要調試的程序比較大,這將是一個耗時費力的方法。

 

2. 查詢

       在某些情況下,我們需要弄清楚在一個運行在內核中的進程的狀態和內存映射。為了獲得這些信息,我們不需要在內核中插入任何代碼。 相反,可以用 /proc 文件系統。在/proc的偽文件系統,保留系統啟動運行就收集的運行時信息 (cpu信息, 內存容量等)。

      ls -l /proc'的輸出結果,通過對 系統中運行的每一個進程在/proc文件系統中有一個以進程id命名的項。每個進程的細節信息可以在進程id對應的目錄下的文件中獲得。也可以'ls /proc/pid'的輸出

解釋/proc文件系統內的所有條目超出了本文的范圍。一些有用的列舉如下:

  • /proc/cmdline -> 內核命令行
  • /proc/cpuinfo -> 關於處理器的品牌,型號信息等
  • /proc/filesystems -> 文件系統的內核支持的信息
  • /proc/<pid>/cmdline -> 命令行參數傳遞到當前進程
  • /proc/<pid>/mem -> 當前進程持有的內存
  • /proc/<pid>/status -> 當前進程的狀態

 

3. 跟蹤

strace的和ltrace是兩個在Linux中用來追蹤程序的執行細節的跟蹤工具。

 

strace:

strace攔截和記錄系統調用及其接收的信號。對於用戶,它顯示了系統調用、傳遞給它們的參數和返回值。strace的可以附着到已在運行的進程或一個新的進程。它作為一個針對開發者和系統管理員的診斷、調試工具是很有用的。它也可以用來當做一個通過跟蹤不同的程序調用來了解系統的工具。這個工具的好處是不需要源代碼,程序也不需要重新編譯。

使用strace的基本語法是:

strace 命令

strace有各種各樣的參數。可以檢查看strace的手冊頁來獲得更多的細節。

strace的輸出非常長,我們通常不會對顯示的每一行都感興趣。我們可以用'-e expr'選項來過濾不想要的數據。

用 '-p pid' 選項來綁到運行中的進程.

用'-o'選項,命令的輸出可以被重定向到文件。

output of strace filtering only the open system call

strace過濾成只有系統調用的輸出

 

ltrace:

ltrace跟蹤和記錄一個進程的動態(運行時)庫的調用及其收到的信號。它也可以跟蹤一個進程所作的系統調用。它的用法是類似與strace。

ltrace command

'-i' 選項在調用庫時打印指令指針。

'-S' 選項被用來現實系統調用和庫調用

所有可用的選項請參閱ltrace手冊。

output of ltrace capturing 'strcmp' library call

ltrace捕捉'STRCMP'庫調用的輸出

 

4. Valgrind

Valgrind是一套調試和分析工具。它的一個被廣泛使用的默認工具——'Memcheck'——可以攔截malloc(),new(),free()和delete()調用。換句話說,它在檢測下面這些問題非常有用:

  • 內存泄露
  • 重釋放
  • 訪問越界
  • 使用未初始化的內存
  • 使用已經被釋放的內存等。

它直接通過可執行文件運行。

Valgrind也有一些缺點,因為它增加了內存占用,會減慢你的程序。它有時會造成誤報和漏報。它不能檢測出靜態分配的數組的訪問越界問題。

為了使用它,首先請下載並安裝在你的系統上。可以使用操作系統上的包管理器來安裝。

使用命令行安裝需要解壓縮和解包下載的文件。

 
        
  1. tar -xjvf valgring-x.y.z.tar.bz2 (where x.y.z is the version number you are trying to install)

進入新創建的目錄(的valgrind-XYZ)內運行以下命令:

 
        
  1. ./configure
  2. make
  3. make install

讓我們通過一個小程序(test.c)來理解valgrind怎么工作的:

 
        
  1. #include <stdio.h>
  2.  
  3. void f(void)
  4.  
  5. {
  6. int x = malloc(10 * sizeof(int));
  7.  
  8. x[10] = 0;
  9. }
  10.  
  11. int main()
  12. {
  13. f();
  14. return 0;
  15. }

編譯程序:

 
        
  1. gcc -o test -g test.c

現在我們有一個可執行文件叫做'test'。我們現在可以用valgrind來檢測內存錯誤:

 
        
  1. valgrind –tool=memcheck –leak-check=yes test

這是valgrind呈現錯誤的輸出:

output of valgrind showing heap block overrun and memory leak

valgrind顯示堆溢出和內存泄漏的輸出

正如我們在上面看到的消息,我們正在試圖訪問函數f未分配的內存以及分配尚未釋放的內存。

 

5. GDB

GDB是來自自由軟件基金會的調試器。它對定位和修復代碼中的問題很有幫助。當被調試的程序運行時,它給用戶控制權去執行各種動作, 比如:

  • 啟動程序
  • 停在指定位置
  • 停在指定的條件
  • 檢查所需信息
  • 改變程序中的數據 等。

你也可以將一個崩潰的程序coredump附着到GDB並分析故障的原因。

GDB提供很多選項來調試程序。 然而,我們將介紹一些重要的選擇,來感受如何開始使用GDB。

如果你還沒有安裝GDB,可以在這里下載:GDB官方網站

 

編譯程序:

為了用GDB調試程序,必須使用gcc的'-g'選項進行編譯。這將以操作系統的本地格式產生調試信息,GDB利用這些信息來工作。

下面是一個簡單的程序(example1.c)執行被零除用來顯示GDB的用法:

 
        
  1. #include
  2. int divide()
  3. {
  4. int x=5, y=0;
  5. return x / y;
  6. }
  7.  
  8. int main()
  9. {
  10. divide();
  11. }

An example showing usage of gdb

展示GDB用法的例子

 

調用 GDB:

通過在命令行中執行'gdb'來啟動gdb:

invoking gdb

調用 gdb

調用后, 它將等待終端命令並執行,直到退出。

如果一個進程已經在運行,你需要將GDB連接到它上面,可以通過指定進程ID來實現。假設程序已經崩潰,要分析問題的原因,則用GDB分析core文件。

 

啟動程序:

一旦你在GDB里面,使用'run'命令來啟動程序進行調試。

 

給程序傳參數:

使用'set args'給你的程序傳參數,當程序下次運行時將獲得該參數。'show args'將顯示傳遞給程序的參數。

 

檢查堆棧:

每當程序停止,任何人想明白的第一件事就是它為什么停止,以及怎么停在那里的。該信息被稱為反向跟蹤。由程序產生每個函數調用和局部變量,傳遞的參數,調用位置等信息一起存儲在堆棧內的數據塊種,被稱為一幀。我們可以使用GDB來檢查所有這些數據。 GDB從最底層的幀開始給這些幀編號。

  • bt: 打印整個堆棧的回溯
  • bt 打印n個幀的回溯
  • frame : 切換到指定的幀,並打印該幀
  • up : 上移'n'個幀
  • down : 下移'n'個幀 ( n默認是1)

 

檢查數據:

程序的數據可以在里面GDB使用'print'命令進行檢查。例如,如果'x'是調試程序內的變量,'print x'會打印x的值。

 

檢查源碼:

源碼可以在GDB中打印。默認情況下,'list'命令會打印10行代碼。

  • list : 列出'linenum'行周圍的源碼
  • list : 從'function'開始列出源碼
  • disas : 顯示該函數機器代碼

 

停止和恢復程序:

使用GDB,我們可以在必要的地方設置斷點,觀察點等來停止程序。

  • break : 在'location'設置一個斷點。當在程序執行到這里時斷點將被擊中,控制權被交給用戶。
  • watch : 當'expr'被程序寫入而且它的值發生變化時GDB將停止
  • catch : 當'event'發生時GDB停止
  • disable : 禁用指定斷點
  • enable : 啟用指定斷點
  • delete : 刪除 斷點/觀察點/捕獲點。 如果沒有傳遞參數默認操作是在所有的斷點
  • step: 一步一步執行程序
  • continue: 繼續執行程序,直到執行完畢

 

退出 GDB:

用'quit'命令還從GDB中退出。

GDB還有更多的可用選項。里面GDB使用help選項了解更多詳情。

getting help within gdb

在GDB中獲得幫助

 

總結

在這篇文章中,我們已經看到不同類型的Linux用戶空間的調試工具。總結以上所有內容,如下是什么時候使用該什么的快速指南:

  • 基本調試,獲得關鍵變量 - print 語句
  • 獲取有關文件系統支持,可用內存,CPU,運行程序的內核狀態等信息 - 查詢 /proc 文件系統
  • 最初的問題診斷,系統調用或庫調用的相關問題,了解程序流程 – strace / ltrace
  • 應用程序內存空間的問題 – valgrind
  • 檢查應用程序運行時的行為,分析應用程序崩潰 – gdb


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM