Linux程序調試-常用調試技巧


程序調試階段:

測試:找出程序的錯誤或缺陷

固化:讓程序錯誤可重現

定位:確定相關代碼行

糾正:修改代碼 修正錯誤

驗證:確定修改解決了問題

1 gcc -Wall -pedantic -ansi   //gcc 編譯  產生編譯的警告信息

 

1取樣法:在程序中添加printf等輸出程序執行過程中的信息,程序錯誤修復后需要刪除

1 #ifdef DEBUG
2     printf("….\n");
3 #endif

定義調試級別,輸出不同類型的內容

 

 

1 #define BASIC_DEBUG 1
2 #define EXTRA_DEBUG 2
3 #define SUPER_DEBUG 4
4 #if (DEBUG & EXTRA_DEBUG)
5     printf...
6 #endif

 

C語言預處理器定義的一些宏可以幫助我們調試(符號前后各有兩個下划線)

   

無需編譯的調試技巧 定義全局變量debug 用戶在調用程序執行時使用 -d 調試選項,決定是否打開調試模式

將調試信息存儲於文件,可以方便自身或用戶自行調試代碼,查找問題

1 if (debug) {
2     sprintf(msg, ...)
3     write_debug(msg)
4 }

程序的受控執行

商業版本常見的調試器有adb、sdb、idebug、dbx等 能用那些調試器取決於UNIX系統

GNU使用調試器gdb,一些gdb的前端程序提供非常友好的界面,xxfdb,KDbg,ddd等

-g 選項是對程序進行調試性編譯的常用選項,需要在編譯每個文件時都加上這個選項,對鏈接器也要加上-g選項。(編譯器會把這個標志自動傳遞給鏈接器)

調試信息會使可執行程序的長度成倍增加(最多10倍),雖然可執行程序的大小增加,但使用內存的數量和原來是一樣的。

調試完后才能后,可以不經過編譯將可執行文件中的調試信息刪除

1 strip <file>

 

使用gdb進行調試

2019123

10:30

開始調試

 
1 //進入調試器
2 gdb ./xxx    //xxx為可執行文件  此時進入gdb軟件  help可查看gdb提供的命令選項
3 //運行
4 run [option]  //  [option]將作為參數傳遞給程序  在程序執行錯誤,gdb將在出錯位置退出  若編譯時使用了 -g選項
5 //則在程序停止后輸出程序終止的位置

棧跟蹤

在到達錯誤位置時,輸入backtrance 簡寫 bt 或 where 輸出調用出錯函數的函數和出錯函數的位置

檢查變量

print 可以給出變量和其他表達式的內容,並將表達式的值賦給偽變量 $<number>

最后一次操作的結果總是以$開頭,而倒數第二次的結果為$$

列出程序源代碼

list

設置斷點

1 break 21 //在21行處打斷點 打斷點之后可以用print 輸出當前關注的變量值
2 cont //程序繼續執行到下一個斷點處
3 display //程序每次停在斷點位置時,自動打印關心的變量值
4 command //指定程序在到達斷點時執行的命令,以end結束 此時設置 >cont >end

程序每次運行到斷點處,自動打印關心的內容,並自動調用程序繼續執行指令 設定完成后程序將一直執行到最后 並在過程中輸出值

   

使用調試器打補丁 gcc 可以在程序進行調試時 直接更改變量的值來進行調試

程序下一次調試,使用info display 和 info break 來查看當前顯示與斷點的內容

1 set variable n = n+1 //設置在調試時,將變量n的值 +1

 

深入學習gdb 強大的功能

1.在支持硬件斷點的cpu上,gdb支持可以在符合某個條件時暫停程序運行

2.gdb可監控表達式的,即當某個表達式取一個特定的值時,gdb可以暫停程序的運行(這樣會對性能造成影響)

3.斷點、計數、條件可以結合在一起設置

4.gdb還可以將自己附在正在運行的程序上,對異常的程序可以在調試過程中直接進行修改,而不必停下編譯並重啟

可以在編譯時用 gcc -O -g來同時獲得程序優化和調試信息 但優化可能會改變程序執行順序

5.調試崩潰的程序時,Linx通常會產生一個 核心轉存儲(core dump).這個文件是程序的內存映像文件

   

一些工具

lint splint LClint等 清理程序中的垃圾,嚴格編譯程序,產生警告

函數調用工具

ctags 為程序中所有的函數創建索引,每個函數對應一個列表,列表列出函數調用位置

cxref 程序分析C語言源代碼並生成一個交叉引用的表格

cflow 程序打印出一個函數調用樹(function call tree),顯示函數之間的調用關系,可以理清程序調用架構,理解操作流程,了解函數的改動將會產生什么樣的影響

prof/gprof 產生執行存檔

想要查找程序的性能問題時,一種常用的技巧是執行存檔(execution profiling),需要特殊的編譯選項,執行存檔可以顯示執行它所花費的時間具體用在哪些步驟上。

給編譯器加上 -p 標志(針對prof程序) -pg 標志(針對gprof)

之后執行程序時,將生成mon.out(gmon.out)文件

斷言 assert

測試某個假設是否成立,如果不成立就停止程序的運行

 

 

#include <assert.h>
void assert(int expression)

 

1 assert //宏對表達式進行求值,如果結果為0,就向標准錯誤輸出一些診斷信息,然后調用abort函數結束程序運行
2 
3 #define NDEBUG //關閉斷言宏

在產品中保留assert並不可取,因為不希望客戶在看到一條assert之后程序強制退出,好的方法是編寫自己的錯誤中斷陷阱例程

   

   

內存調試

2019123

13:50

   

內存調試

1.內存泄露,malloc申請內存后賦給指針,指針的值被改變,此時沒有任何指針指向申請的內存,程序運行時間長了之后將會越來越慢,導致內存耗盡

2.在一個已分配的內存塊尾部的后面(或在它的前面)寫數據,就很可能會損壞malloc庫用於記錄內存分配的數據結構。之后,一個malloc或free調用都會導致段錯誤(Segmentation fault)。此時檢查錯誤發生的地點是很困難的。

ElectricFence可以使用Linux的虛擬內存機制來保護malloc 和 free使用的內存。

使用虛擬內存,在出現非法的內存訪問時,引發段沖突信號並停止程序的運行

valgrind 可以檢測出前邊所說的很多問題,特別是可以檢測出數組訪問錯誤和內存泄露

在程序運行結束時進行內存泄露的檢查 使用 valgrind --leak-check=yes 選項

 


免責聲明!

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



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