Blame view

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