您的位置:首页 > 其它

通过gdb定位内核宕机

2013-09-30 10:40 323 查看
内核宕机不要panic,我们有gdb,通过dump出来信息可以快速定位出出错的地方。下面就以一个实际遇到的例子描述一下怎么通过gdb找到实际出错的代码行。

Unable to handle kernel paging request for data at address 0x000001d0

Faulting instruction address: 0xc0220820

Oops: Kernel access of bad area, sig: 11 [#1]

MPC85xx CDS

Modules linked in: hsl linux_bcm_diag_full(P) linux_uk_proxy(P) linux_kernel_bde(P) wdtDrv pciDrv i2cDrv flashDrv cpuDrv

NIP: c0220820 LR: c0220818 CTR: c02209a4

REGS: dde67b20 TRAP: 0300 Tainted: P (2.6.27.21)

MSR: 00029000 <EE,ME> CR: 24000824 XER: 00000000

DEAR: 000001d0, ESR: 00000000

TASK = decea500[940] 'nsm' THREAD: dde66000

GPR00: 00000001 dde67bd0 decea500 00000001 00000001 decea538 00000078 00000000

GPR08: deceae80 00000000 83d0da00 c02209a4 e8669fbb 10219d44 00000290 ffffffff

GPR16: 00000001 00000000 100d4464 100e7db4 00000000 00000008 dde67ddc dde67dfc

GPR24: dde67ddc dde67dfc dde67dc0 e3970000 00000001 00000000 ddac8018 00000000

NIP [c0220820] rollback_registered+0x2c/0x130

LR [c0220818] rollback_registered+0x24/0x130

Call Trace:

[dde67bd0] [00000008] 0x8 (unreliable)

[dde67be0] [c022094c] unregister_netdevice+0x28/0x80

[dde67bf0] [c02209c4] unregister_netdev+0x20/0x38

[dde67c10] [e393661c] hsl_eth_drv_destroy_netdevice+0x10/0x24 [hsl]

[dde67c20] [e3938490] hsl_os_l3_if_unconfigure+0x20/0x34 [hsl]

[dde67c30] [e393aa94] hsl_ifmgr_L3_delete2+0xf0/0x2b4 [hsl]

[dde67c50] [e394103c] hsl_ifmgr_L3_unregister+0x60/0xfc [hsl]

[dde67c70] [e3926004] hsl_msg_recv_if_delete_svi+0x54/0x15c [hsl]

[dde67c90] [e391feb8] hsl_sock_process_msg+0x260/0x7a8 [hsl]

[dde67ca0] [e392046c] _hsl_sock_sendmsg+0x6c/0xac [hsl]

[dde67cc0] [c0211fc0] sock_sendmsg+0xac/0xe4

[dde67db0] [c02121cc] sys_sendmsg+0x1d4/0x284

[dde67f00] [c0212d40] sys_socketcall+0xe8/0x200

[dde67f40] [c000df5c] ret_from_syscall+0x0/0x3c

Instruction dump:

4bffff48 9421fff0 7c0802a6 3d20c039 93e1000c 7c7f1b78 90010014 800954d8

0f000000 4800a101 2f830000 419e00e4 <813f01d0> 2f890000 409e0034 3c60c033

---[ end trace fc1818f8d9535ae2 ]---

首先介绍一下ppc(powerpc)的寄存器:

通用寄存器:

  r0   在函数开始(function prologs)时使用。

  r1   堆栈指针,相当于ia32架构中的esp寄存器,idapro把这个寄存器反汇编标识为sp。

  r2   内容表(toc)指针,idapro把这个寄存器反汇编标识为rtoc。系统调用时,它包含系统调用号。

  r3   作为第一个参数和返回地址。

  r4-r10 函数或系统调用开始的参数。

  r11   用在指针的调用和当作一些语言的环境指针。

  r12   它用在异常处理和glink(动态连接器)代码。

  r13   保留作为系统线程ID。

  r14-r31 作为本地变量,非易失性。

专用寄存器:

  lr   链接寄存器,它用来存放函数调用结束处的返回地址。

  ctr   计数寄存器,它用来当作循环计数器,会随特定转移操作而递减。

  xer   定点异常寄存器,存放整数运算操作的进位以及溢出信息。

  msr   机器状态寄存器,用来配置微处理器的设定。

  cr   条件寄存器,它分成8个4位字段,cr0-cr7,它反映了某个算法操作的结果并且提供条件分支的机制。

  寄存器r1、r14-r31是非易失性的,这意味着它们的值在函数调用过程保持不变。寄存器r2也算非易失性,但是只有在调用函数在调用后必须恢复它的值时才被处理。

ppc使用了LR寄存器(Link Register)来完成:在bl指令跳转前,下条指令的地址会被保存到LR,函数返回时候调用 blr,系统会跳转到LR所表示的地址,完成返回。

------------------------------分割线--------------------------------------------------

我们开始通过gdb查找宕机的地方:

1. 首先进入内核的编译目录,保证代码与出错的内核一直,没有编译的话要先编译,编译完之后,在当前目录就会有vmlinux,这个是未压缩过的内核bin文件,用gdb运行它(这里是powerpc平台):

gdb4ppc ./vmlinux

2. NIP显示的下一条指令地址(0xc0220820),使用list 指令显示出对应的函数:

(gdb) list *0xc0220820

0xc0220820 is in rollback_registered (net/core/dev.c:4051).

4046 {

4047 BUG_ON(dev_boot_phase);

4048 ASSERT_RTNL();

4049

4050 /* Some devices call without registering for initialization unwind. */

4051 if (dev->reg_state == NETREG_UNINITIALIZED) {

4052 printk(KERN_DEBUG "unregister_netdevice: device %s/%p never "

4053 "was registered\n", dev->name, dev);

4054

4055 WARN_ON(1);

3. 反汇编这个函数 (disassemble /r表示原始的16进制格式的汇编)

(gdb) disassemble /r rollback_registered

Dump of assembler code for function rollback_registered:

0xc02207f4 <+0>: 94 21 ff f0 stwu r1,-16(r1)

0xc02207f8 <+4>: 7c 08 02 a6 mflr r0

0xc02207fc <+8>: 3d 20 c0 39 lis r9,-16327

0xc0220800 <+12>: 93 e1 00 0c stw r31,12(r1)

0xc0220804 <+16>: 7c 7f 1b 78 mr r31,r3

0xc0220808 <+20>: 90 01 00 14 stw r0,20(r1)

0xc022080c <+24>: 80 09 54 d8 lwz r0,21720(r9)

0xc0220810 <+28>: 0f 00 00 00 twnei r0,0

0xc0220814 <+32>: 48 00 a1 01 bl 0xc022a914 <rtnl_is_locked>

0xc0220818 <+36>: 2f 83 00 00 cmpwi cr7,r3,0

0xc022081c <+40>: 41 9e 00 e4 beq cr7,0xc0220900 <rollback_registered+268>

0xc0220820 <+44>: 81 3f 01 d0 lwz r9,464(r31)

0xc0220824 <+48>: 2f 89 00 00 cmpwi cr7,r9,0

0xc0220828 <+52>: 40 9e 00 34 bne cr7,0xc022085c <rollback_registered+104>

可以看到汇编与dump信息里面的Instruction dump完全对得上,地址0xc022082

对应汇编 81 3f 01 d0, dump信息里面特意用尖括号标识出来了,看来就死在这一条指令了。

4. 找到对应的代码行(disassemble /m 将源码嵌入到汇编里面),分析原因。

(gdb) disassemble /m rollback_registered

Dump of assembler code for function rollback_registered:

4046 {

0xc02207f4 <+0>: stwu r1,-16(r1)

0xc02207f8 <+4>: mflr r0

0xc0220800 <+12>: stw r31,12(r1)

0xc0220804 <+16>: mr r31,r3

0xc0220808 <+20>: stw r0,20(r1)

4047 BUG_ON(dev_boot_phase);

0xc02207fc <+8>: lis r9,-16327

0xc022080c <+24>: lwz r0,21720(r9)

0xc0220810 <+28>: twnei r0,0

4048 ASSERT_RTNL();

0xc0220814 <+32>: bl 0xc022a914 <rtnl_is_locked>

0xc0220818 <+36>: cmpwi cr7,r3,0

0xc022081c <+40>: beq cr7,0xc0220900 <rollback_registered+268>

0xc0220900 <+268>: lis r4,-16333

0xc0220904 <+272>: lis r3,-16334

0xc0220908 <+276>: addi r4,r4,-16240

0xc022090c <+280>: li r5,4048

0xc0220910 <+284>: addi r3,r3,-3816

0xc0220914 <+288>: crclr 4*cr1+eq

0xc0220918 <+292>: bl 0xc0027ca0 <printk>

0xc022091c <+296>: bl 0xc0006cfc <dump_stack>

0xc0220920 <+300>: b 0xc0220820 <rollback_registered+44>

4049

4050 /* Some devices call without registering for initialization unwind. */

4051 if (dev->reg_state == NETREG_UNINITIALIZED) {

0xc0220820 <+44>: lwz r9,464(r31)

0xc0220824 <+48>: cmpwi cr7,r9,0

0xc0220828 <+52>: bne cr7,0xc022085c <rollback_registered+104>

这样我们就找到对应的代码语句是 rollback_registered中

if (dev->reg_state == NETREG_UNINITIALIZED) {

这一行,指令是lwz r9,464(r31),R31存放的是dev指针,我们先确认一下偏移464的地方就是

dev->reg_state

(gdb) p &((struct net_device *)0)->reg_state

$1 = (enum {...} *) 0x1d0

0x1d0也就是十进制的464,dump信息里的R31寄存器是0,即dev是NULL,这也就是这条指令导致产生访问非法地址0x000001d0的原因:

Unable to handle kernel paging request for data at address 0x000001d0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: