Linux kernel 的一个panic问题定位

如下是一个kernelpanicOops和堆栈信息:

panic info:

 PCis at __run_hrtimer+0x230/0x298

[19816.115957] c0 LR is at__raw_spin_lock+0x2c/0x94

[19816.115968] c0 pc :[<c0064db4>]    lr :[<c0593884>]    psr: 20000193

[19816.115974] c0 sp : caa3dbe8  ip : caa3dbc0 fp : caa3dc1c

[19816.115983] c0 r10: c0080e44  r9 : c0f14a00 r8 : 00000001

[19816.115992] c0 r7 : 00000002  r6 : c0f14a00 r5 : c0f14aa8  r4 : c093c4b0

[19816.116002] c0 r3 : 00000003  r2 : 00000103 r1 : 00000000  r0 : 00000001

[19816.116013] c0 Flags: nzCv  IRQs off FIQs on  Mode SVC_32  ISA ARM Segment user

[19816.116023] c0 Control: 10c53c7d  Table: 9aa0006a  DAC: 00000015

....................

.......................

.........................

[19816.118270] c0 [<c0064db4>](__run_hrtimer+0x230/0x298) from [<c00659f0>](hrtimer_interrupt+0x120/0x248)

[19816.118289] c0 [<c00659f0>](hrtimer_interrupt+0x120/0x248) from [<c0065b64>] (__hrtimer_peek_ahead_timers.part.9+0x4c/0x58)

[19816.118308] c0 [<c0065b64>](__hrtimer_peek_ahead_timers.part.9+0x4c/0x58) from [<c0065bbc>](hrtimer_peek_ahead_timers+0x4c/0x74)

[19816.118327] c0 [<c0065bbc>](hrtimer_peek_ahead_timers+0x4c/0x74) from [<c0065bfc>](run_hrtimer_softirq+0x18/0x1c)

[19816.118346] c0 [<c0065bfc>](run_hrtimer_softirq+0x18/0x1c) from [<c004771c>](__do_softirq+0x150/0x29c)

[19816.118364] c0 [<c004771c>](__do_softirq+0x150/0x29c) from [<c0047d68>] (irq_exit+0x64/0xac)

[19816.118383] c0 [<c0047d68>](irq_exit+0x64/0xac) from [<c0010234>] (handle_IRQ+0x8c/0xc8)

[19816.118401] c0 [<c0010234>](handle_IRQ+0x8c/0xc8) from [<c00093a8>] (gic_handle_irq+0xd8/0x188)

[19816.118420] c0 [<c00093a8>](gic_handle_irq+0xd8/0x188) from [<c000f3c4>] (__irq_svc+0x44/0x78)

[19816.118431] c0 Exceptionstack(0xcaa3dd50 to 0xcaa3dd98)

[19816.118442] c0 dd40:                                     d8bc2f2c60000013 00000000 c08c2cec

[19816.118457] c0 dd60: 60000013 6000001300000001 00000001 00000000 d4421c00 cccc8b00 caa3ddac

[19816.118471] c0 dd80: caa3dd98 caa3dd98c0593590 c0593594 60000013 ffffffff

[19816.118489] c0 [<c000f3c4>](__irq_svc+0x44/0x78) from [<c0593594>](_raw_spin_unlock_irqrestore+0x48/0x70)

[19816.118510] c0 [<c0593594>](_raw_spin_unlock_irqrestore+0x48/0x70) from [<c006a0f0>](__wake_up+0x54/0x5c)

[19816.118532] c0 [<c006a0f0>](__wake_up+0x54/0x5c) from [<c03e4fd0>](binder_thread_write+0x21c0/0x2488)

[19816.118552] c0 [<c03e4fd0>](binder_thread_write+0x21c0/0x2488) from [<c03e65c4>](binder_ioctl+0x38c/0x998)

[19816.118571] c0 [<c03e65c4>](binder_ioctl+0x38c/0x998) from [<c011694c>] (do_vfs_ioctl+0x4f4/0x568)

[19816.118590] c0 [<c011694c>](do_vfs_ioctl+0x4f4/0x568) from [<c0116a08>] (sys_ioctl+0x48/0x6c)

