/* * Handle breakpoints, single steps and other debuggy things. To keep * things simple initially, we run with interrupts and exceptions * disabled all the time. */ asmlinkage void do_debug(struct pt_regs *regs) { unsigned long dc, ds; ds = __mfdr(DBGREG_DS); pr_debug("do_debug: pc = %08lx, ds = %08lx\n", regs->pc, ds); if (test_thread_flag(TIF_BREAKPOINT)) { pr_debug("TIF_BREAKPOINT set\n"); /* We're taking care of it */ clear_thread_flag(TIF_BREAKPOINT); __mtdr(DBGREG_BWC2A, 0); } if (test_thread_flag(TIF_SINGLE_STEP)) { pr_debug("TIF_SINGLE_STEP set, ds = 0x%08lx\n", ds); if (ds & DS_SSS) { dc = __mfdr(DBGREG_DC); dc &= ~DC_SS; __mtdr(DBGREG_DC, dc); clear_thread_flag(TIF_SINGLE_STEP); ptrace_break(current, regs); } } else { /* regular breakpoint */ ptrace_break(current, regs); } }
asmlinkage void do_debug_priv(struct pt_regs *regs) { unsigned long dc, ds; unsigned long die_val; ds = __mfdr(DBGREG_DS); pr_debug("do_debug_priv: pc = %08lx, ds = %08lx\n", regs->pc, ds); if (ds & DS_SSS) die_val = DIE_SSTEP; else die_val = DIE_BREAKPOINT; if (notify_die(die_val, regs, 0, SIGTRAP) == NOTIFY_STOP) return; if (likely(ds & DS_SSS)) { extern void itlb_miss(void); extern void tlb_miss_common(void); struct thread_info *ti; dc = __mfdr(DBGREG_DC); dc &= ~DC_SS; __mtdr(DBGREG_DC, dc); ti = current_thread_info(); set_ti_thread_flag(ti, TIF_BREAKPOINT); /* The TLB miss handlers don't check thread flags */ if ((regs->pc >= (unsigned long)&itlb_miss) && (regs->pc <= (unsigned long)&tlb_miss_common)) { __mtdr(DBGREG_BWA2A, sysreg_read(RAR_EX)); __mtdr(DBGREG_BWC2A, 0x40000001 | (get_asid() << 1)); } /* * If we're running in supervisor mode, the breakpoint * will take us where we want directly, no need to * single step. */ if ((regs->sr & MODE_MASK) != MODE_SUPERVISOR) set_ti_thread_flag(ti, TIF_SINGLE_STEP); } else { panic("Unable to handle debug trap at pc = %08lx\n", regs->pc); } }
int __init arch_init_kprobes(void) { printk("KPROBES: Enabling monitor mode (MM|DBE)...\n"); __mtdr(DBGREG_DC, DC_MM | DC_DBE); /* TODO: Register kretprobe trampoline */ return 0; }
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 = __mfdr(DBGREG_DC); dc &= ~DC_SS; __mtdr(DBGREG_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 = __mfdr(DBGREG_DC); dc |= DC_SS; __mtdr(DBGREG_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)); }
long arch_ptrace(struct task_struct *child, long request, long addr, long data) { unsigned long tmp; int ret; pr_debug("arch_ptrace(%ld, %d, %#lx, %#lx)\n", request, child->pid, addr, data); pr_debug("ptrace: Enabling monitor mode...\n"); __mtdr(DBGREG_DC, __mfdr(DBGREG_DC) | DC_MM | DC_DBE); switch (request) { /* Read the word at location addr in the child process */ case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (ret == sizeof(tmp)) ret = put_user(tmp, (unsigned long __user *)data); else ret = -EIO; 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 = access_process_vm(child, addr, &data, sizeof(data), 1); if (ret == sizeof(data)) ret = 0; else ret = -EIO; 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; /* Detach a process that was attached */ case PTRACE_DETACH: ret = ptrace_detach(child, data); 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; } pr_debug("sys_ptrace returning %d (DC = 0x%08lx)\n", ret, __mfdr(DBGREG_DC)); return ret; }
void machine_restart(char *cmd) { __mtdr(DBGREG_DC, DC_DBE); __mtdr(DBGREG_DC, DC_RES); while (1) ; }