linux/arch/powerpc/kernel/uprobes.c
<<
>>
Prefs
   1/*
   2 * User-space Probes (UProbes) for powerpc
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17 *
  18 * Copyright IBM Corporation, 2007-2012
  19 *
  20 * Adapted from the x86 port by Ananth N Mavinakayanahalli <ananth@in.ibm.com>
  21 */
  22#include <linux/kernel.h>
  23#include <linux/sched.h>
  24#include <linux/ptrace.h>
  25#include <linux/uprobes.h>
  26#include <linux/uaccess.h>
  27#include <linux/kdebug.h>
  28
  29#include <asm/sstep.h>
  30
  31#define UPROBE_TRAP_NR  UINT_MAX
  32
  33/**
  34 * is_trap_insn - check if the instruction is a trap variant
  35 * @insn: instruction to be checked.
  36 * Returns true if @insn is a trap variant.
  37 */
  38bool is_trap_insn(uprobe_opcode_t *insn)
  39{
  40        return (is_trap(*insn));
  41}
  42
  43/**
  44 * arch_uprobe_analyze_insn
  45 * @mm: the probed address space.
  46 * @arch_uprobe: the probepoint information.
  47 * @addr: vaddr to probe.
  48 * Return 0 on success or a -ve number on error.
  49 */
  50int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
  51                struct mm_struct *mm, unsigned long addr)
  52{
  53        if (addr & 0x03)
  54                return -EINVAL;
  55
  56        return 0;
  57}
  58
  59/*
  60 * arch_uprobe_pre_xol - prepare to execute out of line.
  61 * @auprobe: the probepoint information.
  62 * @regs: reflects the saved user state of current task.
  63 */
  64int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
  65{
  66        struct arch_uprobe_task *autask = &current->utask->autask;
  67
  68        autask->saved_trap_nr = current->thread.trap_nr;
  69        current->thread.trap_nr = UPROBE_TRAP_NR;
  70        regs->nip = current->utask->xol_vaddr;
  71
  72        user_enable_single_step(current);
  73        return 0;
  74}
  75
  76/**
  77 * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs
  78 * @regs: Reflects the saved state of the task after it has hit a breakpoint
  79 * instruction.
  80 * Return the address of the breakpoint instruction.
  81 */
  82unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
  83{
  84        return instruction_pointer(regs);
  85}
  86
  87/*
  88 * If xol insn itself traps and generates a signal (SIGILL/SIGSEGV/etc),
  89 * then detect the case where a singlestepped instruction jumps back to its
  90 * own address. It is assumed that anything like do_page_fault/do_trap/etc
  91 * sets thread.trap_nr != UINT_MAX.
  92 *
  93 * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr,
  94 * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to
  95 * UPROBE_TRAP_NR == UINT_MAX set by arch_uprobe_pre_xol().
  96 */
  97bool arch_uprobe_xol_was_trapped(struct task_struct *t)
  98{
  99        if (t->thread.trap_nr != UPROBE_TRAP_NR)
 100                return true;
 101
 102        return false;
 103}
 104
 105/*
 106 * Called after single-stepping. To avoid the SMP problems that can
 107 * occur when we temporarily put back the original opcode to
 108 * single-step, we single-stepped a copy of the instruction.
 109 *
 110 * This function prepares to resume execution after the single-step.
 111 */
 112int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
 113{
 114        struct uprobe_task *utask = current->utask;
 115
 116        WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
 117
 118        current->thread.trap_nr = utask->autask.saved_trap_nr;
 119
 120        /*
 121         * On powerpc, except for loads and stores, most instructions
 122         * including ones that alter code flow (branches, calls, returns)
 123         * are emulated in the kernel. We get here only if the emulation
 124         * support doesn't exist and have to fix-up the next instruction
 125         * to be executed.
 126         */
 127        regs->nip = utask->vaddr + MAX_UINSN_BYTES;
 128
 129        user_disable_single_step(current);
 130        return 0;
 131}
 132
 133/* callback routine for handling exceptions. */
 134int arch_uprobe_exception_notify(struct notifier_block *self,
 135                                unsigned long val, void *data)
 136{
 137        struct die_args *args = data;
 138        struct pt_regs *regs = args->regs;
 139
 140        /* regs == NULL is a kernel bug */
 141        if (WARN_ON(!regs))
 142                return NOTIFY_DONE;
 143
 144        /* We are only interested in userspace traps */
 145        if (!user_mode(regs))
 146                return NOTIFY_DONE;
 147
 148        switch (val) {
 149        case DIE_BPT:
 150                if (uprobe_pre_sstep_notifier(regs))
 151                        return NOTIFY_STOP;
 152                break;
 153        case DIE_SSTEP:
 154                if (uprobe_post_sstep_notifier(regs))
 155                        return NOTIFY_STOP;
 156        default:
 157                break;
 158        }
 159        return NOTIFY_DONE;
 160}
 161
 162/*
 163 * This function gets called when XOL instruction either gets trapped or
 164 * the thread has a fatal signal, so reset the instruction pointer to its
 165 * probed address.
 166 */
 167void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
 168{
 169        struct uprobe_task *utask = current->utask;
 170
 171        current->thread.trap_nr = utask->autask.saved_trap_nr;
 172        instruction_pointer_set(regs, utask->vaddr);
 173
 174        user_disable_single_step(current);
 175}
 176
 177/*
 178 * See if the instruction can be emulated.
 179 * Returns true if instruction was emulated, false otherwise.
 180 */
 181bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
 182{
 183        int ret;
 184
 185        /*
 186         * emulate_step() returns 1 if the insn was successfully emulated.
 187         * For all other cases, we need to single-step in hardware.
 188         */
 189        ret = emulate_step(regs, auprobe->insn);
 190        if (ret > 0)
 191                return true;
 192
 193        return false;
 194}
 195
 196unsigned long
 197arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
 198{
 199        unsigned long orig_ret_vaddr;
 200
 201        orig_ret_vaddr = regs->link;
 202
 203        /* Replace the return addr with trampoline addr */
 204        regs->link = trampoline_vaddr;
 205
 206        return orig_ret_vaddr;
 207}
 208