linux panic 问题定位


1     概述

详细描述出现kernel panic时的处理过程。

from:http://blog.csdn.net/wdq347/article/details/39641551 


2     定位方法

2.1   调用栈

最直接、简单的方法,查看panic时的调用栈,根据打印的出错函数及文件行数,找到panic的位置,再详细处理。

2.2   出错地址

有时候会出现错误的调用栈,此时必须查看出错的指令地址,对于x86架构来说,就是EIP,同时关注调用栈的地址。在调用栈错误时,可以手工将地址转换成出错函数及行数,以下分两个部分介绍:

2.2.1  内核模块

大部分kernel panic都是由于可加载卸载的内核模块导致,此时可以通过如下步骤将地址翻译成具体代码位置。

1.     获取内核模块基地址

查看/proc/modules,找到关注的内核模块的基地址,如下是一个示例

root@miner:~#cat /proc/modules | grep mm

mm           643877 0 - Live 0xd27cf000 (O)

mm_if       1526      1mm, Live 0xd27b8000 (O)

绝大部分情况下,系统在重启后,模块的基地址不会改变。如上图所示,mm模块的地址空间从基地址0xd27cf000开始,大小为643877,如果某个地址落在这个区间,则确定为此模块的地址。

2.     计算地址偏移

将出错的内核地址减去模块基地址,即得到偏移地址。

3.     生成模块可调试文件

确保编译内核时EXTRA_CFLAGS参数添加-g,如此编译后会生成内核模块对应的.o文件(假设为hello.o),使用编译工具链ld(交叉编译时需要使用交叉编译工具链),命令如下:

 ld -r -d -o hello.ko.debug hello.o

4.     gdb调试

gdbhello.ko.debug

假设偏移地址为0xa7d0,则info line*0xa7d0便得到panic时的位置信息。

2.2.2  内核

如果出错地址为内核,则不需要计算偏移地址,直接使用出错地址即可。,使用gdb 调试vmlinux,注意不是vmlinuz,方法基本与内核模块类似


 

3     panic 实例

3.1    代码段卸载

l  现象

insmod 模块报“operation not permitted”,很快出现panic 信息。此问题为与客户联调时现场出现。

l  定位

此问题最终原因是模块初始化时接口返回值混乱导致,实际上此模块已经成功插入到内核,但是因为返回值混乱,导致判断是插入模块失败,因此当前内核模块退出,此内核模块的代码段卸载,但此内核模块注册到内核报文处理过程没有被正确卸载,故在报文收发时因为没有可用的代码段导致panic。

 

3.2    死锁

l  现象

设备在报文有流量的情况下下发配置到内核,会小概率性的出现panic,panic时串口显示“rcu_preempt self-detected stall on CPU”

l  定位

此问题最终原因是内核死锁。有两个过程需要同步,一个是报文收发软中断,另一个是命令下发过程(进程上下文),代码中使用spin_lock 同步。

在命令下发过程中,锁已经获取,但恰好此时有一个软中断到来,打断了命令下发过程,而且在软中断过程中需要获取相同的锁,此锁已经被命令下属过程占住,因此导致死锁。解决方法很简单,在命令下发过程中禁止软中断,即使用spin_lock_bh 同步。

 

3.3    代码段替换

l  现象

短时间内,内核模块卸载再加载后,会随机小概率的出现panic

l  定位

内核模块会在流结构中存储若干内容,包括分配的结点指针等。当内核模块卸载之后,这条流一直存在没有结束;当内核模块两次加载后,这条流又被处理,使用了前一次无效的结点指针,导致panic。

此问题通过“模块引用”计数方案解决,当内核模块卸载再加载后,之前已经处理过的流直接bypass。

 

3.4    使用释放的内存

l  现象

网口down再up之后,小概率的出现panic,出错信息如下:

