当前位置:硬件测评 > 基于MIPS的backtrace调试

基于MIPS的backtrace调试

  • 发布:2023-09-25 12:40

首先来看一下当应用层出现错误,默认的linux-kernel输出的错误信息。应用层代码如下:

#include 
#include 
#include extern int sigset(int signo);
int func_a(unsigned char* a, unsigned char * b, int c, int d);
int func_b(unsigned char* a);
int func_c(unsigned char* a);int func_a(unsigned char* a, unsigned char * b, int c, int d)
{func_b(a);return 0;
}int func_b(unsigned char* a)
{func_c(a);return 0;
}int func_c(unsigned char* a)
{*a = "Hello";return 0;
}int main(int argc, char* argv[])
{unsigned char* a;unsigned char buffer[2];a = NULL;//*a = 1;  func_a(a, buffer, 2, 3);return 0;
}

在函数func_c中对空指针a赋值,导致异常,将内核打印打开,输出的错误信息如下:

# echo "8  4    1    7" >/proc/sys/kernel/printk

# ./main

do_page_fault(): sending SIGSEGV to main for invalid write access to 00000000
epc = 00400854 in main[400000+1000]
ra  = 00400818 in main[400000+1000]

Segmentation fault

看起来kernel对应用层引发的异常不够重视啊,我们来想办法改善一下。

当内核崩溃,将会执行异常处理程序,mips架构下溃函数执行流程是:

do_page_fault()->die()->show_registers()->show_stacktrace()->show_backtrace()

查看kernel源码,Fault.c (\linux-pdk2.8.0-20220401-auto\arch\mips\mm):

static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write,unsigned long address)
{...bad_area_nosemaphore:/* User mode accesses just cause a SIGSEGV */if (user_mode(regs)) {tsk->thread.cp0_badvaddr = address;tsk->thread.error_code = write;if (show_unhandled_signals &&unhandled_signal(tsk, SIGSEGV) &&__ratelimit(&ratelimit_state)) {pr_info("\ndo_page_fault(): sending SIGSEGV to %s for invalid %s %0*lx",tsk->comm,write ? "write access to" : "read access from",field, address);pr_info("epc = %0*lx in", field,(unsigned long) regs->cp0_epc);print_vma_addr(" ", regs->cp0_epc);pr_info("ra  = %0*lx in", field,(unsigned long) regs->regs[31]);print_vma_addr(" ", regs->regs[31]);pr_info("\n");}current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;www.sychzs.cn_signo = SIGSEGV;www.sychzs.cn_errno = 0;/* www.sychzs.cn_code has been set above */www.sychzs.cn_addr = (void __user *) address;force_sig_info(SIGSEGV, &info, tsk);return;}...
}

果然由usermode引发的异常打印的信息很有限。

不过kernel本身已经提供了很多打印现场的函数,我们在这里调用试试看效果。

下面函数打印了现场的寄存器信息及stack数据。

Traps.c (.\linux-pdk2.8.0-20220401-auto\arch\mips\kernel): :void show_registers(struct pt_regs *regs)

static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write,unsigned long address)
{...if (show_unhandled_signals &&unhandled_signal(tsk, SIGSEGV) &&__ratelimit(&ratelimit_state)) {pr_info("\ndo_page_fault(): sending SIGSEGV to %s for invalid %s %0*lx",tsk->comm,write ? "write access to" : "read access from",field, address);pr_info("epc = %0*lx in", field,(unsigned long) regs->cp0_epc);print_vma_addr(" ", regs->cp0_epc);pr_info("ra  = %0*lx in", field,(unsigned long) regs->regs[31]);			print_vma_addr(" ", regs->regs[31]);pr_info("\n");show_registers(regs);	//Ben 230516#1}...
}

加上这个函数后,输出结果如下:

# ./main

do_page_fault(): sending SIGSEGV to main for invalid write access to 00000000
epc = 00400854 in main[400000+1000]
ra  = 00400818 in main[400000+1000]

CPU: 0 PID: 1007 Comm: main Tainted: G           O    4.4.261-as-release #9
task: 8fc4c028 ti: 8f402000 task.ti: 8f402000
$ 0   : 00000000 00000001 00000000 00000030
$ 4   : 00000000 7fe03344 00000002 00000003
$ 8   : 000191a0 00000000 00000000 726f7272
$12   : 0000000a 00000000 76f71350 00400628
$16   : 00000000 004008d0 004bd68b 00000000
$20   : 00000000 77383498 ffffffff 00000000
$24   : 00000000 00400870                  
$28   : 76f72e30 7fe032e0 7fe032e0 00400818
Hi    : 000001a5
Lo    : 00005e17
epc   : 00400854 0x400854
ra    : 00400818 0x400818
Status: 21008813        USER EXL IE 
Cause : 0080000c (ExcCode 03)
BadVA : 00000000
PrId  : 00019755 (MIPS 74Kc)
Modules linked in: wxa(O) vc1(O) mjpg(O)
Process main (pid: 1007, threadinfo=8f402000, task=8fc4c028, tls=770c3490)
Stack : 7fe03344 7fe032e8 00000000 770c4234 00000000 770bec88 00000001 00000000
          7fe03308 004007dc 00000000 76b8bbe8 00000000 00400914 00000000 00000000
          7fe03328 004008a8 00000000 7fe03344 00000002 00000003 004008d0 004bd68b
          00000000 004d43c4 004a6a70 76e0b2a8 00000001 7fe03424 76f72e30 00000010
          76f72e30 00000001 76e0b268 7fe03350 00000000 004008d0 004bd68b 00000000
          ...
Call Trace:
over

Code: 24420a30  304300ff  8fc20008 00001025  03c0e825  8fbe0004  27bd0008  03e00008 
Segmentation fault

相关文章

热门推荐