void NORET_TYPE die(const char *str, struct pt_regs *regs, long err) { static int die_counter; console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); printk(KERN_ALERT "Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); printk(KERN_EMERG); #ifdef CONFIG_PREEMPT printk(KERN_CONT "PREEMPT "); #endif #ifdef CONFIG_FRAME_POINTER printk(KERN_CONT "FRAME_POINTER "); #endif if (current_cpu_data.features & AVR32_FEATURE_OCD) { unsigned long did = ocd_read(DID); printk(KERN_CONT "chip: 0x%03lx:0x%04lx rev %lu\n", (did >> 1) & 0x7ff, (did >> 12) & 0x7fff, (did >> 28) & 0xf); } else {
static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) { unsigned long dc; pr_debug("resuming execution at PC=%08lx\n", regs->pc); dc = ocd_read(DC); dc &= ~(1 << OCD_DC_SS_BIT); ocd_write(DC, dc); *p->addr = BREAKPOINT_INSTRUCTION; flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t)); }
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) { unsigned long dc; pr_debug("preparing to singlestep over %p (PC=%08lx)\n", p->addr, regs->pc); BUG_ON(!(sysreg_read(SR) & SYSREG_BIT(SR_D))); dc = ocd_read(DC); dc |= 1 << OCD_DC_SS_BIT; ocd_write(DC, dc); *p->addr = p->opcode; flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t)); }
void ocd_enable(struct task_struct *child) { u32 dc; if (child) pr_debug("ocd_enable: child=%s [%u]\n", child->comm, child->pid); else pr_debug("ocd_enable (no child)\n"); if (!child || !test_and_set_tsk_thread_flag(child, TIF_DEBUG)) { spin_lock(&ocd_lock); ocd_count++; dc = ocd_read(DC); dc |= (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT); ocd_write(DC, dc); spin_unlock(&ocd_lock); } }
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) { unsigned long dc; pr_debug("preparing to singlestep over %p (PC=%08lx)\n", p->addr, regs->pc); BUG_ON(!(sysreg_read(SR) & SYSREG_BIT(SR_D))); dc = ocd_read(DC); dc |= 1 << OCD_DC_SS_BIT; ocd_write(DC, dc); /* * We must run the instruction from its original location * since it may actually reference PC. * * TODO: Do the instruction replacement directly in icache. */ *p->addr = p->opcode; flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t)); }
void ocd_disable(struct task_struct *child) { u32 dc; if (!child) pr_debug("ocd_disable (no child)\n"); else if (test_tsk_thread_flag(child, TIF_DEBUG)) pr_debug("ocd_disable: child=%s [%u]\n", child->comm, child->pid); if (!child || test_and_clear_tsk_thread_flag(child, TIF_DEBUG)) { spin_lock(&ocd_lock); ocd_count--; WARN_ON(ocd_count < 0); if (ocd_count <= 0) { dc = ocd_read(DC); dc &= ~((1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT)); ocd_write(DC, dc); } spin_unlock(&ocd_lock); } }
asmlinkage struct pt_regs *do_debug(struct pt_regs *regs) { struct thread_info *ti; unsigned long trampoline_addr; u32 status; u32 ctrl; int code; status = ocd_read(DS); ti = current_thread_info(); code = TRAP_BRKPT; pr_debug("do_debug: status=0x%08x PC=0x%08lx SR=0x%08lx tif=0x%08lx\n", status, regs->pc, regs->sr, ti->flags); if (!user_mode(regs)) { unsigned long die_val = DIE_BREAKPOINT; if (status & (1 << OCD_DS_SSS_BIT)) die_val = DIE_SSTEP; if (notify_die(die_val, "ptrace", regs, 0, 0, SIGTRAP) == NOTIFY_STOP) return regs; if ((status & (1 << OCD_DS_SWB_BIT)) && test_and_clear_ti_thread_flag( ti, TIF_BREAKPOINT)) { /* * Explicit breakpoint from trampoline or * exception/syscall/interrupt handler. * * The real saved regs are on the stack right * after the ones we saved on entry. */ regs++; pr_debug(" -> TIF_BREAKPOINT done, adjusted regs:" "PC=0x%08lx SR=0x%08lx\n", regs->pc, regs->sr); BUG_ON(!user_mode(regs)); if (test_thread_flag(TIF_SINGLE_STEP)) { pr_debug("Going to do single step...\n"); return regs; } /* * No TIF_SINGLE_STEP means we're done * stepping over a syscall. Do the trap now. */ code = TRAP_TRACE; } else if ((status & (1 << OCD_DS_SSS_BIT)) && test_ti_thread_flag(ti, TIF_SINGLE_STEP)) { pr_debug("Stepped into something, " "setting TIF_BREAKPOINT...\n"); set_ti_thread_flag(ti, TIF_BREAKPOINT); /* * We stepped into an exception, interrupt or * syscall handler. Some exception handlers * don't check for pending work, so we need to * set up a trampoline just in case. * * The exception entry code will undo the * trampoline stuff if it does a full context * save (which also means that it'll check for * pending work later.) */ if ((regs->sr & MODE_MASK) == MODE_EXCEPTION) { trampoline_addr = (unsigned long)&debug_trampoline; pr_debug("Setting up trampoline...\n"); ti->rar_saved = sysreg_read(RAR_EX); ti->rsr_saved = sysreg_read(RSR_EX); sysreg_write(RAR_EX, trampoline_addr); sysreg_write(RSR_EX, (MODE_EXCEPTION | SR_EM | SR_GM)); BUG_ON(ti->rsr_saved & MODE_MASK); } /* * If we stepped into a system call, we * shouldn't do a single step after we return * since the return address is right after the * "scall" instruction we were told to step * over. */ if ((regs->sr & MODE_MASK) == MODE_SUPERVISOR) { pr_debug("Supervisor; no single step\n"); clear_ti_thread_flag(ti, TIF_SINGLE_STEP); } ctrl = ocd_read(DC); ctrl &= ~(1 << OCD_DC_SS_BIT); ocd_write(DC, ctrl); return regs; } else { printk(KERN_ERR "Unexpected OCD_DS value: 0x%08x\n", status); printk(KERN_ERR "Thread flags: 0x%08lx\n", ti->flags); die("Unhandled debug trap in kernel mode", regs, SIGTRAP); } } else if (status & (1 << OCD_DS_SSS_BIT)) { /* Single step in user mode */ code = TRAP_TRACE; ctrl = ocd_read(DC); ctrl &= ~(1 << OCD_DC_SS_BIT); ocd_write(DC, ctrl); } pr_debug("Sending SIGTRAP: code=%d PC=0x%08lx SR=0x%08lx\n", code, regs->pc, regs->sr); clear_thread_flag(TIF_SINGLE_STEP); _exception(SIGTRAP, regs, code, instruction_pointer(regs)); return regs; }
static int ocd_DS_get(void *data, u64 *val) { *val = ocd_read(DS); return 0; }
long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int ret; pr_debug("ptrace: Enabling monitor mode...\n"); ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT)); switch (request) { /* Read the word at location addr in the child process */ case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: ret = generic_ptrace_peekdata(child, addr, data); break; case PTRACE_PEEKUSR: ret = ptrace_read_user(child, addr, (unsigned long __user *)data); break; /* Write the word in data at location addr */ case PTRACE_POKETEXT: case PTRACE_POKEDATA: ret = generic_ptrace_pokedata(child, addr, data); break; case PTRACE_POKEUSR: ret = ptrace_write_user(child, addr, data); break; /* continue and stop at next (return from) syscall */ case PTRACE_SYSCALL: /* restart after signal */ case PTRACE_CONT: ret = -EIO; if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; /* XXX: Are we sure no breakpoints are active here? */ wake_up_process(child); ret = 0; break; /* * Make the child exit. Best I can do is send it a * SIGKILL. Perhaps it should be put in the status that it * wants to exit. */ case PTRACE_KILL: ret = 0; if (child->exit_state == EXIT_ZOMBIE) break; child->exit_code = SIGKILL; wake_up_process(child); break; /* * execute single instruction. */ case PTRACE_SINGLESTEP: ret = -EIO; if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); ptrace_single_step(child); child->exit_code = data; wake_up_process(child); ret = 0; break; case PTRACE_GETREGS: ret = ptrace_getregs(child, (void __user *)data); break; case PTRACE_SETREGS: ret = ptrace_setregs(child, (const void __user *)data); break; default: ret = ptrace_request(child, request, addr, data); break; } return ret; }