diff options
| -rw-r--r-- | arch/sparc64/kernel/kprobes.c | 113 | ||||
| -rw-r--r-- | include/asm-sparc64/kprobes.h | 4 |
2 files changed, 115 insertions, 2 deletions
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c index d94f901d321e..34fc3ddd5002 100644 --- a/arch/sparc64/kernel/kprobes.c +++ b/arch/sparc64/kernel/kprobes.c | |||
| @@ -480,8 +480,117 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 480 | return 0; | 480 | return 0; |
| 481 | } | 481 | } |
| 482 | 482 | ||
| 483 | /* architecture specific initialization */ | 483 | /* Called with kretprobe_lock held. The value stored in the return |
| 484 | int arch_init_kprobes(void) | 484 | * address register is actually 2 instructions before where the |
| 485 | * callee will return to. Sequences usually look something like this | ||
| 486 | * | ||
| 487 | * call some_function <--- return register points here | ||
| 488 | * nop <--- call delay slot | ||
| 489 | * whatever <--- where callee returns to | ||
| 490 | * | ||
| 491 | * To keep trampoline_probe_handler logic simpler, we normalize the | ||
| 492 | * value kept in ri->ret_addr so we don't need to keep adjusting it | ||
| 493 | * back and forth. | ||
| 494 | */ | ||
| 495 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, | ||
| 496 | struct pt_regs *regs) | ||
| 497 | { | ||
| 498 | ri->ret_addr = (kprobe_opcode_t *)(regs->u_regs[UREG_RETPC] + 8); | ||
| 499 | |||
| 500 | /* Replace the return addr with trampoline addr */ | ||
| 501 | regs->u_regs[UREG_RETPC] = | ||
| 502 | ((unsigned long)kretprobe_trampoline) - 8; | ||
| 503 | } | ||
| 504 | |||
| 505 | /* | ||
| 506 | * Called when the probe at kretprobe trampoline is hit | ||
| 507 | */ | ||
| 508 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | ||
| 509 | { | ||
| 510 | struct kretprobe_instance *ri = NULL; | ||
| 511 | struct hlist_head *head, empty_rp; | ||
| 512 | struct hlist_node *node, *tmp; | ||
| 513 | unsigned long flags, orig_ret_address = 0; | ||
| 514 | unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; | ||
| 515 | |||
| 516 | INIT_HLIST_HEAD(&empty_rp); | ||
| 517 | spin_lock_irqsave(&kretprobe_lock, flags); | ||
| 518 | head = kretprobe_inst_table_head(current); | ||
| 519 | |||
| 520 | /* | ||
| 521 | * It is possible to have multiple instances associated with a given | ||
| 522 | * task either because an multiple functions in the call path | ||
| 523 | * have a return probe installed on them, and/or more then one return | ||
| 524 | * return probe was registered for a target function. | ||
| 525 | * | ||
| 526 | * We can handle this because: | ||
| 527 | * - instances are always inserted at the head of the list | ||
| 528 | * - when multiple return probes are registered for the same | ||
| 529 | * function, the first instance's ret_addr will point to the | ||
| 530 | * real return address, and all the rest will point to | ||
| 531 | * kretprobe_trampoline | ||
| 532 | */ | ||
| 533 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | ||
| 534 | if (ri->task != current) | ||
| 535 | /* another task is sharing our hash bucket */ | ||
| 536 | continue; | ||
| 537 | |||
| 538 | if (ri->rp && ri->rp->handler) | ||
| 539 | ri->rp->handler(ri, regs); | ||
| 540 | |||
| 541 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
| 542 | recycle_rp_inst(ri, &empty_rp); | ||
| 543 | |||
| 544 | if (orig_ret_address != trampoline_address) | ||
| 545 | /* | ||
| 546 | * This is the real return address. Any other | ||
| 547 | * instances associated with this task are for | ||
| 548 | * other calls deeper on the call stack | ||
| 549 | */ | ||
| 550 | break; | ||
| 551 | } | ||
| 552 | |||
| 553 | kretprobe_assert(ri, orig_ret_address, trampoline_address); | ||
| 554 | regs->tpc = orig_ret_address; | ||
| 555 | regs->tnpc = orig_ret_address + 4; | ||
| 556 | |||
| 557 | reset_current_kprobe(); | ||
| 558 | spin_unlock_irqrestore(&kretprobe_lock, flags); | ||
| 559 | preempt_enable_no_resched(); | ||
| 560 | |||
| 561 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { | ||
| 562 | hlist_del(&ri->hlist); | ||
| 563 | kfree(ri); | ||
| 564 | } | ||
| 565 | /* | ||
| 566 | * By returning a non-zero value, we are telling | ||
| 567 | * kprobe_handler() that we don't want the post_handler | ||
| 568 | * to run (and have re-enabled preemption) | ||
| 569 | */ | ||
| 570 | return 1; | ||
| 571 | } | ||
| 572 | |||
| 573 | void kretprobe_trampoline_holder(void) | ||
| 574 | { | ||
| 575 | asm volatile(".global kretprobe_trampoline\n" | ||
| 576 | "kretprobe_trampoline:\n" | ||
| 577 | "\tnop\n" | ||
| 578 | "\tnop\n"); | ||
| 579 | } | ||
| 580 | static struct kprobe trampoline_p = { | ||
| 581 | .addr = (kprobe_opcode_t *) &kretprobe_trampoline, | ||
| 582 | .pre_handler = trampoline_probe_handler | ||
| 583 | }; | ||
| 584 | |||
| 585 | int __init arch_init_kprobes(void) | ||
| 485 | { | 586 | { |
| 587 | return register_kprobe(&trampoline_p); | ||
| 588 | } | ||
| 589 | |||
| 590 | int __kprobes arch_trampoline_kprobe(struct kprobe *p) | ||
| 591 | { | ||
| 592 | if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline) | ||
| 593 | return 1; | ||
| 594 | |||
| 486 | return 0; | 595 | return 0; |
| 487 | } | 596 | } |
diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h index 5020eaf67c29..7237dd87663e 100644 --- a/include/asm-sparc64/kprobes.h +++ b/include/asm-sparc64/kprobes.h | |||
| @@ -14,11 +14,15 @@ typedef u32 kprobe_opcode_t; | |||
| 14 | 14 | ||
| 15 | #define arch_remove_kprobe(p) do {} while (0) | 15 | #define arch_remove_kprobe(p) do {} while (0) |
| 16 | 16 | ||
| 17 | #define ARCH_SUPPORTS_KRETPROBES | ||
| 18 | |||
| 17 | #define flush_insn_slot(p) \ | 19 | #define flush_insn_slot(p) \ |
| 18 | do { flushi(&(p)->ainsn.insn[0]); \ | 20 | do { flushi(&(p)->ainsn.insn[0]); \ |
| 19 | flushi(&(p)->ainsn.insn[1]); \ | 21 | flushi(&(p)->ainsn.insn[1]); \ |
| 20 | } while (0) | 22 | } while (0) |
| 21 | 23 | ||
| 24 | void kretprobe_trampoline(void); | ||
| 25 | |||
| 22 | /* Architecture specific copy of original instruction*/ | 26 | /* Architecture specific copy of original instruction*/ |
| 23 | struct arch_specific_insn { | 27 | struct arch_specific_insn { |
| 24 | /* copy of the original instruction */ | 28 | /* copy of the original instruction */ |
