|
6.4 必修實(shí)驗(yàn)3--內(nèi)核異常分析(3) 接下來(lái)的這些信息,和這個(gè)模塊的調(diào)試沒(méi)多大關(guān)系,它們是虛擬內(nèi)存頁(yè)目錄、頁(yè)表信息、oops錯(cuò)誤號(hào)以及最后訪問(wèn)的sysfs文件等。 - pgd = c39d8000
- [00000000] *pgd=339cf031, *pte=00000000, *ppte=00000000
- Internal error: Oops: 817 [#1]
- last sysfs file: /sys/devices/platform/soc-audio/sound/card0/mixer/dev
- Modules linked in: oops(+)
再接下來(lái)是寄存器信息,這部分信息比較重要,其中最可能幫助定位錯(cuò)誤的寄存器當(dāng)然是PC。在這部分信息中,下面這句最為關(guān)鍵。 - PC is at func_D+0x1c/0x28 [oops]
它直接地告訴了我們,oops出錯(cuò)時(shí),PC是位于func_D函數(shù)標(biāo)號(hào)之后的0x1c處(怎么去尋找它?后面會(huì)進(jìn)行分析。另外請(qǐng)思考后面的0x28代表什么?)。 寄存器信息之后是棧信息,但這里還用不上,先略過(guò)。 最后的部分,也就是Backtrace標(biāo)號(hào)開(kāi)始的地方,它是oops的精華。它表示回溯信息,也告訴調(diào)試者在oops出錯(cuò)之前,模塊調(diào)用了那些函數(shù)。當(dāng)然,在本實(shí)例中,可以看到模塊調(diào)用了func_D后就出錯(cuò)了,顯然錯(cuò)誤就在func_D中了。 結(jié)尾部分還有一點(diǎn)信息請(qǐng)注意。
- Code: e59f0010 eb412fb6 e3a0200b e3a03000 (e5832000)
Code標(biāo)號(hào)開(kāi)始的字段記錄了模塊出錯(cuò)前最后幾條機(jī)器碼,其中被括號(hào)括起來(lái)的就是oops出錯(cuò)對(duì)應(yīng)的機(jī)器碼。 (4)根據(jù)上面的分析,可以使用反匯編來(lái)確定出錯(cuò)的位置。在RHEL5中,使用命令:arm-linux-objdump -D -S oops.ko >log,將模塊文件反匯編到log中,使用vim打開(kāi)該文件log,直接找到func_D標(biāo)號(hào)處,如圖6-17所示。
| | (點(diǎn)擊查看大圖)圖6-17 反匯編結(jié)果 |
根據(jù)前面的信息,出錯(cuò)位置應(yīng)該在func_D+0x1c處,func_D在0x1c,所以出錯(cuò)地址應(yīng)該是0x38。看看這句匯編代碼,前面的語(yǔ)句將寄存器r3賦值為0,然后這句又試圖將寄存器r2的值存入到r3指向的地址處,也就是向0地址寫(xiě)。因此出錯(cuò)。再來(lái)看看這句出錯(cuò)代碼對(duì)應(yīng)的機(jī)器碼e5832000,顯然就是之前在opps的Code字段中看到的被括起來(lái)的那個(gè)。 (5)通過(guò)反匯編程序,定位了匯編代碼中的錯(cuò)誤位置,但對(duì)于用C語(yǔ)言編寫(xiě)的內(nèi)核模塊而言,這樣還不夠。如何才能準(zhǔn)確地定位到C語(yǔ)言中的語(yǔ)句呢?回憶一下在<<Linux應(yīng)用程序開(kāi)發(fā)班>>中學(xué)習(xí)gdb調(diào)試時(shí),能夠在調(diào)試中看到對(duì)應(yīng)的源碼。當(dāng)時(shí)為了進(jìn)行g(shù)db調(diào)試,在編譯時(shí)加入了-g選項(xiàng),這樣可以將調(diào)試信息加入到目標(biāo)文件中。由此得到靈感,在這里也加入-g試試。進(jìn)入實(shí)驗(yàn)代碼目錄2-3-1中的內(nèi)核源碼目錄,修改其頂層Makefile,如圖6-18所示。 | | (點(diǎn)擊查看大圖)圖6-18 內(nèi)核調(diào)試信息開(kāi)關(guān) |
提示 可見(jiàn)編譯模塊時(shí)加入調(diào)試信息,需要定義CONFIG_DEBUG_INFO這個(gè)宏,由于它默認(rèn)是關(guān)閉的,所以內(nèi)核并沒(méi)有啟用-g選項(xiàng),可以暫時(shí)把這個(gè)宏開(kāi)關(guān)注釋掉,使KBUILD_CFLAGS標(biāo)識(shí)擁有-g選項(xiàng)。 (6)修改內(nèi)核Makefile后,再次編譯模塊。然后將新得到的oops.ko反匯編,使用命令:arm-linux-objdump -D -S oops.ko >log。用vim打開(kāi)log文件。這時(shí),通過(guò)匯編混合C語(yǔ)言調(diào)試信息的結(jié)果,結(jié)合前面的分析,可以很輕松的定位到C語(yǔ)言的錯(cuò)誤語(yǔ)句就出現(xiàn)在"*p = a + 5"處,如圖6-19所示。
| | (點(diǎn)擊查看大圖)圖6-19 定位出錯(cuò)的C語(yǔ)言語(yǔ)句 |
5.總結(jié) 通過(guò)本節(jié)實(shí)驗(yàn),可以學(xué)會(huì)oops信息的分析方法,掌握利用oops信息調(diào)試內(nèi)核模塊的基本方法。下面列出利用oops定位出錯(cuò)點(diǎn)的基本步驟。 (1)oops出錯(cuò)時(shí),首先搜集到所有oops打印信息,如果模塊中本身有很多printk打印語(yǔ)句,首先根據(jù)oops開(kāi)頭的打印信息分析出錯(cuò)點(diǎn)的大概位置。 (2)通過(guò)Backtrace字段,分析發(fā)生oops錯(cuò)誤前模塊程序的執(zhí)行路徑,將范圍縮小到某個(gè)函數(shù)中。 (3)如果通過(guò)前面兩步仍無(wú)法定位出錯(cuò)點(diǎn),那么就直接通過(guò)PC來(lái)定位。查看出錯(cuò)時(shí) oops信息中打印出的PC的值并記錄下來(lái)。在內(nèi)核Makefile中加入-g選項(xiàng),重新編譯模塊。 (4)通過(guò)objdump反匯編該模塊。在反匯編得出的匯編混合C語(yǔ)言調(diào)試信息的代碼中,結(jié)合前3步的分析結(jié)論,精確定位出錯(cuò)點(diǎn)的位置。
|