[plain]  view plain copy
  1. <1>[592005.836736]BUG: unable to handle kernel NULL pointer dereference at 00000001  
  2. <1>[592005.845688]IP: [<f89a6075>] 0xf89a6074  
  3. <4>[592005.846675]*pde = 00000000  
  4. <4>[592005.846675]Oops: 0000 [#1]  
  5. <4>[592005.846675]Modules linked in: algapi [last unloaded: maxnet_dpi_if]  
  6. <4>[592005.846675]  
  7. <4>[592005.846675]Pid: 0, comm: swapper Tainted: G          O 3.3.8 #38 HOLL Technologies        /         
  8. <4>[592005.846675]EIP: 0060:[<f89a6075>] EFLAGS: 00010246 CPU: 0  
  9. <4>[592005.846675]EIP is at 0xf89a6075  
  10. <4>[592005.846675]EAX: c19b6c08 EBX: 00000000 ECX: 00000000 EDX: f59be000  
  11. <4>[592005.846675]ESI: f59be000 EDI: 00000001 EBP: c19b6c10 ESP: f600bbac  
  12. <4>[592005.846675]  DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068  
  13. <0>[592005.846675]Process swapper (pid: 0, ti=f600a000 task=c14264c0 task.ti=c141e000)  
  14. <0>[592005.846675]Stack:  
  15. <4>[592005.846675]  00000000 fffffffe 00000000 c19b7600 c12b775dc1a9fb30 b554c74e 00000869  
  16. <4>[592005.846675]  c1a9fc30 c1a9f8c0 c1a9f800 00000000 0386df19c1a9f800 00000001 c1a9fb30  
  17. <4>[592005.846675]  c1a9fa30 b90e8051 00000869 c19b7600 c1a9fb30c1a9fa30 c1a9f910 c1a9f800  
  18. <0>[592005.846675]Call Trace:  
  19. <4>[592005.846675]  [<c12b775d>] ? htb_dequeue+0x3ad/0x7a0  
  20. <4>[592005.846675]  [<c12b0635>] ? __qdisc_run+0x75/0xf0  


 

l  定位

粗看发现htb_dequeue函数,后来仔细查看是在我们自己的内核模块sch_per,是通过EIP地址转换得到,不清楚此版本的linux kernel显示调用栈为什么不完整。

具体原因是在网口down时,会释放当前所有的IP结点,但是其活跃链表的链表头没有初始化,仍然指向了已经释放的IP结点,导致网口再次up时,出现panic。

 

3.5    栈越界写
[plain]  view plain copy
  1. </pre></h2><p>l  <strong>现象</strong></p><p></p><pre name="code" class="plain"><1>[3872.496538] BUG: unable to handle kernel NULL pointer dereference at   (null)  
  2. <1>[3872.504815] IP: [<  (null)>]   (null)  
  3. <4>[3872.506445] *pde = 00000000  
  4. <4>[3872.506445] Oops: 0000 [#1]  
  5. <4>[3872.506445] Modules linked in: maxnet_dpi(O) sch_per(O)  
  6. <4>[3872.506445]  
  7. <4>[3872.506445] Pid: 0, comm: swapper Tainted: G           O 3.3.8 #44 MICRO-STAR INTERNATIONALCO., LTD MS-9641/MS-9641  
  8. <4>[3872.506445] EIP: 0060:[<00000000>] EFLAGS: 00010286 CPU: 0  
  9. <4>[3872.506445] EIP is at 0x0  
  10. <4>[3872.506445] EAX: 00000000 EBX: 00000000 ECX: 00000000 EDX: c1a3d96d  
  11. <4>[3872.506445] ESI: 00000000 EDI: 00000000 EBP: 00000000 ESP: f680bce8  
  12. <4>[3872.506445]  DS: 007b ES: 007b FS: 0000GS: 0000 SS: 0068  
  13. <0>[3872.506445] Process swapper (pid: 0, ti=f680a000 task=c14264c0task.ti=c141e000)  
  14. <0>[3872.506445] Stack:  
  15. <4>[3872.506445]  00000000 00000000 00000000f680bd08 f89237d0 f680bd40 f88fb0a2 c1a3d840  
  16. <4>[3872.506445]  00000000 00000000 0000000000000000 00000000 00000000 00000000 00000000  
  17. <4>[3872.506445]  00000000 00000000 0000000000000000 00000006 00000000 f88fb41c c12c9500  
  18. <0>[3872.506445] Call Trace:  
  19. <4>[3872.506445]  [<f89237d0>] ?miner_qos_fini+0x240/0x600 [maxnet_dpi]  


某一台设备,经常性的panic(每天平均一次以上),但EIP记录为0,无法获得panic时的地址,通过翻译调用栈地址,仅能得到在内核模块的forward函数和local_in函数位置,详细的panic位置无法获取。

 

粗略查看,panic有两种情况,一种是在0xf89237d0,另一种是在0xf89237bb,目前已知maxnet-dpi.ko 的基地址为0xf8919000,这两种情况如下:

(1) 0xf89237d0

此地址(偏移地址为0xa7d0)定位到函数 app_local_in 的第一行,反汇编后查看,发现指令如下:

0000a7d0 <app_local_in>:

#ifndef MAXNET_CHINA_TELECOM

static int app_local_in(unsigned char*layer2_data, maxnet_tupleinfo_t *tuple, void *data)

{

   a7d0:       57                      push   %edi

仅仅一个入栈动作(push %edi)导致panic,如果其地址可信,怀疑可能是硬件问题。

 

(2) 0xf89237bb

此地址定位到maxnet_dpi_proc函数的最后一行,即maxnet_dpi_forward调用处

 

此问题仅在一台设备上出现,且此设备为很多年前的、不发货仅供测试的设备,也可能是硬件问题

此问题待定,目前尚未解决!!!!!!!

 

l  现象2

程序在某台网关设备上频繁重启,相关日志如下:

[plain]  view plain copy
  1. CPU 0 Unable to handle kernel pagingrequest at virtual address 587d7a98, epc == c224ca68, ra == c224cc0c  
  2. Oops[#1]:  
  3. Cpu 0  
  4. $ 0  : 00000000 00000031 ffff0000 00000000  
  5. $ 4  : 00000001 00000006 00000000 00000000  
  6. $ 8  : 00007740 8bd8791a 00000010 64725049  
  7. $12  : 00000000 00000000 00000000 00000000  
  8. $16  : 7376694f 43394e4f 64725049 587d7a98  
  9. $20  : c228ed60 c2290000 8b9e8100 00000004  
  10. $24  : 00000010 c128c3cc                   
  11. $28  : 8d7d4000 8d7d7a38 8d7d7c28 c224cc0c  
  12. Hi   : 033e3b62  
  13. Lo   : f4806fde  
  14. epc  : c224ca68 maxnet_dpi_proc+0xa8/0x374 [m01_b01]  
  15.    Tainted: P           O  
  16. ra   : c224cc0c maxnet_dpi_proc+0x24c/0x374 [m01_b01]  
  17. Status: 10009903    KERNEL EXL IE  
  18. Cause : 0000000c  
  19. BadVA : 587d7a98  
  20. PrId : 0002a080 (Broadcom BMIPS4350)  
  21. Call Trace:  
  22. [<c224ca68>]maxnet_dpi_proc+0xa8/0x374 [m01_b01]  
  23. [<c173420c>]ips_check+0xc0/0x14c [dpi]  

 

查看出错代码位置的反汇编,发现对应的代码段如下:

[cpp]  view plain copy
  1. *layer7_id= 0;  
  2. layer3_data =IP_HEADER_FROM_MAC(layer2data);  
  3. eh = (struct ethheader*) layer2data;  
  4. if ( IP_PROTO_UDP ==tupleinfo->proto ) {  
  5. /*4. we check the hostnameby DHCP for osinfo detection */  
  6. if ( MAXNET_DPI_ENGINE_ON== g_dpi_engine_conf.osinfo_engine_status ){  
  7. if((!tupleinfo->direct)&&  
  8. 68 ==ntohs(tupleinfo->sport) &&  
  9. 67 ==ntohs(tupleinfo->dport)){  
  10. memcpy(mac_address,eh->h_source, 6);  
  11. dpi_osinfo_refresh_hostname(layer3_data,tupleinfo->sipv4, mac_address);  
  12. }  
  13. }  
  14. }  
  15. *layer7_id= 0;  


出错的指令地址对应红色代码,但上方不远处有相同的代码,故认为是DHCP处理函数(dpi_osinfo_refresh_hostname)导致,详细查看代码,发现其内部的子函数在memcpy 时没有注意长度,会导致栈数组越界。

栈越界时,会将很多信息破坏,包括调用栈、返回指针,所以之前看到的panic,连EIP都是错的,以后如果看到调用栈损坏、EIP非法,就可以考虑是否为栈越界。



“Unhandled Page fault" 是在内核代码里输出的 (arch/arm/mm/fault.c):

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. static void  
  2. __do_user_fault(struct task_struct *tsk, unsigned long addr,  
  3.                 unsigned int fsr, unsigned int sig, int code,  
  4.                 struct pt_regs *regs)  
  5. {  
  6.         struct siginfo si;  
  7.   
  8. #ifdef CONFIG_DEBUG_USER  
  9.         if (user_debug & UDBG_SEGV) {  
  10.                 printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",  
  11.                        tsk->comm, sig, addr, fsr);  
  12.                 show_pte(tsk->mm, addr);  
  13.                 show_regs(regs);  
  14.         }  
  15. #endif  

从代码可以看出,需要配置 CONFIG_DEBUG_USER和设置 user_debug。user_debug可以在内核启动参数里设置。

在qemu上,可以以如下的方式启动:

qemu-system-arm -M vexpress-a9 -kernel ./linux-3.2/arch/arm/boot/zImage -sd rootfs.img --append "root=/dev/mmcblk0 rw rootfs=ext3 rootdelay=3  physmap.enabled=0  console=tty0 user_debug=0xff" -net nic,vlan=0 -net tap,vlan=0


然后测试:

如果"unhandled page fault"不能看到,执行下:

echo 8 > /proc/sys/kernel/printk

可以根据pc寄存器的信息调试:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. ~$ arm-linux-gnueabi-addr2line -f -e test20 0x000083a2  
  2. main  
  3. /home/charles/test20.c:4  
或者:

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. arm-linux-gnueabi-objdump -S -l -z  -j .text test20   >1.txt  
在输出文件里查找  pc值对应的代码



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Linux panic是指Linux操作系统发生严重错误或异常情况时,系统无法继续正常运行,进入一种紧急状态,显示出一些错误信息,这种情况也被称为“内核崩溃”。通常需要通过重启系统来解决这种问题Linux panic可能是由于硬件故障、驱动程序错误、内存泄漏、文件系统损坏等原因引起的。为了避免出现Linux panic,需要定期进行系统维护和更新,及时修复系统中的错误和漏洞。 ### 回答2: Linux Panic是指Linux系统内核遇到了无法处理的致命错误,导致系统进入非常严重的错误状态。在发生Panic时,Linux内核意识到系统已经无法正常运行,需要立即停止运行,以避免更加严重的问题发生。 通常,Panic会出现一些类似于以下信息的错误提示: Kernel panic: VFS: Unable to mount root fs on unknown-block(0,0) 或者 Kernel panic - not syncing: Attempted to kill init! 这些错误提示是内核检测到Linux内核已经无法处理运行中的问题时所输出的信息。 通常,Linux Panic发生的原因有很多,例如内存不足,磁盘损坏,文件系统错误等等。因此,当出现Panic错误时,我们需要根据错误提示信息来确定问题涉及的范围,然后进行相应的修复操作。 通常,我们可以尝试从容易导致Panic的组件进行排除,并逐个确定导致Panic的原因所在。例如,我们可以检查硬件故障,重装操作系统,使用紧急修复模式等方法。 总之,当Linux系统发生Panic时,需要及时了解导致此问题的具体原因,并动手解决问题。这有助于保持Linux系统的稳定性和正常运行。 ### 回答3: Linux PanicLinux系统中的一种紧急异常情况,在系统遇到严重问题时会自动触发。它通常是由于系统硬件或软件故障引起,在发生panic时,Linux系统无法继续执行正常的操作,这时候系统会停止运行并显示一系列的错误信息。一般情况下,我们可以通过这些错误信息来确定或者猜测出导致Linux panic的原因,然后针对性地进行相应的处理。 Linux Panic包括Kernel Panic和User Space Panic两种情况,其中Kernel Panic是指内核发生错误、意外终止或严重问题,导致系统无法正常运行。当出现Kernel Panic时,系统会停止执行、并显示一堆错误信息,这时候我们需要重启计算机,并解决导致错误的原因。 User Space Panic是指用户空间程序出现故障,导致系统无法正常运行。这时候,我们需要排除程序故障的原因,或者使用备份文件替换出故障的程序。 为了避免Linux Panic的发生,我们需要注意以下几点: 1.定期对系统进行备份,以防数据丢失 2.检查系统硬件设备是否正常,并定期进行系统维护和更新 3.避免非法的程序和软件安装,并使用合法的软件 4.定期进行系统优化,减少系统负担 总之,Linux Panic虽然是一种紧急异常情况,但我们可以通过正确的处理方法,避免数据丢失和硬件损坏等问题,并保证系统的正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值