[panic] 一个kernel panic错误分析的例子

1.首先从log分析,可以看到最后挂在mdrv_HDMI_GetSourceSelect + 0x8c处。

<4>[ 5022.810137] [<ffffff8000ffcd74>] mdrv_HDMI_GetSourceSelect+0x8c/0x118 [utpa2k]

<4>[ 5022.810877] [<ffffff8000f7eae8>] HDMIRxIoctl+0x650/0xa78 [utpa2k]

<4>[ 5022.811552] [<ffffff8000e7ff14>] UtopiaIoctl+0x3c/0xb0 [utpa2k]

<4>[ 5022.812276] [<ffffff8000ff92a4>] MDrv_HDMI_GetTimingInfo+0x54/0x1c0 [utpa2k]

<4>[ 5022.812949] [<ffffff8000fb1b78>] MApi_XC_PCMonitor_U2+0xc30/0x17b0 [utpa2k]

<4>[ 5022.813577] [<ffffff8000f9e1cc>] _PCMONITORIoctl+0x174/0x22d0 [utpa2k]

<4>[ 5022.814171] [<ffffff8000fab4b0>] XCIoctl+0xc8/0xe28 [utpa2k]

<4>[ 5022.814650] [<ffffff8000e7ff14>] UtopiaIoctl+0x3c/0xb0 [utpa2k]

<4>[ 5022.815160] [<ffffff8000f8908c>] MApi_XC_PCMonitor_EX+0x64/0xf8 [utpa2k]

<4>[ 5022.815181] [<ffffff8002778d6c>] MI_DISP_IMPL_XC_InitDisplayOut+0x46c/0x818 [xcker]

<4>[ 5022.815642] [<ffffff8000e879d4>] MsOS_MPool_Remove_PA2VARange+0x14c/0x4a0 [utpa2k]

<4>[ 5022.815653] [<ffffff80080ee0f4>] kthread+0xec/0x100

<4>[ 5022.815660] [<ffffff8008084910>] ret_from_fork+0x10/0x40

2.因为panic位置是utp2k.ko,所以对应code在utopia中。进入utopia目录,找到函数mdrv_HDMI_GetSourceSelect在mdrv_hdmi.c中。

3.找到mdrv_hdmi.o,对其进行反汇编:/mtkeda/dtv/msttools/arm/Linaro/gcc-linaro-4.9/2014.11-x86_64_aarch64-elf/bin/aarch64-none-elf-objdump –D –S ./modules/xc/drv/xc/mdrv_hdmi.o > mdrv_hdmi.asm。

4.在mdrv_hdmi.asm中找到mdrv_HDMI_GetSourceSelect + 0x8c.

 

 

可以看到异常位置对应c code中的

 

5.分析错误原因。

a. panic时,寄存器信息如下:

<4>[ 5022.807976] pc : [<ffffff8000ffcd74>] lr : [<ffffff8000ffcd60>] pstate: 20000145

<4>[ 5022.807978] sp : ffffffc040a1b9c0

<4>[ 5022.807982] x29: ffffffc040a1b9c0 x28: 0000000000000001

<4>[ 5022.807989] x27: 0000000000000000 x26: 0000000000000000

<4>[ 5022.807994] x25: 0000000000000002 x24: 0000000000000002

<4>[ 5022.808000] x23: ffffffc040a1bb60 x22: 000000000000001f

<4>[ 5022.808006] x21: 00000000000000b0 x20: ffffff8008fac688

<4>[ 5022.808011] x19: ffffff800c6d5180 x18: 0000000000000000

<4>[ 5022.808017] x17: 0000000000000000 x16: 0000000000000000

<4>[ 5022.808022] x15: 000000007ffff000 x14: 0000007fffffffff

<4>[ 5022.808028] x13: ffffffc0452b1000 x12: 0000000000000000

<4>[ 5022.808034] x11: ffffff8008fbc000 x10: 00000000000008a0

<4>[ 5022.808039] x9 : ffffffc040a1bb40 x8 : ffffffc040a1bbd0

<4>[ 5022.808045] x7 : 0000000000000000 x6 : ffffffc040a1b910

<4>[ 5022.808051] x5 : ffffffc073633090 x4 : 0000000000000000

<4>[ 5022.808056] x3 : ffffff8008122df8 x2 : ffffff800c6d2000

<4>[ 5022.808062] x1 : 00000000000000b0 x0 : 00000000000000b0

b. panic时,执行的指令为:

 

madd为汇编的乘和运算,xd = xn1 * xn2 + xn3;

因此有:

x1 = 0xb0;

x2 = ffffff800c6d2000;

x19 = 0x48;

x19 = x1 * x19 + x2 = 0xb0 * 0x48 + ffffff800c6d2000;

c. 对*(x19 + 455) = *w0时出错,因此可能是x19地址不合法。而x19不合法则可能是上面的计算出现异常。

对照C语言和汇编可以看到。

 

X19=0x48表示stHDMIPollingInfo的机构提大小,而x1=0xb0表示HDMI_GET_PORT_SELECT(enInputPortType)的计算结果,x2=ffffff800c6d2000表示pHDMIRxResourcePrivate的起始地址,#455表示ucHDMIInfoSource的offset。

在上面计算中,仅0xb0是可变项,也是传入参数转换而来,因此可能是0xb0溢出。

d. HDMI_GET_PORT_SELECT的定义如下:

 

其中INPUT_PORT_DIV0=80,因此a = 80 + 0xb0 = 256, a在汇编中为x1, x1的取值为uxtb w1, w19,所以a为uchar类型,而uchar类型的256即是0,做a-INPUT_PORT_DVI0的目的是为了得到0~3 4个input DVI source,因为stHDMIPollingInfo只有4组数据。

 

因此HDMI_GET_PORT_SELECT(enInputPortType)的值只能为0,1,2,3。

 

0xb0的结果会使程序越界读取数据,因此会出现内存越界的错误,需要检查输入值不是80~83的原因。

原文地址:https://www.cnblogs.com/smilingsusu/p/12703082.html