ARM Linux內(nèi)核驅(qū)動(dòng)異常定位方法分析反匯編方式
==================================================================================================================
本文引用地址:http://m.butianyuan.cn/article/201611/317993.htmUnable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 17 [#1]
last sysfs file: /sys/devices/virtual/vc/vcsa1/dev
Modules linked in:
CPU: 0 Not tainted (2.6.39 #1)
PC is at atmel_tasklet_func+0x110/0x69c
LR is at atmel_tasklet_func+0x10/0x69c
pc : [
sp : c7825f50 ip : c045e0bc fp : 00000000
r10: c0456a80 r9 : 0000000a r8 : 00000000
r7 : c7874568 r6 : c045e0a8 r5 : 00000100 r4 : c045dfb4
r3 : 00000002 r2 : 00000ffc r1 : 00000001 r0 : 00000001
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 0005317f Table: 27aec000 DAC: 00000017
Process ksoftirqd/0 (pid: 3, stack limit = 0xc7824270)
Stack: (0xc7825f50 to 0xc7826000)
5f40: 00000100 c7824000 00000001 00000018
5f60: 0000000a c0456a80 c7825f84 00000000 00000100 c7824000 00000001 00000018
5f80: c0456a80 c0047b70 00000006 c0047650 c0432e50 00000000 c7824000 00000000
5fa0: 00000000 c0047938 00000000 00000000 00000000 c00479a0 c7825fd4 c7819f60
5fc0: 00000000 c0058c64 c00335f4 00000000 00000000 00000000 c7825fd8 c7825fd8
5fe0: 00000000 c7819f60 c0058be0 c00335f4 00000013 c00335f4 0c200050 fc3b9beb
[
[
[
[
[
Code: 1a000002 e59f057c e59f157c ebfa416c (e5983000)
---[ end trace 6b8e1841ba3a56c9 ]---
Kernel panic - not syncing: Fatal exception in interrupt
[
[
[
[
[
[
Exception stack(0xc7825f08 to 0xc7825f50)
5f00: 00000001 00000001 00000ffc 00000002 c045dfb4 00000100
5f20: c045e0a8 c7874568 00000000 0000000a c0456a80 00000000 c045e0bc c7825f50
5f40:c01a4e30 c01a4f3020000013 ffffffff
[
[
[
[
[
[
==================================================================================================================
通常認(rèn)為,產(chǎn)生異常的地址是lr寄存器的值,從上面的異常信息可以看到[lr]的值是c01a4e30。
接下來,我們可以通過內(nèi)核鏡像文件反匯編來找到這個(gè)地址。內(nèi)核編譯完成后,會(huì)在內(nèi)核代碼根目錄下生成vmlinux文件,我們可以通過以下命令來反匯編:
arm-none-eabi-objdump -Dz-Svmlinux >linux.dump
值得注意的是,arm-none-eabi-objdump的參數(shù)-S表示盡可能的把原來的代碼和反匯編出來的代碼一起呈現(xiàn)出來,-S參數(shù)需要結(jié)合arm-linux-gcc編譯參數(shù)-g,才能達(dá)到反匯編時(shí)同時(shí)輸出原來的代碼。所以,我在linux內(nèi)核代碼根目錄的Makefile中增加-g編譯參數(shù):
KBUILD_CFLAGS :=-g-Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
-fno-strict-aliasing -fno-common
-Werror-implicit-function-declaration
-Wno-format-security
-fno-delete-null-pointer-checks
修改Makefile后,重新編譯內(nèi)核,在根目錄中生成的vmlinux文件就會(huì)包含了原來的代碼信息,因此,該文件的大小也比原來大一倍!
最后執(zhí)行“arm-none-eabi-objdump -Dz-Svmlinux >linux.dump”,由于加入了-g編譯參數(shù),執(zhí)行這個(gè)反匯編命令需要很長時(shí)間(本人在虛擬機(jī)上執(zhí)行,花了近6個(gè)小時(shí)?。磪R編出來的linux.dump文件也比原來的44MB增大到驚人的503MB。
接下來可以用UltraEdit打開linux.dump文件,查找“c01a4e30”字符串。
最后定位到的信息是:
==================================================================================================================
/*
* tasklet handling tty stuff outside the interrupt handler.
*/
static void atmel_tasklet_func(unsigned long data)
{
c01a4e20:e92d45f0 push{r4, r5, r6, r7, r8, sl, lr}
c01a4e24:e24dd01c subsp, sp, #28; 0x1c
c01a4e28:e1a04000 movr4, r0
/* The interrupt handler does not take the lock */
spin_lock(&port->lock);
if (atmel_use_pdc_tx(port))
atmel_tx_pdc(port);
else if (atmel_use_dma_tx(port))
c01a4e2c:ebfffda1 blc01a44b8
c01a4e30:e3500000 cmpr0, #0; 0x0
c01a4e34:e5943034 ldrr3, [r4, #52]
c01a4e38:0a00007b beqc01a502c
==================================================================================================================
可以看出來,異常的產(chǎn)生位于atmel_tasklet_func函數(shù)的else if (atmel_use_dma_tx(port))一行。
估計(jì)atmel_use_dma_tx(port)的“port”參數(shù)為空指針?biāo)拢?/p>
最后,我把串口的DMA功能去掉,改為直接傳送,這樣做雖然效率低了點(diǎn),但產(chǎn)生異常的現(xiàn)象消失了。
到后面再仔細(xì)分析為什么會(huì)產(chǎn)生這個(gè)異常,徹底解決這個(gè)問題。
評(píng)論