Root/arch/avr32/kernel/kprobes.c

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    __this_cpu_write(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

Archive Download this file



interactive