printk("\n");
}
-void show_trace_task(struct task_struct *tsk)
+void show_trace_raw(struct thread_info *tp, unsigned long ksp)
{
- unsigned long pc, fp;
- unsigned long thread_base = (unsigned long) tsk->thread_info;
+ unsigned long pc, fp, thread_base;
struct reg_window *rw;
int count = 0;
- if (!tsk)
- return;
-
- fp = tsk->thread_info->ksp + STACK_BIAS;
+ fp = ksp + STACK_BIAS;
+ thread_base = (unsigned long) tp;
do {
/* Bogus frame pointer? */
if (fp < (thread_base + sizeof(struct thread_info)) ||
printk("\n");
}
+void show_trace_task(struct task_struct *tsk)
+{
+ if (tsk)
+ show_trace_raw(tsk->thread_info,
+ tsk->thread_info->ksp);
+}
+
void die_if_kernel(char *str, struct pt_regs *regs)
{
extern void __show_regs(struct pt_regs * regs);
return tally;
}
-void unhandled_fault(unsigned long address, struct task_struct *tsk,
- struct pt_regs *regs)
+static void unhandled_fault(unsigned long address, struct task_struct *tsk,
+ struct pt_regs *regs)
{
if ((unsigned long) address < PAGE_SIZE) {
printk(KERN_ALERT "Unable to handle kernel NULL "
die_if_kernel("Oops", regs);
}
+extern void show_trace_raw(struct thread_info *, unsigned long);
+
+static void bad_kernel_pc(struct pt_regs *regs)
+{
+ unsigned long ksp;
+
+ printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n",
+ regs->tpc);
+ __asm__("mov %%sp, %0" : "=r" (ksp));
+ show_trace_raw(current_thread_info(), ksp);
+ unhandled_fault(regs->tpc, current, regs);
+}
+
/*
* We now make sure that mmap_sem is held in all paths that call
* this. Additionally, to prevent kswapd from ripping ptes from
if (!regs->tpc || (regs->tpc & 0x3))
return 0;
if (regs->tstate & TSTATE_PRIV) {
- insn = *(unsigned int *)regs->tpc;
+ insn = *(unsigned int *) regs->tpc;
} else {
insn = get_user_insn(regs->tpc);
}
(fault_code & FAULT_CODE_DTLB))
BUG();
+ if (regs->tstate & TSTATE_PRIV) {
+ unsigned long tpc = regs->tpc;
+ extern unsigned int _etext;
+
+ /* Sanity check the PC. */
+ if ((tpc >= KERNBASE && tpc < (unsigned long) &_etext) ||
+ (tpc >= MODULES_VADDR && tpc < MODULES_END)) {
+ /* Valid, no problems... */
+ } else {
+ bad_kernel_pc(regs);
+ return;
+ }
+ }
+
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
goto intr_or_no_mm;
if (test_thread_flag(TIF_32BIT)) {
- regs->tpc &= 0xffffffff;
+ if (!(regs->tstate & TSTATE_PRIV))
+ regs->tpc &= 0xffffffff;
address &= 0xffffffff;
}