linux/arch/ppc64/kernel/kprobes.c
<<
>>
Prefs
   1/*
   2 *  Kernel Probes (KProbes)
   3 *  arch/ppc64/kernel/kprobes.c
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18 *
  19 * Copyright (C) IBM Corporation, 2002, 2004
  20 *
  21 * 2002-Oct     Created by Vamsi Krishna S <vamsi_krishna@in.ibm.com> Kernel
  22 *              Probes initial implementation ( includes contributions from
  23 *              Rusty Russell).
  24 * 2004-July    Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes
  25 *              interface to access function arguments.
  26 * 2004-Nov     Ananth N Mavinakayanahalli <ananth@in.ibm.com> kprobes port
  27 *              for PPC64
  28 */
  29
  30#include <linux/config.h>
  31#include <linux/kprobes.h>
  32#include <linux/ptrace.h>
  33#include <linux/spinlock.h>
  34#include <linux/preempt.h>
  35#include <asm/kdebug.h>
  36#include <asm/sstep.h>
  37
  38/* kprobe_status settings */
  39#define KPROBE_HIT_ACTIVE       0x00000001
  40#define KPROBE_HIT_SS           0x00000002
  41
  42static struct kprobe *current_kprobe;
  43static unsigned long kprobe_status, kprobe_saved_msr;
  44static struct pt_regs jprobe_saved_regs;
  45
  46int arch_prepare_kprobe(struct kprobe *p)
  47{
  48        kprobe_opcode_t insn = *p->addr;
  49
  50        if (IS_MTMSRD(insn) || IS_RFID(insn))
  51                /* cannot put bp on RFID/MTMSRD */
  52                return 1;
  53        return 0;
  54}
  55
  56void arch_copy_kprobe(struct kprobe *p)
  57{
  58        memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
  59}
  60
  61void arch_remove_kprobe(struct kprobe *p)
  62{
  63}
  64
  65static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
  66{
  67        *p->addr = p->opcode;
  68        regs->nip = (unsigned long)p->addr;
  69}
  70
  71static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
  72{
  73        regs->msr |= MSR_SE;
  74        regs->nip = (unsigned long)&p->ainsn.insn;
  75}
  76
  77static inline int kprobe_handler(struct pt_regs *regs)
  78{
  79        struct kprobe *p;
  80        int ret = 0;
  81        unsigned int *addr = (unsigned int *)regs->nip;
  82
  83        /* We're in an interrupt, but this is clear and BUG()-safe. */
  84        preempt_disable();
  85
  86        /* Check we're not actually recursing */
  87        if (kprobe_running()) {
  88                /* We *are* holding lock here, so this is safe.
  89                   Disarm the probe we just hit, and ignore it. */
  90                p = get_kprobe(addr);
  91                if (p) {
  92                        disarm_kprobe(p, regs);
  93                        ret = 1;
  94                } else {
  95                        p = current_kprobe;
  96                        if (p->break_handler && p->break_handler(p, regs)) {
  97                                goto ss_probe;
  98                        }
  99                }
 100                /* If it's not ours, can't be delete race, (we hold lock). */
 101                goto no_kprobe;
 102        }
 103
 104        lock_kprobes();
 105        p = get_kprobe(addr);
 106        if (!p) {
 107                unlock_kprobes();
 108#if 0
 109                if (*addr != BREAKPOINT_INSTRUCTION) {
 110                        /*
 111                         * The breakpoint instruction was removed right
 112                         * after we hit it.  Another cpu has removed
 113                         * either a probepoint or a debugger breakpoint
 114                         * at this address.  In either case, no further
 115                         * handling of this interrupt is appropriate.
 116                         */
 117                        ret = 1;
 118                }
 119#endif
 120                /* Not one of ours: let kernel handle it */
 121                goto no_kprobe;
 122        }
 123
 124        kprobe_status = KPROBE_HIT_ACTIVE;
 125        current_kprobe = p;
 126        kprobe_saved_msr = regs->msr;
 127        if (p->pre_handler(p, regs)) {
 128                /* handler has already set things up, so skip ss setup */
 129                return 1;
 130        }
 131
 132ss_probe:
 133        prepare_singlestep(p, regs);
 134        kprobe_status = KPROBE_HIT_SS;
 135        return 1;
 136
 137no_kprobe:
 138        preempt_enable_no_resched();
 139        return ret;
 140}
 141
 142/*
 143 * Called after single-stepping.  p->addr is the address of the
 144 * instruction whose first byte has been replaced by the "breakpoint"
 145 * instruction.  To avoid the SMP problems that can occur when we
 146 * temporarily put back the original opcode to single-step, we
 147 * single-stepped a copy of the instruction.  The address of this
 148 * copy is p->ainsn.insn.
 149 */
 150static void resume_execution(struct kprobe *p, struct pt_regs *regs)
 151{
 152        int ret;
 153
 154        regs->nip = (unsigned long)p->addr;
 155        ret = emulate_step(regs, p->ainsn.insn[0]);
 156        if (ret == 0)
 157                regs->nip = (unsigned long)p->addr + 4;
 158
 159        regs->msr &= ~MSR_SE;
 160}
 161
 162static inline int post_kprobe_handler(struct pt_regs *regs)
 163{
 164        if (!kprobe_running())
 165                return 0;
 166
 167        if (current_kprobe->post_handler)
 168                current_kprobe->post_handler(current_kprobe, regs, 0);
 169
 170        resume_execution(current_kprobe, regs);
 171        regs->msr |= kprobe_saved_msr;
 172
 173        unlock_kprobes();
 174        preempt_enable_no_resched();
 175
 176        /*
 177         * if somebody else is singlestepping across a probe point, msr
 178         * will have SE set, in which case, continue the remaining processing
 179         * of do_debug, as if this is not a probe hit.
 180         */
 181        if (regs->msr & MSR_SE)
 182                return 0;
 183
 184        return 1;
 185}
 186
 187/* Interrupts disabled, kprobe_lock held. */
 188static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 189{
 190        if (current_kprobe->fault_handler
 191            && current_kprobe->fault_handler(current_kprobe, regs, trapnr))
 192                return 1;
 193
 194        if (kprobe_status & KPROBE_HIT_SS) {
 195                resume_execution(current_kprobe, regs);
 196                regs->msr |= kprobe_saved_msr;
 197
 198                unlock_kprobes();
 199                preempt_enable_no_resched();
 200        }
 201        return 0;
 202}
 203
 204/*
 205 * Wrapper routine to for handling exceptions.
 206 */
 207int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
 208                             void *data)
 209{
 210        struct die_args *args = (struct die_args *)data;
 211        switch (val) {
 212        case DIE_IABR_MATCH:
 213        case DIE_DABR_MATCH:
 214        case DIE_BPT:
 215                if (kprobe_handler(args->regs))
 216                        return NOTIFY_STOP;
 217                break;
 218        case DIE_SSTEP:
 219                if (post_kprobe_handler(args->regs))
 220                        return NOTIFY_STOP;
 221                break;
 222        case DIE_GPF:
 223        case DIE_PAGE_FAULT:
 224                if (kprobe_running() &&
 225                    kprobe_fault_handler(args->regs, args->trapnr))
 226                        return NOTIFY_STOP;
 227                break;
 228        default:
 229                break;
 230        }
 231        return NOTIFY_DONE;
 232}
 233
 234int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 235{
 236        struct jprobe *jp = container_of(p, struct jprobe, kp);
 237
 238        memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs));
 239
 240        /* setup return addr to the jprobe handler routine */
 241        regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry);
 242        regs->gpr[2] = (unsigned long)(((func_descr_t *)jp->entry)->toc);
 243
 244        return 1;
 245}
 246
 247void jprobe_return(void)
 248{
 249        preempt_enable_no_resched();
 250        asm volatile("trap" ::: "memory");
 251}
 252
 253void jprobe_return_end(void)
 254{
 255};
 256
 257int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 258{
 259        /*
 260         * FIXME - we should ideally be validating that we got here 'cos
 261         * of the "trap" in jprobe_return() above, before restoring the
 262         * saved regs...
 263         */
 264        memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
 265        return 1;
 266}
 267
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.