void __noreturn die(const char *str, struct pt_regs *regs, long err, unsigned long addr) { static int die_counter; oops_enter(); spin_lock_irq(&die_lock); console_verbose(); bust_spinlocks(1); pr_err("%s: err %04lx (%s) addr %08lx [#%d]\n", str, err & 0xffff, trap_name(err & 0xffff), addr, ++die_counter); print_modules(); show_regs(regs); pr_err("Process: %s (pid: %d, stack limit = %p)\n", current->comm, task_pid_nr(current), task_stack_page(current) + THREAD_SIZE); bust_spinlocks(0); add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); if (kexec_should_crash(current)) crash_kexec(regs); if (in_interrupt()) panic("Fatal exception in interrupt"); if (panic_on_oops) panic("Fatal exception"); spin_unlock_irq(&die_lock); oops_exit(); do_exit(SIGSEGV); }
//! This is what called from low-level asm trap code void phantom_kernel_trap( struct trap_state *ts ) { int trapno = ts->trapno; check_global_lock_entry_count(); // Debug int (*handler)(struct trap_state *ts) = phantom_trap_handlers[trapno]; if(handler == 0) { #if 1 // off to debug stack trap on real AMD cpu if( phantom_check_user_trap( ts ) ) // returns 0 if not an user mode thread, 1 if exception processed return; #endif trap_panic(ts); } if(handler(ts)) { dump_ss(ts); panic("Trap handler failed for trap %s\n", trap_name(trapno)); } #if ARCH_arm // Why just on arm? Will do any harm on PC? Need to check return value from handler to skip SoftIRQ processing? //hal_softirq_dispatcher(ts); #endif }
void dump_ss(struct trap_state *st) { if(panic_reenter > 1) return; //int from_user = (st->cs & 3) || (st->eflags & EFL_VM); printf("Dump of mips state:\n" ); printf("Z = (0) AT= %08x V0= %08x V1= %08x\n", st->r1, st->r2, st->r3); printf("A0= %08x A1= %08x A2= %08x A3= %08x\n", st->r4, st->r5, st->r6, st->r7); printf("T0= %08x T1= %08x T2= %08x T3= %08x\n", st->r8, st->r9, st->r10, st->r11); printf("T4= %08x T5= %08x T6= %08x T7= %08x\n", st->r12, st->r13, st->r14, st->r15); // TODO rest 16 printf("S0= %08x S1= %08x S2= %08x S3= %08x\n", st->r16, st->r17, st->r18, st->r19); printf("S4= %08x S5= %08x S6= %08x S7= %08x\n", st->r20, st->r21, st->r22, st->r23); printf("T8= %08x T9= %08x K0= %08x K1= %08x\n", st->r24, st->r25, st->r26, st->r27); printf("GP= %08x SP= %08x FP= %08x RA= %08x\n", st->r28, st->r29, st->r30, st->r31); printf("HI= %08x LO= %08x PC= %08x\n", st->hi, st->lo, st->pc ); printf("trapno %d: %s, intno %08x\n", st->trapno, trap_name(st->trapno), st->intno); //if(st->trapno == T_PAGE_FAULT) printf("page fault linear address %08x\n", st->cr2); if(phantom_symtab_getname) { printf("PC %6p: %s\n", st->pc, phantom_symtab_getname((void *)st->pc) ); } stack_dump_from((void *)st->r11); }
/* * Print trap reason. */ void kdbprinttrap( int type, int code) { printf("kernel: %s (%d), code=%x\n", trap_name(type), type, code); }
int trap_panic(struct trap_state *ts) { dump_ss(ts); int type = ts->trapno; panic("Unexpected trap %s\n", trap_name(type)); return -1; }
boolean_t kdb_trap( int type, int code, struct i386_saved_state *regs) { spl_t s; s = splhigh(); saved_ipl[cpu_number()] = s; switch (type) { case T_DEBUG: /* single_step */ { int addr; int status = get_dr6(); if (status & 0xf) { /* hmm hdw break */ addr = status & 0x8 ? get_dr3() : status & 0x4 ? get_dr2() : status & 0x2 ? get_dr1() : get_dr0(); regs->efl |= EFL_RF; db_single_step_cmd(addr, 0, 1, "p"); } } case T_INT3: /* breakpoint */ case T_WATCHPOINT: /* watchpoint */ case -1: /* keyboard interrupt */ break; default: if (db_recover) { i386_nested_saved_state = *regs; db_printf("Caught %s (%d), code = %x, pc = %x\n", trap_name(type), type, code, regs->eip); db_error(""); /*NOTREACHED*/ } kdbprinttrap(type, code); } #if NCPUS > 1 if (db_enter()) #endif /* NCPUS > 1 */ { i386_last_saved_statep = regs; i386_last_kdb_sp = (unsigned) &type; /* XXX Should switch to ddb`s own stack here. */ ddb_regs = *regs; if ((regs->cs & 0x3) == KERNEL_RING) { /* * Kernel mode - esp and ss not saved */ ddb_regs.uesp = (int)®s->uesp; /* kernel stack pointer */ ddb_regs.ss = KERNEL_DS; } cnpollc(TRUE); db_task_trap(type, code, (regs->cs & 0x3) != 0); cnpollc(FALSE); regs->eip = ddb_regs.eip; regs->efl = ddb_regs.efl; regs->eax = ddb_regs.eax; regs->ecx = ddb_regs.ecx; regs->edx = ddb_regs.edx; regs->ebx = ddb_regs.ebx; if ((regs->cs & 0x3) != KERNEL_RING) { /* * user mode - saved esp and ss valid */ regs->uesp = ddb_regs.uesp; /* user stack pointer */ regs->ss = ddb_regs.ss & 0xffff; /* user stack segment */ } regs->ebp = ddb_regs.ebp; regs->esi = ddb_regs.esi; regs->edi = ddb_regs.edi; regs->es = ddb_regs.es & 0xffff; regs->cs = ddb_regs.cs & 0xffff; regs->ds = ddb_regs.ds & 0xffff; regs->fs = ddb_regs.fs & 0xffff; regs->gs = ddb_regs.gs & 0xffff; if ((type == T_INT3) && (db_get_task_value(regs->eip, BKPT_SIZE, FALSE, TASK_NULL) == BKPT_INST)) regs->eip += BKPT_SIZE; } #if NCPUS > 1 db_leave(); #endif /* NCPUS > 1 */ splx(s); return 1; }