int __kprobes hw_breakpoint_handler(struct die_args *args) { int rc = NOTIFY_STOP; struct perf_event *bp; struct pt_regs *regs = args->regs; int stepped = 1; struct arch_hw_breakpoint *info; unsigned int instr; unsigned long dar = regs->dar; set_dabr(0); rcu_read_lock(); bp = __get_cpu_var(bp_per_reg); if (!bp) goto out; info = counter_arch_bp(bp); if (bp->overflow_handler == ptrace_triggered) { perf_bp_event(bp, regs); rc = NOTIFY_DONE; goto out; } info->extraneous_interrupt = !((bp->attr.bp_addr <= dar) && (dar - bp->attr.bp_addr < bp->attr.bp_len)); if (user_mode(regs)) { bp->ctx->task->thread.last_hit_ubp = bp; regs->msr |= MSR_SE; goto out; } stepped = 0; instr = 0; if (!__get_user_inatomic(instr, (unsigned int *) regs->nip)) stepped = emulate_step(regs, instr); if (!stepped) { WARN(1, "Unable to handle hardware breakpoint. Breakpoint at " "0x%lx will be disabled.", info->address); perf_event_disable(bp); goto out; } if (!info->extraneous_interrupt) perf_bp_event(bp, regs); set_dabr(info->address | info->type | DABR_TRANSLATION); out: rcu_read_unlock(); return rc; }
static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret) { if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) || ((unsigned long)ptr & 3)) return -EFAULT; if (!__get_user_inatomic(*ret, ptr)) return 0; return read_user_stack_slow(ptr, ret, 4); }
static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret) { if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) || ((unsigned long)ptr & 7)) return -EFAULT; if (!__get_user_inatomic(*ret, ptr)) return 0; return read_user_stack_slow(ptr, ret, 8); }
/* * Handle debug exception notifications. */ int __kprobes hw_breakpoint_handler(struct die_args *args) { int rc = NOTIFY_STOP; struct perf_event *bp; struct pt_regs *regs = args->regs; int stepped = 1; struct arch_hw_breakpoint *info; unsigned int instr; unsigned long dar = regs->dar; /* Disable breakpoints during exception handling */ set_dabr(0, 0); /* * The counter may be concurrently released but that can only * occur from a call_rcu() path. We can then safely fetch * the breakpoint, use its callback, touch its counter * while we are in an rcu_read_lock() path. */ rcu_read_lock(); bp = __get_cpu_var(bp_per_reg); if (!bp) goto out; info = counter_arch_bp(bp); /* * Return early after invoking user-callback function without restoring * DABR if the breakpoint is from ptrace which always operates in * one-shot mode. The ptrace-ed process will receive the SIGTRAP signal * generated in do_dabr(). */ if (bp->overflow_handler == ptrace_triggered) { perf_bp_event(bp, regs); rc = NOTIFY_DONE; goto out; } /* * Verify if dar lies within the address range occupied by the symbol * being watched to filter extraneous exceptions. If it doesn't, * we still need to single-step the instruction, but we don't * generate an event. */ info->extraneous_interrupt = !((bp->attr.bp_addr <= dar) && (dar - bp->attr.bp_addr < bp->attr.bp_len)); /* Do not emulate user-space instructions, instead single-step them */ if (user_mode(regs)) { current->thread.last_hit_ubp = bp; regs->msr |= MSR_SE; goto out; } stepped = 0; instr = 0; if (!__get_user_inatomic(instr, (unsigned int *) regs->nip)) stepped = emulate_step(regs, instr); /* * emulate_step() could not execute it. We've failed in reliably * handling the hw-breakpoint. Unregister it and throw a warning * message to let the user know about it. */ if (!stepped) { WARN(1, "Unable to handle hardware breakpoint. Breakpoint at " "0x%lx will be disabled.", info->address); perf_event_disable(bp); goto out; } /* * As a policy, the callback is invoked in a 'trigger-after-execute' * fashion */ if (!info->extraneous_interrupt) perf_bp_event(bp, regs); set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx); out: rcu_read_unlock(); return rc; }