掌握Linux除錯技術(轉)

post0發表於2007-08-14
掌握Linux除錯技術(轉)[@more@]

  您可以用各種方法來監控執行著的使用者空間程式:可以為其執行偵錯程式並單步除錯該程式,新增列印語句,或者新增工具來分析程式。本文描述了幾種可以用來除錯在 Linux 上執行的程式的方法。我們將回顧四種除錯問題的情況,這些問題包括段錯誤,記憶體溢位和洩漏,還有掛起。

  本文討論了四種除錯 Linux 程式的情況。在第 1 種情況中,我們使用了兩個有記憶體分配問題的樣本程式,使用 MEMWATCH 和 Yet Another Malloc Debugger(YAMD)工具來除錯它們。在第 2 種情況中,我們使用了 Linux 中的 strace 實用程式,它能夠跟蹤系統呼叫和訊號,從而找出程式發生錯誤的地方。在第 3 種情況中,我們使用 Linux 核心的 Oops 功能來解決程式的段錯誤,並向您展示如何設定核心原始碼級偵錯程式(kernel source level debugger,kgdb),以使用 GNU 偵錯程式(GNU debugger,gdb)來解決相同的問題;kgdb 程式是使用序列連線的 Linux 核心遠端 gdb。在第 4 種情況中,我們使用 Linux 上提供的魔術鍵控順序(magic key sequence)來顯示引發掛起問題的元件的資訊。

  常見除錯方法

  當您的程式中包含錯誤時,很可能在程式碼中某處有一個條件,您認為它為真(true),但實際上是假(false)。找出錯誤的過程也就是在找出錯誤後推翻以前一直確信為真的某個條件過程。

  以下幾個示例是您可能確信成立的條件的一些型別:

  在原始碼中的某處,某變數有特定的值。

  在給定的地方,某個結構已被正確設定。

  對於給定的 if-then-else 語句,if 部分就是被執行的路徑。

  當子例程被呼叫時,該例程正確地接收到了它的引數。

  找出錯誤也就是要確定上述所有情況是否存在。如果您確信在子例程被呼叫時某變數應該有特定的值,那麼就檢查一下情況是否如此。如果您相信 if 結構會被執行,那麼也檢查一下情況是否如此。通常,您的假設都會是正確的,但最終您會找到與假設不符的情況。結果,您就會找出發生錯誤的地方。

  除錯是您無法逃避的任務。進行除錯有很多種方法,比如將訊息列印到螢幕上、使用偵錯程式,或只是考慮程式執行的情況並仔細地揣摩問題所在。

  在修正問題之前,您必須找出它的源頭。舉例來說,對於段錯誤,您需要了解段錯誤發生在程式碼的哪一行。一旦您發現了程式碼中出錯的行,請確定該方法中變數的值、方法被呼叫的方式以及關於錯誤如何發生的詳細情況。使用偵錯程式將使找出所有這些資訊變得很簡單。如果沒有偵錯程式可用,您還可以使用其它的工具。(請注意,產品環境中可能並不提供偵錯程式,而且 Linux 核心沒有內建的偵錯程式。)

  實用的記憶體和核心工具

  您可以使用 Linux 上的除錯工具,透過各種方式跟蹤使用者空間和核心問題。請使用下面的工具和技術來構建和除錯您的原始碼:

  使用者空間工具:

  記憶體工具:MEMWATCH 和 YAMD

  strace

  GNU 偵錯程式(gdb)

  魔術鍵控順序

  核心工具:

  核心原始碼級偵錯程式(kgdb)

  內建核心偵錯程式(kdb)

  Oops

  本文將討論一類透過人工檢查程式碼不容易找到的問題,而且此類問題只在很少見的情況下存在。記憶體錯誤通常在多種情況同時存在時出現,而且您有時只能在部署程式之後才能發現記憶體錯誤

  第 1 種情況:記憶體除錯工具

  C 語言作為 Linux 系統上標準的程式語言給予了我們對動態記憶體分配很大的控制權。然而,這種自由可能會導致嚴重的記憶體管理問題,而這些問題可能導致程式崩潰或隨時間的推移導致效能降級。

  記憶體洩漏(即 malloc() 記憶體在對應的 free() 呼叫執行後永不被釋放)和緩衝區溢位(例如對以前分配到某陣列的記憶體進行寫操作)是一些常見的問題,它們可能很難檢測到。這一部分將討論幾個除錯工具,它們極大地簡化了檢測和找出記憶體問題的過程。

  MEMWATCH

  MEMWATCH 由 Johan Lindh 編寫,是一個開放原始碼 C 語言記憶體錯誤檢測工具,您可以自己下載它(請參閱本文後面部分的參考資料)。只要在程式碼中新增一個標頭檔案並在 gcc 語句中定義了 MEMWATCH 之後,您就可以跟蹤程式中的記憶體洩漏和錯誤了。MEMWATCH 支援 ANSI C,它提供結果日誌紀錄,能檢測雙重釋放(double-free)、錯誤釋放(erroneous free)、沒有釋放的記憶體(unfreed memory)、溢位和下溢等等。

  清單 1. 記憶體樣本(test1.c)

  #include

  #include

  #include "memwatch.h"

  int main(void)

  {

  char *ptr1;

  char *ptr2;

  ptr1 = malloc(512);

  ptr2 = malloc(512);

  ptr2 = ptr1;

  free(ptr2);

  free(ptr1);

  }

  清單 1 中的程式碼將分配兩個 512 位元組的記憶體塊,然後指向第一個記憶體塊的指標被設定為指向第二個記憶體塊。結果,第二個記憶體塊的地址丟失,從而產生了記憶體洩漏。

  現在我們編譯清單 1 的 memwatch.c。下面是一個 makefile 示例:

  test1

  gcc -DMEMWATCH -DMW_STDIO test1.c memwatch

  c -o test1

  當您執行 test1 程式後,它會生成一個關於洩漏的記憶體的報告。清單 2 展示了示例 memwatch.log 輸出檔案。

  清單 2. test1 memwatch.log 檔案

  MEMWATCH 2.67 Copyright (C) 1992-1999 Johan Lindh

  ...

  double-free: <4> test1.c(15), 0x80517b4 was freed from test1.c(14)

  ...

  unfreed: <2> test1.c(11), 512 bytes at 0x80519e4

  {FE FE FE FE FE FE FE FE FE FE FE FE ..............}

  Memory usage statistics (global):

  N)umber of allocations made: 2

  L)argest memory usage : 1024

  T)otal of all alloc() calls: 1024

  U)nfreed bytes totals : 512

  MEMWATCH 為您顯示真正導致問題的行。如果您釋放一個已經釋放過的指標,它會告訴您。對於沒有釋放的記憶體也一樣。日誌結尾部分顯示統計資訊,包括洩漏了多少記憶體,使用了多少記憶體,以及總共分配了多少記憶體。

  YAMD

  YAMD 軟體包由 Nate Eldredge 編寫,可以查詢 C 和 C++ 中動態的、與記憶體分配有關的問題。在撰寫本文時,YAMD 的最新版本為 0.32。請下載 yamd-0.32.tar.gz(請參閱參考資料)。執行 make 命令來構建程式;然後執行 make install 命令安裝程式並設定工具。

  一旦您下載了 YAMD 之後,請在 test1.c 上使用它。請刪除 #include memwatch.h 並對 makefile 進行如下小小的修改:

  使用 YAMD 的 test1

  gcc -g test1.c -o test1

  清單 3 展示了來自 test1 上的 YAMD 的輸出。

  清單 3. 使用 YAMD 的 test1 輸出

  YAMD version 0.32

  Executable: /usr/src/test/yamd-0.32/test1

  ...

  INFO: Normal allocation of this block

  Address 0x40025e00, size 512

  ...

  INFO: Normal allocation of this block

  Address 0x40028e00, size 512

  ...

  INFO: Normal deallocation of this block

  Address 0x40025e00, size 512

  ...

  ERROR: Multiple freeing At

  free of pointer already freed

  Address 0x40025e00, size 512

  ...

  WARNING: Memory leak

  Address 0x40028e00, size 512

  WARNING: Total memory leaks:

  1 unfreed allocations totaling 512 bytes

  *** Finished at Tue ... 10:07:15 2002

  Allocated a grand total of 1024 bytes 2 allocations

  Average of 512 bytes per allocation

  Max bytes allocated at one time: 1024

  24 K alloced internally / 12 K mapped now / 8 K max

  Virtual program size is 1416 K

  End.

  YAMD 顯示我們已經釋放了記憶體,而且存在記憶體洩漏。讓我們在清單 4 中另一個樣本程式上試試 YAMD。

  清單 4. 記憶體程式碼(test2.c)

  #include

  #include

  int main(void)

  {

  char *ptr1;

  char *ptr2;

  char *chptr;

  int i = 1;

  ptr1 = malloc(512);

  ptr2 = malloc(512);

  chptr = (char *)malloc(512);

  for (i; i <= 512; i++) {

  chptr[i] = 'S';

  }

  ptr2 = ptr1;

  free(ptr2);

  free(ptr1);

  free(chptr);

  }

  您可以使用下面的命令來啟動 YAMD:

  ./run-yamd /usr/src/test/test2/test2

  清單 5 顯示了在樣本程式 test2 上使用 YAMD 得到的輸出。YAMD 告訴我們在 for 迴圈中有“越界(out-of-bounds)”的情況。

  清單 5. 使用 YAMD 的 test2 輸出

  Running /usr/src/test/test2/test2

  Temp output to /tmp/yamd-out.1243

  *********

  ./run-yamd: line 101: 1248 Segmentation fault (core dumped)

  YAMD version 0.32

  Starting run: /usr/src/test/test2/test2

  Executable: /usr/src/test/test2/test2

  Virtual program size is 1380 K

  ...

  INFO: Normal allocation of this block

  Address 0x40025e00, size 512

  ...

  INFO: Normal allocation of this block

  Address 0x40028e00, size 512

  ...

  INFO: Normal allocation of this block

  Address 0x4002be00, size 512

  ERROR: Crash

  ...

  Tried to write address 0x4002c000

  Seems to be part of this block:

  Address 0x4002be00, size 512

  ...

  Address in question is at offset 512 (out of bounds)

  Will dump core after checking heap.

  Done.

  MEMWATCH 和 YAMD 都是很


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-957060/,如需轉載,請註明出處,否則將追究法律責任。

相關文章