1. gzyueqian
      18529173453
      首頁 > 新聞中心 > > 正文

      揭開Linux系統內核調試器的神秘面紗

      更新時間: 2007-05-22 11:20:25來源: 粵嵌教育瀏覽量:1159


        KDB 入門指南

        調試內核問題時,能夠跟蹤內核執行情況并查看其內存和數據結構是非常有用的。Linux 中的內置內 核調試器 KDB 提供了這種功能。在本文中您把了解怎么樣使用 KDB 所提供的功能,以及怎么樣在 Linux 機器上安裝和設置 KDB。您還把熟悉 KDB 中可以使用的命令以及設置和顯示選項。

        Linux 內核調試器(KDB)允許您調試 Linux 內核。這個恰如其名的工具實質上是內核代碼的補丁,它允許高手訪問內核內存和數據結構。KDB 的主要優點之一就是它不需要用另一臺機器進行調試:您可以調試正在運行的內核。

        設置一臺用于 KDB 的機器需要花費一些工作,因為需要給內核打補丁并進行重新編譯。KDB 的用戶應當熟悉 Linux 內核的編譯(在一定程度上還要熟悉內核內部機理),但是如果您需要編譯內核方面的幫助,請參閱本文結尾處的參考資料一節。

        在本文中,我們把從有關下載 KDB 補丁、打補丁、(重新)編譯內核以及啟動 KDB 方面的信息著手。然后我們把了解 KDB 命令并研究一些較常用的命令。,我們把研究一下有關設置和顯示選項方面的一些詳細信息。

        入門

        KDB 項目是由 Silicon Graphics 維護的(請參閱參考資料以獲取鏈接),您需要從它的 FTP 站點下載與內核版本有關的補丁。(在編寫本文時)可用的 KDB 版本是 4.2。您把需要下載并應用兩個補丁。

        一個是“公共的”補丁,包含了對通用內核代碼的更改,另一個是特定于體系結構的補丁。補丁可作為 bz2 文件獲取。例如,在運行 2.4.20 內核的 x86 機器上,您會需要 kdb-v4.2-2.4.20-common-1.bz2 和 kdb-v4.2-2.4.20-i386-1.bz2。

        這里所提供的所有示例都是針對 i386 體系結構和 2.4.20 內核的。您把需要根據您的機器和內核版本進行適當的更改。您還需要擁有 root 許可權以執行這些操作。

        把文件復制到 /usr/src/linux 目錄中并從用 bzip2 壓縮的文件解壓縮補丁文件:

      #bzip2 -d kdb-v4.2-2.4.20-common-1.bz2

      #bzip2 -d kdb-v4.2-2.4.20-i386-1.bz2

        您把獲得 kdb-v4.2-2.4.20-common-1 和 kdb-v4.2-2.4-i386-1 文件。

        現在,應用這些補丁:

      #patch -p1

      #patch -p1

        這些補丁應該干凈利落地加以應用。查找任何以 .rej 結尾的文件。這個擴展名表明這些是失敗的補丁。如果內核樹沒問題,那么補丁的應用就不會有任何問題。

        接下來,需要構建內核以支持 KDB。步是設置 CONFIG_KDB 選項。使用您喜歡的配置機制(xconfig 和 menuconfig 等)來完成這一步。轉到結尾處的“Kernel hacking”部分并選擇“Built-in Kernel Debugger support”選項。

        您還可以根據自己的偏好選擇其它兩個選項。選擇“Compile the kernel with frame pointers”選項(如果有的話)則設置 CONFIG_FRAME_POINTER 標志。這把產生更好的堆棧回溯,因為幀指針寄存器被用作幀指針而不是通用寄存器。
        您還可以選擇“KDB off by default”選項。這把設置 CONFIG_KDB_OFF 標志,并且在缺省情況下把關閉 KDB。我們把在后面一節中對此進行詳細介紹。

        保存配置,然后退出。重新編譯內核。建議在構建內核之前執行“make clean”。用常用方式安裝內核并引導它。

        初始化并設置環境變量

        您可以定義把在 KDB 初始化期間執行的 KDB 命令。需要在純文本文件 kdb_cmds 中定義這些命令,該文件位于 Linux 源代碼樹(當然是在打了補丁之后)的 KDB 目錄中。該文件還可以用來定義設置顯示和打印選項的環境變量。文件開頭的注釋提供了編輯文件方面的幫助。使用這個文件的缺點是,在您更改了文件之后需要重新構建并重新安裝內核。

        激活 KDB

        如果編譯期間沒有選中 CONFIG_KDB_OFF,那么在缺省情況下 KDB 是活動的。否則,您需要顯式地激活它 - 通過在引導期間把 kdb=on 標志傳遞給內核或者通過在掛裝了 /proc 之后執行該工作:

        #echo "1" >/proc/sys/kernel/kdb

        倒過來執行上述步驟則會取消激活 KDB。也就是說,如果缺省情況下 KDB 是打開的,那么把 kdb=off 標志傳遞給內核或者執行下面這個操作把會取消激活 KDB:

        #echo "0" >/proc/sys/kernel/kdb

        我們可以看到 rmqueue() 被 __alloc_pages 調用,后者接下來又被 _alloc_pages 調用,以此類推。

        每一幀的個雙字(double word)指向下一幀,這后面緊跟著調用函數的地址。因此,跟蹤堆棧就變成一件輕松的工作了。

        go 命令可以有選擇地以一個地址作為參數。如果您想在某個特定地址處繼續執行,則可以提供該地址作為參數。另一個辦法是使用 rm 命令修改指令指針寄存器,然后只要輸入 go。如果您想跳過似乎會引起問題的某個特定指令或一組指令,這就會很有用。但是,請注意,該指令使用不慎會造成嚴重的問題,系統可能會嚴重崩潰。

        您可以利用一個名為 defcmd 的有用命令來定義自己的命令集。例如,每當遇到斷點時,您可能希望能同時檢查某個特殊變量、檢查某些寄存器的內容并轉儲堆棧。通常,您必須要輸入一系列命令,以便能同時執行所有這些工作。defcmd 允許您定義自己的命令,該命令可以包含一個或多個預定義的 KDB 命令。然后只需要用一個命令就可以完成所有這三項工作。其語法如下:

      [code:1:6ddc15f4ad][0]kdb> defcmd name "usage" "help"

      [0]kdb> [defcmd] type the commands here

      [0]kdb> [defcmd] endefcmd [/code:1:6ddc15f4ad]

        例如,可以定義一個(簡單的)新命令 hari,它顯示從地址 0xc000000 開始的一行內存、顯示寄存器的內容并轉儲堆棧:

      [code:1:6ddc15f4ad][0]kdb> defcmd hari "" "no arguments needed"


      [0]kdb> [defcmd] md 0xc000000 1


      [0]kdb> [defcmd] rd


      [0]kdb> [defcmd] md %ebp 1


      [0]kdb> [defcmd] endefcmd [/code:1:6ddc15f4ad]

      該命令的輸出會是:

      [code:1:6ddc15f4ad][0]kdb> hari

      [hari]kdb> md 0xc000000 1

      0xc000000 00000001 f000e816 f000e2c3 f000e816

      [hari]kdb> rd

      eax = 0x00000000 ebx = 0xc0105330 ecx = 0xc0466000 edx = 0xc0466000
      ....
      ...

      [hari]kdb> md %ebp 1

      0xc0467fbc c0467fd0 c01053d2 00000002 000a0200

      [0]kdb> [/code:1:6ddc15f4ad]

        可以使用 bph 和 bpha 命令(假如體系結構支持使用硬件寄存器)來應用讀寫斷點。這意味著每當從某個特定地址讀取數據或將數據寫入該地址時,我們都可以對此進行控制。當調試數據/內存毀壞問題時這可能會極其方便,在這種情況中您可以用它來識別毀壞的代碼/進程。
      示例

      [code:1:6ddc15f4ad]每當將四個字節寫入地址 0xc0204060 時就進入內核調試器:

      [0]kdb> bph 0xc0204060 dataw 4

      在讀取從 0xc000000 開始的至少兩個字節的數據時進入內核調試器:

      [0]kdb> bph 0xc000000 datar 2[/code:1:6ddc15f4ad]

      [size=18:6ddc15f4ad]結束語[/size:6ddc15f4ad]

        對于執行內核調試,KDB 是一個方便的且功能強大的工具。它提供了各種選項,并且使我們能夠分析內存內容和數據結構。妙的是,它不需要用另一臺機器來執行調試。

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

        內存泄漏(即 malloc() 內存在對應的 free() 調用執行后永不被釋放)和緩沖區溢出(例如對以前分配到某數組的內存進行寫操作)是一些常見的問題,它們可能很難檢測到。這一部分將討論幾個調試工具,它們極大地簡化了檢測和找出內存問題的過程。

        MEMWATCH 由 Johan Lindh 編寫,是一個開放源代碼 C 語言內存錯誤檢測工具,您可以自己下載它(請參閱本文后面部分的參考資料)。只要在代碼中添加一個頭文件并在 gcc 語句中定義了 MEMWATCH 之后,您就可以跟蹤程序中的內存泄漏和錯誤了。MEMWATCH 支持 ANSI C,它提供結果日志紀錄,能檢測雙重釋放(double-free)、錯誤釋放(erroneous free)、沒有釋放的內存(unfreed memory)、溢出和下溢等等。

      清單 1. 內存樣本(test1.c)

      [code:1:ff78191c7b]#include

      #include

      #include "memwatch.h"


      int main(void)

      {

      char *ptr1;

      char *ptr2;


      ptr1 = malloc(512);

      ptr2 = malloc(512);


      ptr2 = ptr1;

      free(ptr2);

      free(ptr1);

      }[/code:1:ff78191c7b]

        清單 1 中的代碼將分配兩個 512 字節的內存塊,然后指向個內存塊的指針被設定為指向第二個內存塊。結果,第二個內存塊的地址丟失,從而產生了內存泄漏。

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

      test1

      [code:1:ff78191c7b]gcc -DMEMWATCH -DMW_STDIO test1.c memwatch c -o test1[/code:1:ff78191c7b]

      當您運行 test1 程序后,它會生成一個關于泄漏的內存的報告。清單 2 展示了示例 memwatch.log 輸出文件。

      清單 2. test1 memwatch.log 文件

      [code:1:ff78191c7b]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[/code:1:ff78191c7b]

      MEMWATCH 為您顯示真正導致問題的行。如果您釋放一個已經釋放過的指針,它會告訴您。對于沒有釋放的內存也一樣。日志結尾部分顯示統計信息,包括泄漏了多少內存,使用了多少內存,以及總共分配了多少內存。

      [color=blue:ff78191c7b]YAMD[/color:ff78191c7b]

      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 輸出

      [code:1:ff78191c7b]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.[/code:1:ff78191c7b]

      YAMD 顯示我們已經釋放了內存,而且存在內存泄漏。讓我們在清單 4 中另一個樣本程序上試試 YAMD。

      清單 4. 內存代碼(test2.c)

      [code:1:ff78191c7b]#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);

      }[/code:1:ff78191c7b]

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

      [code:1:ff78191c7b]./run-yamd /usr/src/test/test2/test2 [/code:1:ff78191c7b]

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

      清單 5. 使用 YAMD 的 test2 輸出

      [code:1:ff78191c7b]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.[/code:1:ff78191c7b]

        MEMWATCH 和 YAMD 都是很有用的調試工具,它們的使用方法有所不同。對于 MEMWATCH,您需要添加包含文件 memwatch.h 并打開兩個編譯時間標記。對于鏈接(link)語句,YAMD 只需要 -g 選項。

      免費預約試聽課

      亚洲另类欧美综合久久图片区_亚洲中文字幕日产无码2020_欧美日本一区二区三区桃色视频_亚洲AⅤ天堂一区二区三区

      
      

      1. 日本一区二区三不卡高清区免费 | 在线观看亚州精品 | 亚洲欧美在线中文理论 | 亚洲日韩欧美精品一中文字幕 | 夜夜躁日日躁狠狠久久AV | 亚洲国产一线播放 |