[19816.118608] c0 [<c0116a08>](sys_ioctl+0x48/0x6c) from [<c000f840>] (ret_fast_syscall+0x0/0x48)

 

对于这个问题,现在的分析已经到了怎么来定位问题,整个过程大概如下:

从函数__run_hrtimer反汇编中(下面只贴了三行汇编语句,事实上分析的话,要把整个函数的反汇编都要分析一遍。)

0xc0064dac <__run_hrtimer+552>:cmp     r3, #2

0xc0064db0 <__run_hrtimer+556>: beq     0xc0064db8 <__run_hrtimer+564>

0xc0064db4 <__run_hrtimer+560>:                 ; <UNDEFINED>instruction: 0xe7f001f2

这里面的r3是跟立即数2比较也就是对应代码的BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);中的HRTIMER_STATE_CALLBACK比较,这个宏定义就是0x2,但现在的r3Oops里面的值是0x3(事实上我们怎么定位到刚才的BUG_ON这行语句的,首先Oops里面有kernel BUGat/home/raoli/work/8830_branch/20140305_2227_P8360_DZTX_eng/MocorDroid_4.1.3_sc8830/idh.code/kernel/kernel/hrtimer.c:1228!语句,其次可以用gdb命令:b *PC指针的地址进行定位,最后就是分析汇编进行最后的定位确认)

[19816.115992] c0 r7 : 00000002  r6 : c0f14a00 r5 : c0f14aa8  r4 : c093c4b0

[19816.116002] c0 r3 : 00000003  r2 : 00000103 r1 : 00000000  r0 : 00000001

从这里推断出timer->state=0x3的。

 

再分析分析反汇编这个函数的参数1也就是刚压栈的时候的r0其实一直保存在r4中,也就是地址c093c4b0中,从crash工具的命令:struct hrtimer c093c4b0,可以将结构体进行还原如下而且其state = 3,这跟前面的推断是一至的,这点也证明了这个结构体是正确的,

struct hrtimer {

 node = {

   node = {

     rb_parent_color = 3232271248,

     rb_right = 0x0,

     rb_left = 0x0

   },

   expires = {

     tv64 = 20494574000000

    }

  },

 _softexpires = {

   tv64 = 20494574000000

  },

  function = 0xc0080e44 <alarmtimer_fired>,

 base = 0xc0f14aa8,

  state = 3

}

这个结构体的作用是什么呢?最主要的是 function = 0xc0080e44 <alarmtimer_fired>,这个才是这个问题的关键和重点,也就是说__run_hrtimer函数出现panic的时候,里面的回调函数是alarmtimer_fired,这样这个问题点已经找到了,是linux内核本身的问题,是3.4.5的版本,本来前面还曾怀疑过我们自己所使用的hrtimer,我们的震动确实使用了hrtimer,但他的返回值不满足发生panicif语句,所以被排除了,最后也通过客观条件定位到alarmtimer_fired函数。

 

现在再来讨论这个alarmtimer_fired,这个是在kernel/kernel/time/alarmtimer.c中,这个文件的代码从3.1开始就疯狂的升级,3.1之前,这个文件只叫做alarm.c,稍微看来下几个版本,里面的内容都有变化,像我们公司最新的内核版本3.10的这个文件里面的内容跟客户使用的3.4的版本的差别非常大,去kernel论坛搜索了下,这个模块的patch倒是挺多,但针对我们这个问题的patch还真没有。

 

说了这么多大家可能会感觉哪里是不是有点不对,就说这个问题为什么会产生呢?大家可以去看下客户版本内核下alarmtimer_fired函数,这个函数非常的诡异,里面有两对关中断的自旋锁,但中间有一行是执行一个函数却没有用关中断的自旋锁包起来,而从堆栈信息可以看出,这个就是因为中断来了然后引起了这个问题。

 

 

这里没有分析解决方案,由于时间有限,而且是linux内核的本身的问题,短时间内无法解决,事实上这个模块也不停的进行了升级,解决这个问题的最好方法肯怕是内核升级。

你可能感兴趣的:(Linux kernel 的一个panic问题定位)