diff options
Diffstat (limited to 'arch/sparc64/kernel/kprobes.c')
-rw-r--r-- | arch/sparc64/kernel/kprobes.c | 66 |
1 files changed, 60 insertions, 6 deletions
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c index d91c31870ac8..ffc7309e9f22 100644 --- a/arch/sparc64/kernel/kprobes.c +++ b/arch/sparc64/kernel/kprobes.c | |||
@@ -6,9 +6,11 @@ | |||
6 | #include <linux/config.h> | 6 | #include <linux/config.h> |
7 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
8 | #include <linux/kprobes.h> | 8 | #include <linux/kprobes.h> |
9 | #include <linux/module.h> | ||
9 | #include <asm/kdebug.h> | 10 | #include <asm/kdebug.h> |
10 | #include <asm/signal.h> | 11 | #include <asm/signal.h> |
11 | #include <asm/cacheflush.h> | 12 | #include <asm/cacheflush.h> |
13 | #include <asm/uaccess.h> | ||
12 | 14 | ||
13 | /* We do not have hardware single-stepping on sparc64. | 15 | /* We do not have hardware single-stepping on sparc64. |
14 | * So we implement software single-stepping with breakpoint | 16 | * So we implement software single-stepping with breakpoint |
@@ -302,16 +304,68 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) | |||
302 | { | 304 | { |
303 | struct kprobe *cur = kprobe_running(); | 305 | struct kprobe *cur = kprobe_running(); |
304 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 306 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
307 | const struct exception_table_entry *entry; | ||
308 | |||
309 | switch(kcb->kprobe_status) { | ||
310 | case KPROBE_HIT_SS: | ||
311 | case KPROBE_REENTER: | ||
312 | /* | ||
313 | * We are here because the instruction being single | ||
314 | * stepped caused a page fault. We reset the current | ||
315 | * kprobe and the tpc points back to the probe address | ||
316 | * and allow the page fault handler to continue as a | ||
317 | * normal page fault. | ||
318 | */ | ||
319 | regs->tpc = (unsigned long)cur->addr; | ||
320 | regs->tnpc = kcb->kprobe_orig_tnpc; | ||
321 | regs->tstate = ((regs->tstate & ~TSTATE_PIL) | | ||
322 | kcb->kprobe_orig_tstate_pil); | ||
323 | if (kcb->kprobe_status == KPROBE_REENTER) | ||
324 | restore_previous_kprobe(kcb); | ||
325 | else | ||
326 | reset_current_kprobe(); | ||
327 | preempt_enable_no_resched(); | ||
328 | break; | ||
329 | case KPROBE_HIT_ACTIVE: | ||
330 | case KPROBE_HIT_SSDONE: | ||
331 | /* | ||
332 | * We increment the nmissed count for accounting, | ||
333 | * we can also use npre/npostfault count for accouting | ||
334 | * these specific fault cases. | ||
335 | */ | ||
336 | kprobes_inc_nmissed_count(cur); | ||
337 | |||
338 | /* | ||
339 | * We come here because instructions in the pre/post | ||
340 | * handler caused the page_fault, this could happen | ||
341 | * if handler tries to access user space by | ||
342 | * copy_from_user(), get_user() etc. Let the | ||
343 | * user-specified handler try to fix it first. | ||
344 | */ | ||
345 | if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) | ||
346 | return 1; | ||
305 | 347 | ||
306 | if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) | 348 | /* |
307 | return 1; | 349 | * In case the user-specified fault handler returned |
350 | * zero, try to fix up. | ||
351 | */ | ||
308 | 352 | ||
309 | if (kcb->kprobe_status & KPROBE_HIT_SS) { | 353 | entry = search_exception_tables(regs->tpc); |
310 | resume_execution(cur, regs, kcb); | 354 | if (entry) { |
355 | regs->tpc = entry->fixup; | ||
356 | regs->tnpc = regs->tpc + 4; | ||
357 | return 1; | ||
358 | } | ||
311 | 359 | ||
312 | reset_current_kprobe(); | 360 | /* |
313 | preempt_enable_no_resched(); | 361 | * fixup_exception() could not handle it, |
362 | * Let do_page_fault() fix it. | ||
363 | */ | ||
364 | break; | ||
365 | default: | ||
366 | break; | ||
314 | } | 367 | } |
368 | |||
315 | return 0; | 369 | return 0; |
316 | } | 370 | } |
317 | 371 | ||