linux/arch/avr32/kernel/kprobes.c
<<
>>
Prefs
   1/*
   2 *  Kernel Probes (KProbes)
   3 *
   4 * Copyright (C) 2005-2006 Atmel Corporation
   5 *
   6 * Based on arch/ppc64/kernel/kprobes.c
   7 *  Copyright (C) IBM Corporation, 2002, 2004
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13
  14#include <linux/kprobes.h>
  15#include <linux/ptrace.h>
  16
  17#include <asm/cacheflush.h>
  18#include <linux/kdebug.h>
  19#include <asm/ocd.h>
  20
  21DEFINE_PER_CPU(struct kprobe *, current_kprobe);
  22static unsigned long kprobe_status;
  23static struct pt_regs jprobe_saved_regs;
  24
  25struct kretprobe_blackpoint kretprobe_blacklist[] = {{NULL, NULL}};
  26
  27int __kprobes arch_prepare_kprobe(struct kprobe *p)
  28{
  29        int ret = 0;
  30
  31        if ((unsigned long)p->addr & 0x01) {
  32                printk("Attempt to register kprobe at an unaligned address\n");
  33                ret = -EINVAL;
  34        }
  35
  36        /* XXX: Might be a good idea to check if p->addr is a valid
  37         * kernel address as well... */
  38
  39        if (!ret) {
  40                pr_debug("copy kprobe at %p\n", p->addr);
  41                memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
  42                p->opcode = *p->addr;
  43        }
  44
  45        return ret;
  46}
  47
  48void __kprobes arch_arm_kprobe(struct kprobe *p)
  49{
  50        pr_debug("arming kprobe at %p\n", p->addr);
  51        ocd_enable(NULL);
  52        *p->addr = BREAKPOINT_INSTRUCTION;
  53        flush_icache_range((unsigned long)p->addr,
  54                           (unsigned long)p->addr + sizeof(kprobe_opcode_t));
  55}
  56
  57void __kprobes arch_disarm_kprobe(struct kprobe *p)
  58{
  59        pr_debug("disarming kprobe at %p\n", p->addr);
  60        ocd_disable(NULL);
  61        *p->addr = p->opcode;
  62        flush_icache_range((unsigned long)p->addr,
  63                           (unsigned long)p->addr + sizeof(kprobe_opcode_t));
  64}
  65
  66static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
  67{
  68        unsigned long dc;
  69
  70        pr_debug("preparing to singlestep over %p (PC=%08lx)\n",
  71                 p->addr, regs->pc);
  72
  73        BUG_ON(!(sysreg_read(SR) & SYSREG_BIT(SR_D)));
  74
  75        dc = ocd_read(DC);
  76        dc |= 1 << OCD_DC_SS_BIT;
  77        ocd_write(DC, dc);
  78
  79        /*
  80         * We must run the instruction from its original location
  81         * since it may actually reference PC.
  82         *
  83         * TODO: Do the instruction replacement directly in icache.
  84         */
  85        *p->addr = p->opcode;
  86        flush_icache_range((unsigned long)p->addr,
  87                           (unsigned long)p->addr + sizeof(kprobe_opcode_t));
  88}
  89
  90static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
  91{
  92        unsigned long dc;
  93
  94        pr_debug("resuming execution at PC=%08lx\n", regs->pc);
  95
  96        dc = ocd_read(DC);
  97        dc &= ~(1 << OCD_DC_SS_BIT);
  98        ocd_write(DC, dc);
  99
 100        *p->addr = BREAKPOINT_INSTRUCTION;
 101        flush_icache_range((unsigned long)p->addr,
 102                           (unsigned long)p->addr + sizeof(kprobe_opcode_t));
 103}
 104
 105static void __kprobes set_current_kprobe(struct kprobe *p)
 106{
 107        __get_cpu_var(current_kprobe) = p;
 108}
 109
 110static int __kprobes kprobe_handler(struct pt_regs *regs)
 111{
 112        struct kprobe *p;
 113        void *addr = (void *)regs->pc;
 114        int ret = 0;
 115
 116        pr_debug("kprobe_handler: kprobe_running=%p\n",
 117                 kprobe_running());
 118
 119        /*
 120         * We don't want to be preempted for the entire
 121         * duration of kprobe processing
 122         */
 123        preempt_disable();
 124
 125        /* Check that we're not recursing */
 126        if (kprobe_running()) {
 127                p = get_kprobe(addr);
 128                if (p) {
 129                        if (kprobe_status == KPROBE_HIT_SS) {
 130                                printk("FIXME: kprobe hit while single-stepping!\n");
 131                                goto no_kprobe;
 132                        }
 133
 134                        printk("FIXME: kprobe hit while handling another kprobe\n");
 135                        goto no_kprobe;
 136                } else {
 137                        p = kprobe_running();
 138                        if (p->break_handler && p->break_handler(p, regs))
 139                                goto ss_probe;
 140                }
 141                /* If it's not ours, can't be delete race, (we hold lock). */
 142                goto no_kprobe;
 143        }
 144
 145        p = get_kprobe(addr);
 146        if (!p)
 147                goto no_kprobe;
 148
 149        kprobe_status = KPROBE_HIT_ACTIVE;
 150        set_current_kprobe(p);
 151        if (p->pre_handler && p->pre_handler(p, regs))
 152                /* handler has already set things up, so skip ss setup */
 153                return 1;
 154
 155ss_probe:
 156        prepare_singlestep(p, regs);
 157        kprobe_status = KPROBE_HIT_SS;
 158        return 1;
 159
 160no_kprobe:
 161        preempt_enable_no_resched();
 162        return ret;
 163}
 164
 165static int __kprobes post_kprobe_handler(struct pt_regs *regs)
 166{
 167        struct kprobe *cur = kprobe_running();
 168
 169        pr_debug("post_kprobe_handler, cur=%p\n", cur);
 170
 171        if (!cur)
 172                return 0;
 173
 174        if (cur->post_handler) {
 175                kprobe_status = KPROBE_HIT_SSDONE;
 176                cur->post_handler(cur, regs, 0);
 177        }
 178
 179        resume_execution(cur, regs);
 180        reset_current_kprobe();
 181        preempt_enable_no_resched();
 182
 183        return 1;
 184}
 185
 186int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 187{
 188        struct kprobe *cur = kprobe_running();
 189
 190        pr_debug("kprobe_fault_handler: trapnr=%d\n", trapnr);
 191
 192        if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
 193                return 1;
 194
 195        if (kprobe_status & KPROBE_HIT_SS) {
 196                resume_execution(cur, regs);
 197                preempt_enable_no_resched();
 198        }
 199        return 0;
 200}
 201
 202/*
 203 * Wrapper routine to for handling exceptions.
 204 */
 205int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
 206                                       unsigned long val, void *data)
 207{
 208        struct die_args *args = (struct die_args *)data;
 209        int ret = NOTIFY_DONE;
 210
 211        pr_debug("kprobe_exceptions_notify: val=%lu, data=%p\n",
 212                 val, data);
 213
 214        switch (val) {
 215        case DIE_BREAKPOINT:
 216                if (kprobe_handler(args->regs))
 217                        ret = NOTIFY_STOP;
 218                break;
 219        case DIE_SSTEP:
 220                if (post_kprobe_handler(args->regs))
 221                        ret = NOTIFY_STOP;
 222                break;
 223        default:
 224                break;
 225        }
 226
 227        return ret;
 228}
 229
 230int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 231{
 232        struct jprobe *jp = container_of(p, struct jprobe, kp);
 233
 234        memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs));
 235
 236        /*
 237         * TODO: We should probably save some of the stack here as
 238         * well, since gcc may pass arguments on the stack for certain
 239         * functions (lots of arguments, large aggregates, varargs)
 240         */
 241
 242        /* setup return addr to the jprobe handler routine */
 243        regs->pc = (unsigned long)jp->entry;
 244        return 1;
 245}
 246
 247void __kprobes jprobe_return(void)
 248{
 249        asm volatile("breakpoint" ::: "memory");
 250}
 251
 252int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 253{
 254        /*
 255         * FIXME - we should ideally be validating that we got here 'cos
 256         * of the "trap" in jprobe_return() above, before restoring the
 257         * saved regs...
 258         */
 259        memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
 260        return 1;
 261}
 262
 263int __init arch_init_kprobes(void)
 264{
 265        /* TODO: Register kretprobe trampoline */
 266        return 0;
 267}
 268