aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sparc64/kernel/kprobes.c131
-rw-r--r--include/asm-sparc64/kprobes.h20
2 files changed, 87 insertions, 64 deletions
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index 755a0d7d887f..b95984154dba 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -38,6 +38,9 @@
38 * - Mark that we are no longer actively in a kprobe. 38 * - Mark that we are no longer actively in a kprobe.
39 */ 39 */
40 40
41DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
42DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
43
41int __kprobes arch_prepare_kprobe(struct kprobe *p) 44int __kprobes arch_prepare_kprobe(struct kprobe *p)
42{ 45{
43 return 0; 46 return 0;
@@ -66,46 +69,39 @@ void __kprobes arch_remove_kprobe(struct kprobe *p)
66{ 69{
67} 70}
68 71
69static struct kprobe *current_kprobe; 72static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb)
70static unsigned long current_kprobe_orig_tnpc;
71static unsigned long current_kprobe_orig_tstate_pil;
72static unsigned int kprobe_status;
73static struct kprobe *kprobe_prev;
74static unsigned long kprobe_orig_tnpc_prev;
75static unsigned long kprobe_orig_tstate_pil_prev;
76static unsigned int kprobe_status_prev;
77
78static inline void save_previous_kprobe(void)
79{ 73{
80 kprobe_status_prev = kprobe_status; 74 kcb->prev_kprobe.kp = kprobe_running();
81 kprobe_orig_tnpc_prev = current_kprobe_orig_tnpc; 75 kcb->prev_kprobe.status = kcb->kprobe_status;
82 kprobe_orig_tstate_pil_prev = current_kprobe_orig_tstate_pil; 76 kcb->prev_kprobe.orig_tnpc = kcb->kprobe_orig_tnpc;
83 kprobe_prev = current_kprobe; 77 kcb->prev_kprobe.orig_tstate_pil = kcb->kprobe_orig_tstate_pil;
84} 78}
85 79
86static inline void restore_previous_kprobe(void) 80static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
87{ 81{
88 kprobe_status = kprobe_status_prev; 82 __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
89 current_kprobe_orig_tnpc = kprobe_orig_tnpc_prev; 83 kcb->kprobe_status = kcb->prev_kprobe.status;
90 current_kprobe_orig_tstate_pil = kprobe_orig_tstate_pil_prev; 84 kcb->kprobe_orig_tnpc = kcb->prev_kprobe.orig_tnpc;
91 current_kprobe = kprobe_prev; 85 kcb->kprobe_orig_tstate_pil = kcb->prev_kprobe.orig_tstate_pil;
92} 86}
93 87
94static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs) 88static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
89 struct kprobe_ctlblk *kcb)
95{ 90{
96 current_kprobe_orig_tnpc = regs->tnpc; 91 __get_cpu_var(current_kprobe) = p;
97 current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL); 92 kcb->kprobe_orig_tnpc = regs->tnpc;
98 current_kprobe = p; 93 kcb->kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL);
99} 94}
100 95
101static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 96static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs,
97 struct kprobe_ctlblk *kcb)
102{ 98{
103 regs->tstate |= TSTATE_PIL; 99 regs->tstate |= TSTATE_PIL;
104 100
105 /*single step inline, if it a breakpoint instruction*/ 101 /*single step inline, if it a breakpoint instruction*/
106 if (p->opcode == BREAKPOINT_INSTRUCTION) { 102 if (p->opcode == BREAKPOINT_INSTRUCTION) {
107 regs->tpc = (unsigned long) p->addr; 103 regs->tpc = (unsigned long) p->addr;
108 regs->tnpc = current_kprobe_orig_tnpc; 104 regs->tnpc = kcb->kprobe_orig_tnpc;
109 } else { 105 } else {
110 regs->tpc = (unsigned long) &p->ainsn.insn[0]; 106 regs->tpc = (unsigned long) &p->ainsn.insn[0];
111 regs->tnpc = (unsigned long) &p->ainsn.insn[1]; 107 regs->tnpc = (unsigned long) &p->ainsn.insn[1];
@@ -117,6 +113,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
117 struct kprobe *p; 113 struct kprobe *p;
118 void *addr = (void *) regs->tpc; 114 void *addr = (void *) regs->tpc;
119 int ret = 0; 115 int ret = 0;
116 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
120 117
121 if (kprobe_running()) { 118 if (kprobe_running()) {
122 /* We *are* holding lock here, so this is safe. 119 /* We *are* holding lock here, so this is safe.
@@ -124,9 +121,9 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
124 */ 121 */
125 p = get_kprobe(addr); 122 p = get_kprobe(addr);
126 if (p) { 123 if (p) {
127 if (kprobe_status == KPROBE_HIT_SS) { 124 if (kcb->kprobe_status == KPROBE_HIT_SS) {
128 regs->tstate = ((regs->tstate & ~TSTATE_PIL) | 125 regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
129 current_kprobe_orig_tstate_pil); 126 kcb->kprobe_orig_tstate_pil);
130 unlock_kprobes(); 127 unlock_kprobes();
131 goto no_kprobe; 128 goto no_kprobe;
132 } 129 }
@@ -136,14 +133,14 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
136 * just single step on the instruction of the new probe 133 * just single step on the instruction of the new probe
137 * without calling any user handlers. 134 * without calling any user handlers.
138 */ 135 */
139 save_previous_kprobe(); 136 save_previous_kprobe(kcb);
140 set_current_kprobe(p, regs); 137 set_current_kprobe(p, regs, kcb);
141 p->nmissed++; 138 p->nmissed++;
142 kprobe_status = KPROBE_REENTER; 139 kcb->kprobe_status = KPROBE_REENTER;
143 prepare_singlestep(p, regs); 140 prepare_singlestep(p, regs, kcb);
144 return 1; 141 return 1;
145 } else { 142 } else {
146 p = current_kprobe; 143 p = __get_cpu_var(current_kprobe);
147 if (p->break_handler && p->break_handler(p, regs)) 144 if (p->break_handler && p->break_handler(p, regs))
148 goto ss_probe; 145 goto ss_probe;
149 } 146 }
@@ -174,14 +171,14 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
174 * in post_kprobes_handler() 171 * in post_kprobes_handler()
175 */ 172 */
176 preempt_disable(); 173 preempt_disable();
177 set_current_kprobe(p, regs); 174 set_current_kprobe(p, regs, kcb);
178 kprobe_status = KPROBE_HIT_ACTIVE; 175 kcb->kprobe_status = KPROBE_HIT_ACTIVE;
179 if (p->pre_handler && p->pre_handler(p, regs)) 176 if (p->pre_handler && p->pre_handler(p, regs))
180 return 1; 177 return 1;
181 178
182ss_probe: 179ss_probe:
183 prepare_singlestep(p, regs); 180 prepare_singlestep(p, regs, kcb);
184 kprobe_status = KPROBE_HIT_SS; 181 kcb->kprobe_status = KPROBE_HIT_SS;
185 return 1; 182 return 1;
186 183
187no_kprobe: 184no_kprobe:
@@ -262,11 +259,12 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
262 * This function prepares to return from the post-single-step 259 * This function prepares to return from the post-single-step
263 * breakpoint trap. 260 * breakpoint trap.
264 */ 261 */
265static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) 262static void __kprobes resume_execution(struct kprobe *p,
263 struct pt_regs *regs, struct kprobe_ctlblk *kcb)
266{ 264{
267 u32 insn = p->ainsn.insn[0]; 265 u32 insn = p->ainsn.insn[0];
268 266
269 regs->tpc = current_kprobe_orig_tnpc; 267 regs->tpc = kcb->kprobe_orig_tnpc;
270 regs->tnpc = relbranch_fixup(insn, 268 regs->tnpc = relbranch_fixup(insn,
271 (unsigned long) p->addr, 269 (unsigned long) p->addr,
272 (unsigned long) &p->ainsn.insn[0], 270 (unsigned long) &p->ainsn.insn[0],
@@ -274,26 +272,30 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
274 retpc_fixup(regs, insn, (unsigned long) p->addr); 272 retpc_fixup(regs, insn, (unsigned long) p->addr);
275 273
276 regs->tstate = ((regs->tstate & ~TSTATE_PIL) | 274 regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
277 current_kprobe_orig_tstate_pil); 275 kcb->kprobe_orig_tstate_pil);
278} 276}
279 277
280static inline int post_kprobe_handler(struct pt_regs *regs) 278static inline int post_kprobe_handler(struct pt_regs *regs)
281{ 279{
282 if (!kprobe_running()) 280 struct kprobe *cur = kprobe_running();
281 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
282
283 if (!cur)
283 return 0; 284 return 0;
284 285
285 if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { 286 if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
286 kprobe_status = KPROBE_HIT_SSDONE; 287 kcb->kprobe_status = KPROBE_HIT_SSDONE;
287 current_kprobe->post_handler(current_kprobe, regs, 0); 288 cur->post_handler(cur, regs, 0);
288 } 289 }
289 290
290 resume_execution(current_kprobe, regs); 291 resume_execution(cur, regs, kcb);
291 292
292 /*Restore back the original saved kprobes variables and continue. */ 293 /*Restore back the original saved kprobes variables and continue. */
293 if (kprobe_status == KPROBE_REENTER) { 294 if (kcb->kprobe_status == KPROBE_REENTER) {
294 restore_previous_kprobe(); 295 restore_previous_kprobe(kcb);
295 goto out; 296 goto out;
296 } 297 }
298 reset_current_kprobe();
297 unlock_kprobes(); 299 unlock_kprobes();
298out: 300out:
299 preempt_enable_no_resched(); 301 preempt_enable_no_resched();
@@ -304,13 +306,16 @@ out:
304/* Interrupts disabled, kprobe_lock held. */ 306/* Interrupts disabled, kprobe_lock held. */
305static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) 307static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
306{ 308{
307 if (current_kprobe->fault_handler 309 struct kprobe *cur = kprobe_running();
308 && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) 310 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
311
312 if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
309 return 1; 313 return 1;
310 314
311 if (kprobe_status & KPROBE_HIT_SS) { 315 if (kcb->kprobe_status & KPROBE_HIT_SS) {
312 resume_execution(current_kprobe, regs); 316 resume_execution(cur, regs, kcb);
313 317
318 reset_current_kprobe();
314 unlock_kprobes(); 319 unlock_kprobes();
315 preempt_enable_no_resched(); 320 preempt_enable_no_resched();
316 } 321 }
@@ -370,24 +375,21 @@ asmlinkage void __kprobes kprobe_trap(unsigned long trap_level,
370} 375}
371 376
372/* Jprobes support. */ 377/* Jprobes support. */
373static struct pt_regs jprobe_saved_regs;
374static struct pt_regs *jprobe_saved_regs_location;
375static struct sparc_stackf jprobe_saved_stack;
376
377int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) 378int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
378{ 379{
379 struct jprobe *jp = container_of(p, struct jprobe, kp); 380 struct jprobe *jp = container_of(p, struct jprobe, kp);
381 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
380 382
381 jprobe_saved_regs_location = regs; 383 kcb->jprobe_saved_regs_location = regs;
382 memcpy(&jprobe_saved_regs, regs, sizeof(*regs)); 384 memcpy(&(kcb->jprobe_saved_regs), regs, sizeof(*regs));
383 385
384 /* Save a whole stack frame, this gets arguments 386 /* Save a whole stack frame, this gets arguments
385 * pushed onto the stack after using up all the 387 * pushed onto the stack after using up all the
386 * arg registers. 388 * arg registers.
387 */ 389 */
388 memcpy(&jprobe_saved_stack, 390 memcpy(&(kcb->jprobe_saved_stack),
389 (char *) (regs->u_regs[UREG_FP] + STACK_BIAS), 391 (char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
390 sizeof(jprobe_saved_stack)); 392 sizeof(kcb->jprobe_saved_stack));
391 393
392 regs->tpc = (unsigned long) jp->entry; 394 regs->tpc = (unsigned long) jp->entry;
393 regs->tnpc = ((unsigned long) jp->entry) + 0x4UL; 395 regs->tnpc = ((unsigned long) jp->entry) + 0x4UL;
@@ -411,14 +413,15 @@ extern void __show_regs(struct pt_regs * regs);
411int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) 413int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
412{ 414{
413 u32 *addr = (u32 *) regs->tpc; 415 u32 *addr = (u32 *) regs->tpc;
416 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
414 417
415 if (addr == (u32 *) jprobe_return_trap_instruction) { 418 if (addr == (u32 *) jprobe_return_trap_instruction) {
416 if (jprobe_saved_regs_location != regs) { 419 if (kcb->jprobe_saved_regs_location != regs) {
417 printk("JPROBE: Current regs (%p) does not match " 420 printk("JPROBE: Current regs (%p) does not match "
418 "saved regs (%p).\n", 421 "saved regs (%p).\n",
419 regs, jprobe_saved_regs_location); 422 regs, kcb->jprobe_saved_regs_location);
420 printk("JPROBE: Saved registers\n"); 423 printk("JPROBE: Saved registers\n");
421 __show_regs(jprobe_saved_regs_location); 424 __show_regs(kcb->jprobe_saved_regs_location);
422 printk("JPROBE: Current registers\n"); 425 printk("JPROBE: Current registers\n");
423 __show_regs(regs); 426 __show_regs(regs);
424 BUG(); 427 BUG();
@@ -427,11 +430,11 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
427 * first so that UREG_FP is the original one for 430 * first so that UREG_FP is the original one for
428 * the stack frame restore. 431 * the stack frame restore.
429 */ 432 */
430 memcpy(regs, &jprobe_saved_regs, sizeof(*regs)); 433 memcpy(regs, &(kcb->jprobe_saved_regs), sizeof(*regs));
431 434
432 memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS), 435 memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
433 &jprobe_saved_stack, 436 &(kcb->jprobe_saved_stack),
434 sizeof(jprobe_saved_stack)); 437 sizeof(kcb->jprobe_saved_stack));
435 438
436 return 1; 439 return 1;
437 } 440 }
diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h
index a8d326a598f0..7ba845320f5c 100644
--- a/include/asm-sparc64/kprobes.h
+++ b/include/asm-sparc64/kprobes.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/config.h> 4#include <linux/config.h>
5#include <linux/types.h> 5#include <linux/types.h>
6#include <linux/percpu.h>
6 7
7typedef u32 kprobe_opcode_t; 8typedef u32 kprobe_opcode_t;
8 9
@@ -18,6 +19,25 @@ struct arch_specific_insn {
18 kprobe_opcode_t insn[MAX_INSN_SIZE]; 19 kprobe_opcode_t insn[MAX_INSN_SIZE];
19}; 20};
20 21
22struct prev_kprobe {
23 struct kprobe *kp;
24 unsigned int status;
25 unsigned long orig_tnpc;
26 unsigned long orig_tstate_pil;
27};
28
29/* per-cpu kprobe control block */
30struct kprobe_ctlblk {
31 unsigned long kprobe_status;
32 unsigned long kprobe_orig_tnpc;
33 unsigned long kprobe_orig_tstate_pil;
34 long *jprobe_saved_esp;
35 struct pt_regs jprobe_saved_regs;
36 struct pt_regs *jprobe_saved_regs_location;
37 struct sparc_stackf jprobe_saved_stack;
38 struct prev_kprobe prev_kprobe;
39};
40
21#ifdef CONFIG_KPROBES 41#ifdef CONFIG_KPROBES
22extern int kprobe_exceptions_notify(struct notifier_block *self, 42extern int kprobe_exceptions_notify(struct notifier_block *self,
23 unsigned long val, void *data); 43 unsigned long val, void *data);