<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > Linux內(nèi)核調(diào)試器內(nèi)幕(4)

          Linux內(nèi)核調(diào)試器內(nèi)幕(4)

          作者: 時(shí)間:2007-05-09 來源:網(wǎng)絡(luò) 收藏
          請遵循下面的步驟來設(shè)置 kgdb 調(diào)試環(huán)境:
          1.下載您的 Linux 內(nèi)核版本適用的補(bǔ)丁。
          2.將組件構(gòu)建到內(nèi)核,因?yàn)檫@是使用 kgdb 最簡單的方法。(請注意,有兩種方法可以構(gòu)建多數(shù)內(nèi)核組件,比如作為模塊或直接構(gòu)建到內(nèi)核中。舉例來說,日志紀(jì)錄文件系統(tǒng)(Journaled File System,JFS)可以作為模塊構(gòu)建,或直接構(gòu)建到內(nèi)核中。通過使用 gdb 補(bǔ)丁,我們就可以將 JFS 直接構(gòu)建到內(nèi)核中。)
          3.應(yīng)用內(nèi)核補(bǔ)丁并重新構(gòu)建內(nèi)核。
          4.創(chuàng)建一個(gè)名為 .gdbinit 的文件,并將其保存在內(nèi)核源文件子目錄中(換句話說就是 /usr/src/linux)。文件 .gdbinit 中有下面四行代碼:
          [code:1:627becdd94]oset remotebaud 115200
          osymbol-file vmlinux
          otarget remote /dev/ttyS0
          oset output-radix 16 [/code:1:627becdd94]

          5.將 append=gdb 這一行添加到 lilo,lilo 是用來在引導(dǎo)內(nèi)核時(shí)選擇使用哪個(gè)內(nèi)核的引導(dǎo)載入程序。
          [code:1:627becdd94]oimage=/boot/bzImage-2.4.17
          olabel=gdb2417
          oread-only
          oroot=/dev/sda8
          oappend=gdb gdbttyS=1 gdb-baud=115200 nmi_watchdog=0 [/code:1:627becdd94]
          清單 7 是一個(gè)腳本示例,它將您在開發(fā)機(jī)器上構(gòu)建的內(nèi)核和模塊引入測試機(jī)器。您需要修改下面幾項(xiàng):
          ?best@sfb:用戶標(biāo)識和機(jī)器名。
          ?/usr/src/linux-2.4.17:內(nèi)核源代碼樹的目錄。
          ?bzImage-2.4.17:測試機(jī)器上將引導(dǎo)的內(nèi)核名。
          ?rcp 和 rsync:必須允許它在構(gòu)建內(nèi)核的機(jī)器上運(yùn)行。
          清單 7. 引入測試機(jī)器的內(nèi)核和模塊的腳本

          [code:1:627becdd94]set -x
          rcp best@sfb: /usr/src/linux-2.4.17/arch/i386/boot/bzImage /boot/bzImage-2.4.17
          rcp best@sfb:/usr/src/linux-2.4.17/System.map /boot/System.map-2.4.17
          rm -rf /lib/modules/2.4.17
          rsync -a best@sfb:/lib/modules/2.4.17 /lib/modules
          chown -R root /lib/modules/2.4.17
          lilo[/code:1:627becdd94]
          現(xiàn)在我們可以通過改為使用內(nèi)核源代碼樹開始的目錄來啟動開發(fā)機(jī)器上的 gdb 程序了。在本示例中,內(nèi)核源代碼樹位于 /usr/src/linux-2.4.17。輸入 gdb 啟動程序。
          如果一切正常,測試機(jī)器將在啟動過程中停止。輸入 gdb 命令 cont 以繼續(xù)啟動過程。一個(gè)常見的問題是,空調(diào)制解調(diào)器電纜可能會被連接到錯誤的串口。如果 gdb 不啟動,將端口改為第二個(gè)串口,這會使 gdb 啟動。
          [color=darkblue:627becdd94]使用 kgdb 調(diào)試內(nèi)核問題[/color:627becdd94]
          清單 8 列出了 jfs_mount.c 文件的源代碼中被修改過的代碼,我們在代碼中創(chuàng)建了一個(gè)空指針異常,從而使代碼在第 109 行產(chǎn)生段錯誤。
          清單 8. 修改過后的 jfs_mount.c 代碼

          [code:1:627becdd94]int jfs_mount(struct super_block *sb)
          {
          ...
          int ptr; /* line 1 added */
          jFYI(1, (
          Mount JFS
          ));
          / *
          * read/validate superblock
          * (initialize mount inode from the superblock)
          * /
          if ((rc = chkSuper(sb))) {
          goto errout20;
          }
          108 ptr=0; /* line 2 added */
          109 printk(%d
          ,*ptr); /* line 3 added */[/code:1:627becdd94]
          清單 9 在向文件系統(tǒng)發(fā)出 mount 命令之后顯示一個(gè) gdb 異常。kgdb 提供了幾條命令,如顯示數(shù)據(jù)結(jié)構(gòu)和變量值以及顯示系統(tǒng)中的所有任務(wù)處于什么狀態(tài)、它們駐留在何處、它們在哪些地方使用了 CPU 等等。清單 9 將顯示回溯跟蹤為該問題提供的信息;where 命令用來執(zhí)行反跟蹤,它將告訴被執(zhí)行的調(diào)用在代碼中的什么地方停止。
          清單 9. gdb 異常和反跟蹤

          [code:1:627becdd94]mount -t jfs /dev/sdb /jfs

          Program received signal SIGSEGV, Segmentation fault.
          jfs_mount (sb=0xf78a3800) at jfs_mount.c:109
          109 printk(%d
          ,*ptr);
          (gdb)where
          #0 jfs_mount (sb=0xf78a3800) at jfs_mount.c:109
          #1 0xc01a0dbb in jfs_read_super ... at super.c:280
          #2 0xc0149ff5 in get_sb_bdev ... at super.c:620
          #3 0xc014a89f in do_kern_mount ... at super.c:849
          #4 0xc0160e66 in do_add_mount ... at namespace.c:569
          #5 0xc01610f4 in do_mount ... at namespace.c:683
          #6 0xc01611ea in sys_mount ... at namespace.c:716
          #7 0xc01074a7 in system_call () at af_packet.c:1891
          #8 0x0 in ?? ()
          (gdb)[/code:1:627becdd94]
          下一部分還將討論這個(gè)相同的 JFS 段錯誤問題,但不設(shè)置調(diào)試器,如果您在非 kgdb 內(nèi)核環(huán)境中執(zhí)行清單 8 中的代碼,那么它使用內(nèi)核可能生成的 Oops 消息。
          [color=darkblue:627becdd94]Oops 分析[/color:627becdd94]
          Oops(也稱 panic,慌張)消息包含系統(tǒng)錯誤的細(xì)節(jié),如 CPU 寄存器的內(nèi)容。在 Linux 中,調(diào)試系統(tǒng)崩潰的傳統(tǒng)方法是分析在發(fā)生崩潰時(shí)發(fā)送到系統(tǒng)控制臺的 Oops 消息。一旦您掌握了細(xì)節(jié),就可以將消息發(fā)送到 ksymoops 實(shí)用程序,它將試圖將代碼轉(zhuǎn)換為指令并將堆棧值映射到內(nèi)核符號。在很多情況下,這些信息就足夠您確定錯誤的可能原因是什么了。請注意,Oops 消息并不包括核心文件。
          讓我們假設(shè)系統(tǒng)剛剛創(chuàng)建了一條 Oops 消息。作為編寫代碼的人,您希望解決問題并確定什么導(dǎo)致了 Oops 消息的產(chǎn)生,或者您希望向顯示了 Oops 消息的代碼的開發(fā)者提供有關(guān)您的問題的大部分信息,從而及時(shí)地解決問題。Oops 消息是等式的一部分,但如果不通過 ksymoops 程序運(yùn)行它也于事無補(bǔ)。下面的圖顯示了格式化 Oops 消息的過程。
          [color=darkblue:627becdd94]格式化 Oops 消息[/color:627becdd94]見附圖

          ksymoops 需要幾項(xiàng)內(nèi)容:Oops 消息輸出、來自正在運(yùn)行的內(nèi)核的 System.map 文件,還有 /proc/ksyms、 vmlinux 和 /proc/modules。關(guān)于如何使用 ksymoops,內(nèi)核源代碼 /usr/src/linux/Documentation/oops-tracing.txt 中或 ksymoops 手冊頁上有完整的說明可以參考。Ksymoops 反匯編代碼部分,指出發(fā)生錯誤的指令,并顯示一個(gè)跟蹤部分表明代碼如何被調(diào)用。
          首先,將 Oops 消息保存在一個(gè)文件中以便通過 ksymoops 實(shí)用程序運(yùn)行它。清單 10 顯示了由安裝 JFS 文件系統(tǒng)的 mount 命令創(chuàng)建的 Oops 消息,問題是由清單 8 中添加到 JFS 安裝代碼的那三行代碼產(chǎn)生的。
          清單 10. ksymoops 處理后的 Oops 消息

          [code:1:627becdd94]ksymoops 2.4.0 on i686 2.4.17. Options used
          ... 15:59:37 sfb1 kernel: Unable to handle kernel NULL pointer dereference at
          virtual address 0000000
          ... 15:59:37 sfb1 kernel: c01588fc
          ... 15:59:37 sfb1 kernel: *pde = 0000000
          ... 15:59:37 sfb1 kernel: Oops: 0000
          ... 15:59:37 sfb1 kernel: CPU: 0
          ... 15:59:37 sfb1 kernel: EIP: 0010:[jfs_mount+60/704]

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

          >>EIP; c01588fc jfs_mount+3c/2c0> =====
          ...
          Trace; c0106cf3 system_call+33/40>
          Code; c01588fc jfs_mount+3c/2c0>
          00000000 _EIP>:
          Code; c01588fc jfs_mount+3c/2c0> =====
          0: 8b 2d 00 00 00 00 mov 0x0,%ebp =====
          Code; c0158902 jfs_mount+42/2c0>
          6: 55 push %ebp[/code:1:627becdd94]
          接下來,您要確定 jfs_mount 中的哪一行代碼引起了這個(gè)問題。Oops 消息告訴我們問題是由位于偏移地址 3c 的指令引起的。做這件事的辦法之一是對 jfs_mount.o 文件使用 objdump 實(shí)用程序,然后查看偏移地址 3c。Objdump 用來反匯編模塊函數(shù),看看您的 C 源代碼會產(chǎn)生什么匯編指令。清單 11 顯示了使用 objdump 后您將看到的內(nèi)容,接著,我們查看 jfs_mount 的 C 代碼,可以看到空值是第 109 行引起的。偏移地址 3c 之所以很重要,是因?yàn)?Oops 消息將該處標(biāo)識為引起問題的位置。
          清單 11. jfs_mount 的匯編程序清單

          [code:1:627becdd94]109 printk(%d
          ,*ptr);

          objdump jfs_mount.o

          jfs_mount.o: file format elf32-i386

          Disassembly of section .text:

          00000000 jfs_mount>:
          0:55 push %ebp
          ...
          2c: e8 cf 03 00 00 call 400 chkSuper>
          31: 89 c3 mov %eax,%ebx
          33: 58 pop %eax
          34: 85 db test %ebx,%ebx
          36: 0f 85 55 02 00 00 jne 291 jfs_mount+0x291>
          3c: 8b 2d 00 00 00 00 mov 0x0,%ebp problem line above
          42: 55 push %ebp[/code:1:627becdd94]
          [color=darkblue:627becdd94]kdb[/color:627becdd94]
          Linux 內(nèi)核調(diào)試器(Linux kernel debugger,kdb)是 Linux 內(nèi)核的補(bǔ)丁,它提供了一種在系統(tǒng)能運(yùn)行時(shí)對內(nèi)核內(nèi)存和數(shù)據(jù)結(jié)構(gòu)進(jìn)行檢查的辦法。請注意,kdb 不需要兩臺機(jī)器,不過它也不允許您像 kgdb 那樣進(jìn)行源代碼級別上的調(diào)試。您可以添加額外的命令,給出該數(shù)據(jù)結(jié)構(gòu)的標(biāo)識或地址,這些命令便可以格式化和顯示基本的系統(tǒng)數(shù)據(jù)結(jié)構(gòu)。目前的命令集允許您控制包括以下操作在內(nèi)的內(nèi)核操作:
          ?處理器單步執(zhí)行
          ?執(zhí)行到某條特定指令時(shí)停止
          ?當(dāng)存?。ɑ蛐薷模┠硞€(gè)特定的虛擬內(nèi)存位置時(shí)停止
          ?當(dāng)存取輸入/輸出地址空間中的寄存器時(shí)停止
          ?對當(dāng)前活動的任務(wù)和所有其它任務(wù)進(jìn)行堆?;厮莞櫍ㄍㄟ^進(jìn)程 ID)
          ?對指令進(jìn)行反匯編
          [color=blue:627becdd94]追擊內(nèi)存溢出[/color:627becdd94]
          您肯定不想陷入類似在幾千次調(diào)用之后發(fā)生分配溢出這樣的情形。
          我們的小組花了許許多多時(shí)間來跟蹤稀奇古怪的內(nèi)存錯誤問題。應(yīng)用程序在我們的開發(fā)工作站上能運(yùn)行,但在新的產(chǎn)品工作站上,這個(gè)應(yīng)用程序在調(diào)用 malloc() 兩百萬次之后就不能運(yùn)行了。真正的問題是在大約一百萬次調(diào)用之后發(fā)生了溢出。新系統(tǒng)之所有存在這個(gè)問題,是因?yàn)楸槐A舻?malloc() 區(qū)域的布局有所不同,從而這些零散內(nèi)存被放置在了不同的地方,在發(fā)生溢出時(shí)破壞了一些不同的內(nèi)容。
          我們用多種不同技術(shù)來解決這個(gè)問題,其中一種是使用調(diào)試器,另一種是在源代碼中添加跟蹤功能。在我職業(yè)生涯的大概也是這個(gè)時(shí)候,我便開始關(guān)注內(nèi)存調(diào)試工具,希望能更快更有效地解決這些類型的問題。在開始一個(gè)新項(xiàng)目時(shí),我最先做的事情之一就是運(yùn)行 MEMWATCH 和 YAMD,看看它們是不是會指出內(nèi)存管理方面的問題。
          內(nèi)存泄漏是應(yīng)用程序中常見的問題,不過您可以使用本文所講述的工具來解決這些問題。


          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();