kernel 异常重启的log输出

异常处理函数,在底层【汇编代码】做一些处理后,最后调用C接口函数。即使是C函数,内核异常的处理函数还是CPU架构相关的,就是函数在arch下的不同目录下实现。


未定义指令的处理:

当发生指令异常时,汇编代码的处理是[64ARMV8架构为例]

对应的汇编代码在文件kernel/arch/arm64/kernel/entry.S中,

el1_undef:

/*

* Undefined instruction

*/

enable_dbg

mov x0,sp

b do_undefinstr



do_undefinstr的实现在具体CPU架构的文件kernel/arch/arm64/kernel/traps.c,不同异常处理一般都调用函数arm64_notify_diearm64_notify_die只是做了简单的处理,最后调用die

do_undefinstr

->arm64_notify_die("Oops- undefined instruction", regs, &info, 0);

->die



die主要由三个子函数oop_begin,__dieoop_end组成,内核异常后的log主要有这三个函数输出。

voiddie(const char *str, struct pt_regs *regs, int err)

{



unsignedlong flags = oops_begin();



ret= __die(str, err, thread, regs);



oops_end(flags,regs, ret);

}



oops_begin()没有打印信息,log主要由函数__die输出,如backtrace

staticint __die(const char *str, int err, struct thread_info *thread,

struct pt_regs *regs)

{

pr_emerg("Internalerror: %s: %x [#%d]" S_PREEMPT S_SMP "\n",

str, err, ++die_counter);





print_modules();

__show_regs(regs);

pr_emerg("Process%.*s (pid: %d, stack limit = 0x%p)\n",

TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1);



if(!user_mode(regs) || in_interrupt()) {

dump_backtrace(regs,tsk);

dump_instr(KERN_EMERG,regs);

}

}

如以下打印信息,都有__die函数输出;

[ 140.325767] Internal error: Oops: 96000045 [#1] PREEMPT SMP

[ 140.325800] Modules linked in: wlan(O)

[ 140.325870] CPU: 0 PID: 5011 Comm: sh Tainted: G W O 3.18.20-perf-ga0cfe42 #1

[ 140.325895] Hardware name: Qualcomm TechnologiesPC i, Inc. MSM 8996v3 + PMI8994 MTP (DT)

[ 140.325925] task: ffffffc004e8a580 ti: ffffffc05809c000 task.ti:ffffffc05809c000

[ 140.325983] PC is at sysrq_handle_crash+0x14/0x1c

[ 140.326010] LR is at __handle_sysrq+0x9c/0x150

[ 140.332644] Process sh (pid: 5011, stack limit = 0xffffffc05809c058)

[ 140.332669] Call trace:

[ 140.332712] [<ffffffc000624ecc>] sysrq_handle_crash+0x14/0x1c

[ 140.332741] [<ffffffc000625ac8>] write_sysrq_trigger+0x48/0x60

[ 140.332784] [<ffffffc0003704f4>] proc_reg_write+0x64/0x84

[ 140.332817] [<ffffffc000320938>] vfs_write+0xb8/0x194

[ 140.332842] [<ffffffc000320fb4>] SyS_write+0x44/0x84

[ 140.332872] Code: 52800020 b909f420 d5033e9f d2800001 (39000020)



下面看die的最后一个函数:oop_end



staticvoid oops_end(unsigned long flags, struct pt_regs *regs, int notify)

{

oop_exit()

if(in_interrupt())

panic("Fatalexception in interrupt");

if(panic_on_oops)

panic("Fatalexception");

}



函数oop_exitpanicCPU无关的文件kernel/kernel/panic.c

oops_exit会输出信息---[end trace da227214a82491b9 ]---

oops_exit(void)->print_oops_end_marker()

->pr_warn("---[end trace %016llx ]---\n", (unsigned long long)oops_id);



内核异常后,整机会重启,重启就是在函数panic控制的,方法就是进入死循环,利用硬件看门狗超时使系统重启。

voidpanic(const char *fmt, ...)

{

pr_emerg("Kernelpanic - not syncing: %s\n", buf);

if(!test_taint(TAINT_DIE) && oops_in_progress <= 1)

dump_stack();

/*

* Run any panic handlers, including those that might need to

* add information to the kmsg dump output.

*/

atomic_notifier_call_chain(&panic_notifier_list,0, buf);

if(panic_timeout > 0) {

/*

* Delay timeout seconds before rebooting the machine.

* We can't use the "normal" timers since we just panicked.

*/

pr_emerg("Rebootingin %d seconds..", panic_timeout);



for(i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) {

touch_nmi_watchdog();

if(i >= i_next) {

i+= panic_blink(state ^= 1);

i_next= i + 3600 / PANIC_BLINK_SPD;

}

mdelay(PANIC_TIMER_STEP);

}

}

}



数据访问异常

dataabort异常并非都会导致系统重启,虚拟内存的缺页机制也是通过数据访问异常实现的。



ENTRY(v6_early_abort)

mrc p15,0, r1, c5, c0, 0 @ get FSR

mrc p15,0, r0, c6, c0, 0 @ get FAR

b do_DataAbort



arch/arm/mm/fault.c:550:do_DataAbort(unsignedlong addr, unsigned int fsr, struct pt_regs *regs)

asmlinkagevoid __exception

do_DataAbort(unsignedlong addr, unsigned int fsr, struct pt_regs *regs)

{

conststruct fsr_info *inf = fsr_info + fsr_fs(fsr);

structsiginfo info;





if(!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))

return;



trace_unhandled_abort(regs,addr, fsr);



printk(KERN_ALERT"Unhandled fault: %s (0x%03x) at 0x%08lx\n",

inf->name,fsr, addr);



info.si_signo= inf->sig;

info.si_errno= 0;

info.si_code = inf->code;

info.si_addr = (void __user *)addr;

arm_notify_die("",regs, &info, fsr, 0);

}



do_DataAbort的异常处理并没有调用arm_notify_die("",regs, &info, fsr, 0);

而是inf->fn(addr,fsr & ~FSR_LNX_PF, regs): c0115920 t do_page_fault

do_page_fault->

__do_kernel_fault(mm,addr, fsr, regs);





/*

*Oops. The kernel tried to access some page that wasn't present.

*/

staticvoid

__do_kernel_fault(structmm_struct *mm, unsigned long addr, unsigned int fsr,

struct pt_regs *regs)

{

/*

* Are we prepared to handle this kernel fault?

*/

if(fixup_exception(regs))

return;



/*

* No handler, we'll have to terminate things with extreme prejudice.

*/

bust_spinlocks(1);

printk(KERN_ALERT

"Unableto handle kernel %s at virtual address %08lx\n",

(addr< PAGE_SIZE) ? "NULL pointer dereference" :

"pagingrequest", addr);



show_pte(mm,addr);

die("Oops",regs, fsr);

}


直接重启

直接重启,没有进入异常处理流程,没有backtrace等信息的保存。利用pstore机制,保存系统最后时间运行的kernellog logcat.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值