根据epc和ra定位linux kernel panic或者应用程序的出错位置

58 篇文章 10 订阅
本文档描述了一种在没有coredump文件的情况下,通过epc和ra信息定位Linux内核panic和应用程序错误的方法。通过分析epc和ra在动态库libc-2.25.so中的地址,结合内核源码和反汇编,发现错误发生在strchrnul函数中,由于非法读取导致SIGSEGV。进一步的调试揭示了问题源于局部变量数组越界,影响了打印函数的栈,最终导致死机。解决办法是检查并修正可能导致越界的代码段。
摘要由CSDN通过智能技术生成

根据epc和ra定位linux kernel panic或者应用程序的出错位置

一、背景

项目中出现了死机的问题,不幸的是没有保存下来coredump文件,只有简要的epc和ra信息。尝试复现问题,一直不能复现。所以尝试通过epc和ra去找到问题。

二、分析过程

log信息如下,目的是想定位到出错的源代码。

[10:39:09]Activating card
[10:39:10]ATR: 3F EF 07 7F F8 FF FF 07 03 FF FF 80 FE FE FC F4 FF FF F8 FF FF FF F8 FF FE 
[10:39:10]TB1=07 TC1=7F TD1=F8 (T8)
[10:39:10][ 4509.682667] 
[10:39:10]do_page_fault(): sending SIGSEGV to core_main.out for invalid read access from 00000001
[10:39:10][ 4509.690651] epc = 778b83ec in libc-2.25.so[77830000+169000]
[10:39:10][ 4509.696411] ra = 778778cc in libc-2.25.so[77830000+169000]

首先要知道epc = 778b83ec ra = 778778cc libc-2.25.so[77830000+169000]分别是什么。通过查找资料epc :exception program counter, 异常程序计数器。ra : return address 返回地址,出错在 libc-2.25.so动态库。[77830000+169000]是什么呢?网上没查到答案,那就查内核源码,根据打印提示找到源码粗略摘要如下:

内核文件:arch/mips/mm/fault.c

__do_page_fault
{
        pr_info("epc = %0*lx in", field,(unsigned long) regs->cp0_epc);
        print_vma_addr(" ", regs->cp0_epc);
        {
                vma = find_vma(mm, ip);

                if (vma && vma->vm_file)  {

                        vma = find_vma(mm, ip);

                        struct file *f = vma->vm_file;

                        p = file_path(f, buf, PAGE_SIZE);

                        printk("%s%s[%lx+%lx]", prefix, kbasename(p), vma->vm_start,vma->vm_end - vma->vm_start); //输出内容为: libc-2.25.so[77830000+169000]

                }

        }
}

通过代码可知 0x77830000 是libc-2.25.so库虚拟内存起始地址,大小为0x169000。那么epc = 778b83ec,对应汇编代码地址778b83ec - 77830000=883ec;ra = 778778cc,对应汇编代码地址778778cc-77830000=478cc。

接下来对libc-2.25.so进行反汇编/opt/montage/mipsel-mt-linux-gnu/bin/mips-linux-gnu-objdump -S libc-2.25.so > libc-2.25.so.dis.s

然后就比较简单了,搜索反汇编文件libc-2.25.so.dis.s查找异常点:883ec。

000883c0 <strchrnul@@GLIBC_2.2>:
883c0: 30820003 andi v0,a0,0x3
883c4: 14400009 bnez v0,883ec <strchrnul@@GLIBC_2.2+0x2c>
883c8: 30a600ff andi a2,a1,0xff
883cc: 1000000c b 88400 <strchrnul@@GLIBC_2.2+0x40>
883d0: 00055a00 sll t3,a1,0x8
883d4: 10400008 beqz v0,883f8 <strchrnul@@GLIBC_2.2+0x38>
883d8: 00000000 nop
883dc: 24840001 addiu a0,a0,1
883e0: 30820003 andi v0,a0,0x3
883e4: 10400006 beqz v0,88400 <strchrnul@@GLIBC_2.2+0x40>
883e8: 00055a00 sll t3,a1,0x8
883ec: 90820000 lbu v0,0(a0) //就是这里出错,这句话的意思是将(a0+0)地址的内容读取到v0寄存器,根据sending SIGSEGV to core_main.out for invalid read access from 00000001推测a0=1
883f0: 14c2fff8 bne a2,v0,883d4 <strchrnul@@GLIBC_2.2+0x14>
883f4: 00000000 nop

似乎看不出什么问题,接着查找返回点478cc

00047824 <_IO_vfprintf@@GLIBC_2.2>:
47824: 3c1c0014 lui gp,0x14
47828: 279cd4ec addiu gp,gp,-11028
.......//太多了省略

478c8: 32108000 andi s0,s0,0x8000
478cc: 8fdc0030 lw gp,48(s8)
478d0: afc20464 sw v0,1124(s8)
478d4: 12000032 beqz s0,479a0 <_IO_vfprintf@@GLIBC_2.2+0x17c>
478d8: afc2045c sw v0,1116(s8)

函数返回点是vfprintf,说明vfprintf调用了strchrnul导致出错。可能是上层调用了printf,那就接着看正常的打印信息如下:

[16:38:22]ATR: 3B 24 00 30 42 30 30 
[16:38:22]TB1=00 no TD1 means T0
[16:38:22]1 protocol types detected. Historical bytes: 30 42 30 30 
[16:38:22]No PTS needed, selected protocol T0, F=372, D=1, N=0
进一步跟踪代码是局部变量数组越界了,冲了打印函数的栈,导致死机。

三、附录Ⅰ:APP的调试

刚开始调试的时候,直接使用了下图中 778b83ec,77830000+169000,77830000等地址,使用addr2line都会报错。报错如下:

## addr2line调试
sean@us1404:~$ mips-linux-addr2line 77764000 -e libcommlog.so -f -C -s
??
??:0

## 找了很多资料,百思不得其解。经过以上的一、二章节的内容后,才知道这几个地址的真正含义
## 我是APP调试,出错内容为
do_page_fault(): sending SIGSEGV to tz_mgr for invalid read access from 00ff4010
[12422.390000] epc = 77f9f170 in libcommlog.so[77f9c000+8000]
[12422.400000] ra  = 77f9f170 in libcommlog.so[77f9c000+8000]

重新修改地址,使用addr2line进行定位分析

epc的地址:7775f3ac-7775c000=33AC

ra的地址:7775f3ac-7775c000=33AC

sean@us1404:~$ mips-linux-addr2line 33AC -e libcommlog.so -f -C -s
savelog
libcommlog.c:824
renyinshan@us1404:~/work/x21G/tzproc/libcommlog/objout$

经过对照代码分析,是因为我定义了一个timezone的获取函数,原来是使用UTC的格式,但是后来改为 CST-8@Asia/Shan,导致越界。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值