亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 3435 | 回復: 1
打印 上一主題 下一主題

在 Linux 上找出并解決程序錯誤的主要方法(轉) [復制鏈接]

論壇徽章:
0
跳轉到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2007-03-28 15:53 |只看該作者 |倒序瀏覽
在LoveUnix上看到的,挺不錯,轉給大家。

PS:文章里提到的工具可以在Google上找。


------------------------------------------------------------------------------------------------------------------

  1. 轉自:http://bbs.loveunix.net/viewthread.php?tid=25068&extra=&page=2


  2. 您可以用各種方法來監(jiān)控運行著的用戶空間程序:可以為其運行調(diào)試器并單步調(diào)試該程序,添加打印語句,或者添加工具來分析程序。本文描

  3. 述了幾種可以用來調(diào)試在 Linux 上運行的程序的方法。我們將回顧四種調(diào)試問題的情況,這些問題包括段錯誤,內(nèi)存溢出和泄漏,還有掛起。
  4. 本文討論了四種調(diào)試 Linux 程序的情況。在第 1 種情況中,我們使用了兩個有內(nèi)存分配問題的樣本程序,使用 MEMWATCH 和 Yet Another

  5. Malloc Debugger(YAMD)工具來調(diào)試它們。在第 2 種情況中,我們使用了 Linux 中的 strace 實用程序,它能夠跟蹤系統(tǒng)調(diào)用和信號,從而

  6. 找出程序發(fā)生錯誤的地方。在第 3 種情況中,我們使用 Linux 內(nèi)核的 Oops 功能來解決程序的段錯誤,并向您展示如何設置內(nèi)核源代碼級調(diào)

  7. 試器(kernel source level debugger,kgdb),以使用 GNU 調(diào)試器(GNU debugger,gdb)來解決相同的問題;kgdb 程序是使用串行連接的

  8. Linux 內(nèi)核遠程 gdb。在第 4 種情況中,我們使用 Linux 上提供的魔術鍵控順序(magic key sequence)來顯示引發(fā)掛起問題的組件的信息

  9. 。

  10. 常見調(diào)試方法
  11. 當您的程序中包含錯誤時,很可能在代碼中某處有一個條件,您認為它為真(true),但實際上是假(false)。找出錯誤的過程也就是在找出

  12. 錯誤后推翻以前一直確信為真的某個條件過程。

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

  14. 在源代碼中的某處,某變量有特定的值。
  15. 在給定的地方,某個結構已被正確設置。
  16. 對于給定的 if-then-else 語句,if 部分就是被執(zhí)行的路徑。
  17. 當子例程被調(diào)用時,該例程正確地接收到了它的參數(shù)。

  18. 找出錯誤也就是要確定上述所有情況是否存在。如果您確信在子例程被調(diào)用時某變量應該有特定的值,那么就檢查一下情況是否如此。如果您

  19. 相信 if 結構會被執(zhí)行,那么也檢查一下情況是否如此。通常,您的假設都會是正確的,但最終您會找到與假設不符的情況。結果,您就會找

  20. 出發(fā)生錯誤的地方。

  21. 調(diào)試是您無法逃避的任務。進行調(diào)試有很多種方法,比如將消息打印到屏幕上、使用調(diào)試器,或只是考慮程序執(zhí)行的情況并仔細地揣摩問題所

  22. 在。

  23. 在修正問題之前,您必須找出它的源頭。舉例來說,對于段錯誤,您需要了解段錯誤發(fā)生在代碼的哪一行。一旦您發(fā)現(xiàn)了代碼中出錯的行,請

  24. 確定該方法中變量的值、方法被調(diào)用的方式以及關于錯誤如何發(fā)生的詳細情況。使用調(diào)試器將使找出所有這些信息變得很簡單。如果沒有調(diào)試

  25. 器可用,您還可以使用其它的工具。(請注意,產(chǎn)品環(huán)境中可能并不提供調(diào)試器,而且 Linux 內(nèi)核沒有內(nèi)建的調(diào)試器。)

  26. 本文將討論一類通過人工檢查代碼不容易找到的問題,而且此類問題只在很少見的情況下存在。內(nèi)存錯誤通常在多種情況同時存在時出現(xiàn),而

  27. 且您有時只能在部署程序之后才能發(fā)現(xiàn)內(nèi)存錯誤。



  28. 第 1 種情況:內(nèi)存調(diào)試工具
  29. C 語言作為 Linux 系統(tǒng)上標準的編程語言給予了我們對動態(tài)內(nèi)存分配很大的控制權。然而,這種自由可能會導致嚴重的內(nèi)存管理問題,而這些

  30. 問題可能導致程序崩潰或隨時間的推移導致性能降級。

  31. 內(nèi)存泄漏(即 malloc() 內(nèi)存在對應的 free() 調(diào)用執(zhí)行后永不被釋放)和緩沖區(qū)溢出(例如對以前分配到某數(shù)組的內(nèi)存進行寫操作)是一些

  32. 常見的問題,它們可能很難檢測到。這一部分將討論幾個調(diào)試工具,它們極大地簡化了檢測和找出內(nèi)存問題的過程。

  33. MEMWATCH
  34. MEMWATCH 由 Johan Lindh 編寫,是一個開放源代碼 C 語言內(nèi)存錯誤檢測工具,您可以自己下載它(請參閱本文后面部分的參考資料)。只要

  35. 在代碼中添加一個頭文件并在 gcc 語句中定義了 MEMWATCH 之后,您就可以跟蹤程序中的內(nèi)存泄漏和錯誤了。MEMWATCH 支持 ANSI C,它提供

  36. 結果日志紀錄,能檢測雙重釋放(double-free)、錯誤釋放(erroneous free)、沒有釋放的內(nèi)存(unfreed memory)、溢出和下溢等等。

  37. 清單 1. 內(nèi)存樣本(test1.c)

  38. CODE
  39. #include <stdlib.h>
  40. #include <stdio.h>
  41. #include "memwatch.h"

  42. int main(void)
  43. {
  44. char *ptr1;
  45. char *ptr2;

  46. ptr1 = malloc(512);
  47. ptr2 = malloc(512);

  48. ptr2 = ptr1;
  49. free(ptr2);
  50. free(ptr1);
  51. }



  52. 清單 1 中的代碼將分配兩個 512 字節(jié)的內(nèi)存塊,然后指向第一個內(nèi)存塊的指針被設定為指向第二個內(nèi)存塊。結果,第二個內(nèi)存塊的地址丟失

  53. ,從而產(chǎn)生了內(nèi)存泄漏。

  54. 現(xiàn)在我們編譯清單 1 的 memwatch.c。下面是一個 makefile 示例:

  55. test1
  56. gcc -DMEMWATCH -DMW_STDIO test1.c memwatch
  57. c -o test1



  58. 當您運行 test1 程序后,它會生成一個關于泄漏的內(nèi)存的報告。


  59. 清單 2 展示了示例 memwatch.log 輸出文件。

  60. 清單 2. test1 memwatch.log 文件
  61. MEMWATCH 2.67 Copyright &copy; 1992-1999 Johan Lindh

  62. ...
  63. double-free: <4> test1.c(15), 0x80517b4 was freed from test1.c(14)
  64. ...
  65. unfreed: <2> test1.c(11), 512 bytes at 0x80519e4
  66. {FE FE FE FE FE FE FE FE FE FE FE FE ..............}

  67. Memory usage statistics (global):
  68. N)umber of allocations made: 2
  69. L)argest memory usage : 1024
  70. T)otal of all alloc() calls: 1024
  71. U)nfreed bytes totals : 512



  72. MEMWATCH 為您顯示真正導致問題的行。如果您釋放一個已經(jīng)釋放過的指針,它會告訴您。對于沒有釋放的內(nèi)存也一樣。日志結尾部分顯示統(tǒng)計

  73. 信息,包括泄漏了多少內(nèi)存,使用了多少內(nèi)存,以及總共分配了多少內(nèi)存。

  74. YAMD
  75. YAMD 軟件包由 Nate Eldredge 編寫,可以查找 C 和 C++ 中動態(tài)的、與內(nèi)存分配有關的問題。在撰寫本文時,YAMD 的最新版本為 0.32。請

  76. 下載 yamd-0.32.tar.gz(請參閱參考資料)。執(zhí)行 make 命令來構建程序;然后執(zhí)行 make install 命令安裝程序并設置工具。

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

  78. 使用 YAMD 的 test1
  79. gcc -g test1.c -o test1

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

  81. 清單 3. 使用 YAMD 的 test1 輸出
  82. YAMD version 0.32
  83. Executable: /usr/src/test/yamd-0.32/test1
  84. ...
  85. INFO: Normal allocation of this block
  86. Address 0x40025e00, size 512
  87. ...
  88. INFO: Normal allocation of this block
  89. Address 0x40028e00, size 512
  90. ...
  91. INFO: Normal deallocation of this block
  92. Address 0x40025e00, size 512
  93. ...
  94. ERROR: Multiple freeing At
  95. free of pointer already freed
  96. Address 0x40025e00, size 512
  97. ...
  98. WARNING: Memory leak
  99. Address 0x40028e00, size 512
  100. WARNING: Total memory leaks:
  101. 1 unfreed allocations totaling 512 bytes

  102. *** Finished at Tue ... 10:07:15 2002
  103. Allocated a grand total of 1024 bytes 2 allocations
  104. Average of 512 bytes per allocation
  105. Max bytes allocated at one time: 1024
  106. 24 K alloced internally / 12 K mapped now / 8 K max
  107. Virtual program size is 1416 K
  108. End.



  109. YAMD 顯示我們已經(jīng)釋放了內(nèi)存,而且存在內(nèi)存泄漏。讓我們在清單 4 中另一個樣本程序上試試 YAMD。

  110. 清單 4. 內(nèi)存代碼(test2.c)

  111. CODE
  112. #include <stdlib.h>
  113. #include <stdio.h>

  114. int main(void)
  115. {
  116. char *ptr1;
  117. char *ptr2;
  118. char *chptr;
  119. int i = 1;
  120. ptr1 = malloc(512);
  121. ptr2 = malloc(512);
  122. chptr = (char *)malloc(512);
  123. for (i; i <= 512; i++) {
  124.    chptr[i] = 'S';
  125. }   
  126. ptr2 = ptr1;
  127. free(ptr2);
  128. free(ptr1);
  129. free(chptr);
  130. }



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

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

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

  134. 清單 5. 使用 YAMD 的 test2 輸出
  135. Running /usr/src/test/test2/test2
  136. Temp output to /tmp/yamd-out.1243
  137. *********
  138. ./run-yamd: line 101: 1248 Segmentation fault (core dumped)
  139. YAMD version 0.32
  140. Starting run: /usr/src/test/test2/test2
  141. Executable: /usr/src/test/test2/test2
  142. Virtual program size is 1380 K
  143. ...
  144. INFO: Normal allocation of this block
  145. Address 0x40025e00, size 512
  146. ...
  147. INFO: Normal allocation of this block
  148. Address 0x40028e00, size 512
  149. ...
  150. INFO: Normal allocation of this block
  151. Address 0x4002be00, size 512
  152. ERROR: Crash
  153. ...
  154. Tried to write address 0x4002c000
  155. Seems to be part of this block:
  156. Address 0x4002be00, size 512
  157. ...
  158. Address in question is at offset 512 (out of bounds)
  159. Will dump core after checking heap.
  160. Done.



  161. MEMWATCH 和 YAMD 都是很有用的調(diào)試工具,它們的使用方法有所不同。對于 MEMWATCH,您需要添加包含文件 memwatch.h 并打開兩個編譯時

  162. 間標記。對于鏈接(link)語句,YAMD 只需要 -g 選項。

  163. Electric Fence
  164. 多數(shù) Linux 分發(fā)版包含一個 Electric Fence 包,不過您也可以選擇下載它。Electric Fence 是一個由 Bruce Perens 編寫的 malloc() 調(diào)

  165. 試庫。它就在您分配內(nèi)存后分配受保護的內(nèi)存。如果存在 fencepost 錯誤(超過數(shù)組末尾運行),程序就會產(chǎn)生保護錯誤,并立即結束。通過

  166. 結合 Electric Fence 和 gdb,您可以精確地跟蹤到哪一行試圖訪問受保護內(nèi)存。Electric Fence 的另一個功能就是能夠檢測內(nèi)存泄漏。


  167. 第 2 種情況:使用 strace
  168. strace 命令是一種強大的工具,它能夠顯示所有由用戶空間程序發(fā)出的系統(tǒng)調(diào)用。strace 顯示這些調(diào)用的參數(shù)并返回符號形式的值。strace

  169. 從內(nèi)核接收信息,而且不需要以任何特殊的方式來構建內(nèi)核。將跟蹤信息發(fā)送到應用程序及內(nèi)核開發(fā)者都很有用。在清單 6 中,分區(qū)的一種格

  170. 式有錯誤,清單顯示了 strace 的開頭部分,內(nèi)容是關于調(diào)出創(chuàng)建文件系統(tǒng)操作(mkfs)的。strace 確定哪個調(diào)用導致問題出現(xiàn)。

  171. 清單 6. mkfs 上 strace 的開頭部分

  172. CODE
  173. execve("/sbin/mkfs.jfs", ["mkfs.jfs", "-f", "/dev/test1"], &
  174. ...
  175. open("/dev/test1", O_RDWR|O_LARGEFILE) = 4
  176. stat64("/dev/test1", {st_mode=&, st_rdev=makedev(63, 255), ...}) = 0
  177. ioctl(4, 0x40041271, 0xbfffe128) = -1 EINVAL (Invalid argument)
  178. write(2, "mkfs.jfs: warning - cannot setb" ..., 98mkfs.jfs: warning -
  179. cannot set blocksize on block device /dev/test1: Invalid argument )
  180. = 98
  181. stat64("/dev/test1", {st_mode=&, st_rdev=makedev(63, 255), ...}) = 0
  182. open("/dev/test1", O_RDONLY|O_LARGEFILE) = 5
  183. ioctl(5, 0x80041272, 0xbfffe124) = -1 EINVAL (Invalid argument)
  184. write(2, "mkfs.jfs: can\'t determine device"..., ..._exit(1)
  185. = ?


  186. 清單 6 顯示 ioctl 調(diào)用導致用來格式化分區(qū)的 mkfs 程序失敗。ioctl BLKGETSIZE64 失敗。(BLKGET-SIZE64 在調(diào)用 ioctl 的源代碼中定

  187. 義。) BLKGETSIZE64 ioctl 將被添加到 Linux 中所有的設備,而在這里,邏輯卷管理器還不支持它。因此,如果 BLKGETSIZE64 ioctl 調(diào)用

  188. 失敗,mkfs 代碼將改為調(diào)用較早的 ioctl 調(diào)用;這使得 mkfs 適用于邏輯卷管理器。
復制代碼

論壇徽章:
0
2 [報告]
發(fā)表于 2007-03-28 15:53 |只看該作者
  1. 第 3 種情況:使用 gdb 和 Oops
  2. 您可以從命令行使用 gdb 程序(Free Software Foundation 的調(diào)試器)來找出錯誤,也可以從諸如 Data Display Debugger(DDD)這樣的幾

  3. 個圖形工具之一使用 gdb 程序來找出錯誤。您可以使用 gdb 來調(diào)試用戶空間程序或 Linux 內(nèi)核。這一部分只討論從命令行運行 gdb 的情況

  4. 。

  5. 使用 gdb program name 命令啟動 gdb。gdb 將載入可執(zhí)行程序符號并顯示輸入提示符,讓您可以開始使用調(diào)試器。您可以通過三種方式用

  6. gdb 查看進程:

  7. 使用 attach 命令開始查看一個已經(jīng)運行的進程;attach 將停止進程。


  8. 使用 run 命令執(zhí)行程序并從頭開始調(diào)試程序。


  9. 查看已有的核心文件來確定進程終止時的狀態(tài)。要查看核心文件,請用下面的命令啟動 gdb。
  10. gdb programname corefilename
  11. 要用核心文件進行調(diào)試,您不僅需要程序的可執(zhí)行文件和源文件,還需要核心文件本身。要用核心文件啟動 gdb,請使用 -c 選項:

  12. gdb -c core programname

  13. gdb 顯示哪行代碼導致程序發(fā)生核心轉儲。

  14. 在運行程序或連接到已經(jīng)運行的程序之前,請列出您覺得有錯誤的源代碼,設置斷點,然后開始調(diào)試程序。您可以使用 help 命令查看全面的

  15. gdb 在線幫助和詳細的教程。

  16. kgdb
  17. kgdb 程序(使用 gdb 的遠程主機 Linux 內(nèi)核調(diào)試器)提供了一種使用 gdb 調(diào)試 Linux 內(nèi)核的機制。kgdb 程序是內(nèi)核的擴展,它讓您能夠

  18. 在遠程主機上運行 gdb 時連接到運行用 kgdb 擴展的內(nèi)核機器。您可以接著深入到內(nèi)核中、設置斷點、檢查數(shù)據(jù)并進行其它操作(類似于您在

  19. 應用程序上使用 gdb 的方式)。這個補丁的主要特點之一就是運行 gdb 的主機在引導過程中連接到目標機器(運行要被調(diào)試的內(nèi)核)。這讓

  20. 您能夠盡早開始調(diào)試。請注意,補丁為 Linux 內(nèi)核添加了功能,所以 gdb 可以用來調(diào)試 Linux 內(nèi)核。

  21. 使用 kgdb 需要兩臺機器:一臺是開發(fā)機器,另一臺是測試機器。一條串行線(空調(diào)制解調(diào)器電纜)將通過機器的串口連接它們。您希望調(diào)試

  22. 的內(nèi)核在測試機器上運行;gdb 在開發(fā)機器上運行。gdb 使用串行線與您要調(diào)試的內(nèi)核通信。

  23. 請遵循下面的步驟來設置 kgdb 調(diào)試環(huán)境:


  24. 下載您的 Linux 內(nèi)核版本適用的補丁。


  25. 將組件構建到內(nèi)核,因為這是使用 kgdb 最簡單的方法。(請注意,有兩種方法可以構建多數(shù)內(nèi)核組件,比如作為模塊或直接構建到內(nèi)核中。

  26. 舉例來說,日志紀錄文件系統(tǒng)(Journaled File System,JFS)可以作為模塊構建,或直接構建到內(nèi)核中。通過使用 gdb 補丁,我們就可以將

  27. JFS 直接構建到內(nèi)核中。)


  28. 應用內(nèi)核補丁并重新構建內(nèi)核。


  29. 創(chuàng)建一個名為 .gdbinit 的文件,并將其保存在內(nèi)核源文件子目錄中(換句話說就是 /usr/src/linux)。文件 .gdbinit 中有下面四行代碼:
  30. set remotebaud 115200
  31. symbol-file vmlinux
  32. target remote /dev/ttyS0
  33. set output-radix 16


  34. 將 append=gdb 這一行添加到 lilo,lilo 是用來在引導內(nèi)核時選擇使用哪個內(nèi)核的引導載入程序。

  35. CODE
  36. image=/boot/bzImage-2.4.17
  37. label=gdb2417
  38. read-only
  39. root=/dev/sda8
  40. append="gdb gdbttyS=1 gdb-baud=115200 nmi_watchdog=0"

  41. 清單 7 是一個腳本示例,它將您在開發(fā)機器上構建的內(nèi)核和模塊引入測試機器。您需要修改下面幾項:


  42. best@sfb:用戶標識和機器名。
  43. /usr/src/linux-2.4.17:內(nèi)核源代碼樹的目錄。
  44. bzImage-2.4.17:測試機器上將引導的內(nèi)核名。
  45. rcp 和 rsync:必須允許它在構建內(nèi)核的機器上運行。

  46. 清單 7. 引入測試機器的內(nèi)核和模塊的腳本

  47. CODE
  48. set -x
  49. rcp best@sfb: /usr/src/linux-2.4.17/arch/i386/boot/bzImage /boot/bzImage-2.4.17
  50. rcp best@sfb:/usr/src/linux-2.4.17/System.map /boot/System.map-2.4.17
  51. rm -rf /lib/modules/2.4.17
  52. rsync -a best@sfb:/lib/modules/2.4.17 /lib/modules
  53. chown -R root /lib/modules/2.4.17
  54. lilo


  55. 現(xiàn)在我們可以通過改為使用內(nèi)核源代碼樹開始的目錄來啟動開發(fā)機器上的 gdb 程序了。在本示例中,內(nèi)核源代碼樹位于 /usr/src/linux-

  56. 2.4.17。輸入 gdb 啟動程序。

  57. 如果一切正常,測試機器將在啟動過程中停止。輸入 gdb 命令 cont 以繼續(xù)啟動過程。一個常見的問題是,空調(diào)制解調(diào)器電纜可能會被連接到

  58. 錯誤的串口。如果 gdb 不啟動,將端口改為第二個串口,這會使 gdb 啟動。

  59. 使用 kgdb 調(diào)試內(nèi)核問題

  60. 單 8 列出了 jfs_mount.c 文件的源代碼中被修改過的代碼,我們在代碼中創(chuàng)建了一個空指針異常,從而使代碼在第 109 行產(chǎn)生段錯誤。

  61. 清單 8. 修改過后的 jfs_mount.c 代碼

  62. CODE
  63. int jfs_mount(struct super_block *sb)
  64. {
  65. ...
  66. int ptr;             /* line 1 added */
  67. jFYI(1, ("\nMount JFS\n"));
  68. / *
  69. * read/validate superblock
  70. * (initialize mount inode from the superblock)
  71. * /
  72. if ((rc = chkSuper(sb))) {
  73.        goto errout20;
  74.    }
  75. 108     ptr=0;             /* line 2 added */
  76. 109     printk("%d\n",*ptr);     /* line 3 added */

  77. 清單 9 在向文件系統(tǒng)發(fā)出 mount 命令之后顯示一個 gdb 異常。kgdb 提供了幾條命令,如顯示數(shù)據(jù)結構和變量值以及顯示系統(tǒng)中的所有任務

  78. 處于什么狀態(tài)、它們駐留在何處、它們在哪些地方使用了 CPU 等等。清單 9 將顯示回溯跟蹤為該問題提供的信息;where 命令用來執(zhí)行反跟

  79. 蹤,它將告訴被執(zhí)行的調(diào)用在代碼中的什么地方停止。

  80. 清單 9. gdb 異常和反跟蹤

  81. CODE
  82. mount -t jfs /dev/sdb /jfs

  83. Program received signal SIGSEGV, Segmentation fault.
  84. jfs_mount (sb=0xf78a3800) at jfs_mount.c:109
  85. 109         printk("%d\n",*ptr);
  86. (gdb)where
  87. #0 jfs_mount (sb=0xf78a3800) at jfs_mount.c:109
  88. #1 0xc01a0dbb in jfs_read_super ... at super.c:280
  89. #2 0xc0149ff5 in get_sb_bdev ... at super.c:620
  90. #3 0xc014a89f in do_kern_mount ... at super.c:849
  91. #4 0xc0160e66 in do_add_mount ... at namespace.c:569
  92. #5 0xc01610f4 in do_mount ... at namespace.c:683
  93. #6 0xc01611ea in sys_mount ... at namespace.c:716
  94. #7 0xc01074a7 in system_call () at af_packet.c:1891
  95. #8 0x0 in ?? ()
  96. (gdb)

  97. 下一部分還將討論這個相同的 JFS 段錯誤問題,但不設置調(diào)試器,如果您在非 kgdb 內(nèi)核環(huán)境中執(zhí)行清單 8 中的代碼,那么它使用內(nèi)核可能

  98. 生成的 Oops 消息。

  99. Oops 分析
  100. Oops(也稱 panic,慌張)消息包含系統(tǒng)錯誤的細節(jié),如 CPU 寄存器的內(nèi)容。在 Linux 中,調(diào)試系統(tǒng)崩潰的傳統(tǒng)方法是分析在發(fā)生崩潰時發(fā)

  101. 送到系統(tǒng)控制臺的 Oops 消息。一旦您掌握了細節(jié),就可以將消息發(fā)送到 ksymoops 實用程序,它將試圖將代碼轉換為指令并將堆棧值映射到

  102. 內(nèi)核符號。在很多情況下,這些信息就足夠您確定錯誤的可能原因是什么了。請注意,Oops 消息并不包括核心文件。

  103. 讓我們假設系統(tǒng)剛剛創(chuàng)建了一條 Oops 消息。作為編寫代碼的人,您希望解決問題并確定什么導致了 Oops 消息的產(chǎn)生,或者您希望向顯示了

  104. Oops 消息的代碼的開發(fā)者提供有關您的問題的大部分信息,從而及時地解決問題。Oops 消息是等式的一部分,但如果不通過 ksymoops 程序

  105. 運行它也于事無補。下面的圖顯示了格式化 Oops 消息的過程。

  106. 格式化 Oops 消息


  107. ksymoops 需要幾項內(nèi)容:Oops 消息輸出、來自正在運行的內(nèi)核的 System.map 文件,還有 /proc/ksyms、vmlinux 和 /proc/modules。關于

  108. 如何使用 ksymoops,內(nèi)核源代碼 /usr/src/linux/Documentation/oops-tracing.txt 中或 ksymoops 手冊頁上有完整的說明可以參考。

  109. Ksymoops 反匯編代碼部分,指出發(fā)生錯誤的指令,并顯示一個跟蹤部分表明代碼如何被調(diào)用。

  110. 首先,將 Oops 消息保存在一個文件中以便通過 ksymoops 實用程序運行它。清單 10 顯示了由安裝 JFS 文件系統(tǒng)的 mount 命令創(chuàng)建的 Oops

  111. 消息,問題是由清單 8 中添加到 JFS 安裝代碼的那三行代碼產(chǎn)生的。

  112. 清單 10. ksymoops 處理后的 Oops 消息

  113. CODE
  114. ksymoops 2.4.0 on i686 2.4.17. Options used
  115. ... 15:59:37 sfb1 kernel: Unable to handle kernel NULL pointer dereference at
  116. virtual address 0000000
  117. ... 15:59:37 sfb1 kernel: c01588fc
  118. ... 15:59:37 sfb1 kernel: *pde = 0000000
  119. ... 15:59:37 sfb1 kernel: Oops: 0000
  120. ... 15:59:37 sfb1 kernel: CPU:    0
  121. ... 15:59:37 sfb1 kernel: EIP:    0010:[jfs_mount+60/704]

  122. ... 15:59:37 sfb1 kernel: Call Trace: [jfs_read_super+287/688]
  123. [get_sb_bdev+563/736] [do_kern_mount+189/336] [do_add_mount+35/208]
  124. [do_page_fault+0/1264]
  125. ... 15:59:37 sfb1 kernel: Call Trace: [<c0155d4f>]...
  126. ... 15:59:37 sfb1 kernel: [<c0106e04 ...
  127. ... 15:59:37 sfb1 kernel: Code: 8b 2d 00 00 00 00 55 ...

  128. >>EIP; c01588fc <jfs_mount+3c/2c0> <=====
  129. ...
  130. Trace; c0106cf3 <system_call+33/40>
  131. Code; c01588fc <jfs_mount+3c/2c0>
  132. 00000000 <_EIP>:
  133. Code; c01588fc <jfs_mount+3c/2c0>  <=====
  134.   0: 8b 2d 00 00 00 00     mov     0x0,%ebp    <=====
  135. Code; c0158902 <jfs_mount+42/2c0>
  136.   6:  55             push     %ebp

  137. 接下來,您要確定 jfs_mount 中的哪一行代碼引起了這個問題。Oops 消息告訴我們問題是由位于偏移地址 3c 的指令引起的。做這件事的辦

  138. 法之一是對 jfs_mount.o 文件使用 objdump 實用程序,然后查看偏移地址 3c。Objdump 用來反匯編模塊函數(shù),看看您的 C 源代碼會產(chǎn)生什

  139. 么匯編指令。清單 11 顯示了使用 objdump 后您將看到的內(nèi)容,接著,我們查看 jfs_mount 的 C 代碼,可以看到空值是第 109 行引起的。

  140. 偏移地址 3c 之所以很重要,是因為 Oops 消息將該處標識為引起問題的位置。

  141. 清單 11. jfs_mount 的匯編程序清單

  142. CODE
  143. 109    printk("%d\n",*ptr);

  144. objdump jfs_mount.o

  145. jfs_mount.o:     file format elf32-i386

  146. Disassembly of section .text:

  147. 00000000 <jfs_mount>:
  148.   0:55             push %ebp
  149. ...
  150. 2c:    e8 cf 03 00 00       call       400 <chkSuper>
  151. 31:    89 c3                   mov     %eax,%ebx
  152. 33:    58                pop     %eax
  153. 34:    85 db                   test     %ebx,%ebx
  154. 36:    0f 85 55 02 00 00 jne     291 <jfs_mount+0x291>
  155. 3c:    8b 2d 00 00 00 00 mov     0x0,%ebp << problem line above
  156. 42:    55            push     %ebp

  157. kdb
  158. Linux 內(nèi)核調(diào)試器(Linux kernel debugger,kdb)是 Linux 內(nèi)核的補丁,它提供了一種在系統(tǒng)能運行時對內(nèi)核內(nèi)存和數(shù)據(jù)結構進行檢查的辦

  159. 法。請注意,kdb 不需要兩臺機器,不過它也不允許您像 kgdb 那樣進行源代碼級別上的調(diào)試。您可以添加額外的命令,給出該數(shù)據(jù)結構的標

  160. 識或地址,這些命令便可以格式化和顯示基本的系統(tǒng)數(shù)據(jù)結構。目前的命令集允許您控制包括以下操作在內(nèi)的內(nèi)核操作:


  161. 處理器單步執(zhí)行
  162. 執(zhí)行到某條特定指令時停止
  163. 當存。ɑ蛐薷模┠硞特定的虛擬內(nèi)存位置時停止
  164. 當存取輸入/輸出地址空間中的寄存器時停止
  165. 對當前活動的任務和所有其它任務進行堆;厮莞櫍ㄍㄟ^進程 ID)
  166. 對指令進行反匯編

  167. 追擊內(nèi)存溢出

  168. 您肯定不想陷入類似在幾千次調(diào)用之后發(fā)生分配溢出這樣的情形。

  169. 我們的小組花了許許多多時間來跟蹤稀奇古怪的內(nèi)存錯誤問題。應用程序在我們的開發(fā)工作站上能運行,但在新的產(chǎn)品工作站上,這個應用程

  170. 序在調(diào)用 malloc() 兩百萬次之后就不能運行了。真正的問題是在大約一百萬次調(diào)用之后發(fā)生了溢出。新系統(tǒng)之所有存在這個問題,是因為被

  171. 保留的 malloc() 區(qū)域的布局有所不同,從而這些零散內(nèi)存被放置在了不同的地方,在發(fā)生溢出時破壞了一些不同的內(nèi)容。

  172. 我們用多種不同技術來解決這個問題,其中一種是使用調(diào)試器,另一種是在源代碼中添加跟蹤功能。在我職業(yè)生涯的大概也是這個時候,我便

  173. 開始關注內(nèi)存調(diào)試工具,希望能更快更有效地解決這些類型的問題。在開始一個新項目時,我最先做的事情之一就是運行 MEMWATCH 和 YAMD,

  174. 看看它們是不是會指出內(nèi)存管理方面的問題。

  175. 內(nèi)存泄漏是應用程序中常見的問題,不過您可以使用本文所講述的工具來解決這些問題。

  176. 第 4 種情況:使用魔術鍵控順序進行回溯跟蹤
  177. 如果在 Linux 掛起時您的鍵盤仍然能用,那請您使用以下方法來幫助解決掛起問題的根源。遵循這些步驟,您便可以顯示當前運行的進程和所

  178. 有使用魔術鍵控順序的進程的回溯跟蹤。


  179. 您正在運行的內(nèi)核必須是在啟用 CONFIG_MAGIC_SYS-REQ 的情況下構建的。您還必須處在文本模式。CLTR+ALT+F1 會使您進入文本模式,

  180. CLTR+ALT+F7 會使您回到 X Windows。
  181. 當在文本模式時,請按 <ALT+ScrollLock>,然后按 <Ctrl+ScrollLock>。上述魔術的擊鍵會分別給出當前運行的進程和所有進程的堆棧跟蹤。
  182. 請查找 /var/log/messages。如果一切設置正確,則系統(tǒng)應該已經(jīng)為您轉換了內(nèi)核的符號地址;厮莞檶⒈粚懙 /var/log/messages 文件中



  183. 結束語
  184. 幫助調(diào)試 Linux 上的程序有許多不同的工具可供使用。本文講述的工具可以幫助您解決許多編碼問題。能顯示內(nèi)存泄漏、溢出等等的位置的工

  185. 具可以解決內(nèi)存管理問題,我發(fā)現(xiàn) MEMWATCH 和 YAMD 很有幫助。

  186. 使用 Linux 內(nèi)核補丁會使 gdb 能在 Linux 內(nèi)核上工作,這對解決我工作中使用的 Linux 的文件系統(tǒng)方面的問題很有幫助。此外,跟蹤實用

  187. 程序能幫助確定在系統(tǒng)調(diào)用期間文件系統(tǒng)實用程序什么地方出了故障。下次當您要擺平 Linux 中的錯誤時,請試試這些工具中的某一個。

  188. 參考資料

  189. 下載 MEMWATCH。


  190. 下載 YAMD。


  191. 下載 ElectricFence。


  192. 請查看 Dynamic Probes 調(diào)試功能程序。


  193. 請閱讀文章“Linux software debugging with GDB”。(developerWorks,2001 年 2 月)


  194. 請訪問 IBM Linux Technology Center。


  195. 在 developerWorks Linux 專區(qū)可以找到更多的 Linux 文章。

  196. 關于作者
  197. Steve Best 在位于德克薩斯州奧斯汀的 IBM Linux Technology Center 工作。目前,他在做 Linux 項目的日志紀錄文件系統(tǒng)(Journaled

  198. File System,JFS)的工作。Steve 在操作系統(tǒng)方面有豐富的從業(yè)經(jīng)驗,他的著重的領域是文件系統(tǒng)、國際化和安全性
復制代碼
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術有限公司. 版權所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關心和支持過ChinaUnix的朋友們 轉載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP