aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/kprobes_64.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2008-01-30 07:31:21 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:31:21 -0500
commitda07ab0375897bb9e108b28129df140ecd3ee94e (patch)
tree2d5f0fe4709cd4e6b6dc9f686514ff5f2ded241c /arch/x86/kernel/kprobes_64.c
parentaa470140e86e45723cf8387292edbce9106ddc1f (diff)
x86: return probe-booster for x86-64
This patch adds kretprobe-booster to kprobes_64.c. - Changes are based on x86-32. - Rewrite register saving/restoring code Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/kprobes_64.c')
-rw-r--r--arch/x86/kernel/kprobes_64.c92
1 files changed, 65 insertions, 27 deletions
diff --git a/arch/x86/kernel/kprobes_64.c b/arch/x86/kernel/kprobes_64.c
index bf0e18473677..bc93b1dd9a01 100644
--- a/arch/x86/kernel/kprobes_64.c
+++ b/arch/x86/kernel/kprobes_64.c
@@ -28,6 +28,8 @@
28 * Fixed to handle %rip-relative addressing mode correctly. 28 * Fixed to handle %rip-relative addressing mode correctly.
29 * 2005-May Rusty Lynch <rusty.lynch@intel.com> 29 * 2005-May Rusty Lynch <rusty.lynch@intel.com>
30 * Added function return probes functionality 30 * Added function return probes functionality
31 * 2007-Dec Masami Hiramatsu <mhiramat@redhat.com> added kprobe-booster
32 * and kretprobe-booster for x86-64
31 */ 33 */
32 34
33#include <linux/kprobes.h> 35#include <linux/kprobes.h>
@@ -507,21 +509,65 @@ no_kprobe:
507} 509}
508 510
509/* 511/*
510 * For function-return probes, init_kprobes() establishes a probepoint 512 * When a retprobed function returns, this code saves registers and
511 * here. When a retprobed function returns, this probe is hit and 513 * calls trampoline_handler() runs, which calls the kretprobe's handler.
512 * trampoline_probe_handler() runs, calling the kretprobe's handler.
513 */ 514 */
514 void kretprobe_trampoline_holder(void) 515 void __kprobes kretprobe_trampoline_holder(void)
515 { 516 {
516 asm volatile ( ".global kretprobe_trampoline\n" 517 asm volatile ( ".global kretprobe_trampoline\n"
517 "kretprobe_trampoline: \n" 518 "kretprobe_trampoline: \n"
518 "nop\n"); 519 /* We don't bother saving the ss register */
520 " pushq %rsp\n"
521 " pushfq\n"
522 /*
523 * Skip cs, ip, orig_ax.
524 * trampoline_handler() will plug in these values
525 */
526 " subq $24, %rsp\n"
527 " pushq %rdi\n"
528 " pushq %rsi\n"
529 " pushq %rdx\n"
530 " pushq %rcx\n"
531 " pushq %rax\n"
532 " pushq %r8\n"
533 " pushq %r9\n"
534 " pushq %r10\n"
535 " pushq %r11\n"
536 " pushq %rbx\n"
537 " pushq %rbp\n"
538 " pushq %r12\n"
539 " pushq %r13\n"
540 " pushq %r14\n"
541 " pushq %r15\n"
542 " movq %rsp, %rdi\n"
543 " call trampoline_handler\n"
544 /* Replace saved sp with true return address. */
545 " movq %rax, 152(%rsp)\n"
546 " popq %r15\n"
547 " popq %r14\n"
548 " popq %r13\n"
549 " popq %r12\n"
550 " popq %rbp\n"
551 " popq %rbx\n"
552 " popq %r11\n"
553 " popq %r10\n"
554 " popq %r9\n"
555 " popq %r8\n"
556 " popq %rax\n"
557 " popq %rcx\n"
558 " popq %rdx\n"
559 " popq %rsi\n"
560 " popq %rdi\n"
561 /* Skip orig_ax, ip, cs */
562 " addq $24, %rsp\n"
563 " popfq\n"
564 " ret\n");
519 } 565 }
520 566
521/* 567/*
522 * Called when we hit the probe point at kretprobe_trampoline 568 * Called from kretprobe_trampoline
523 */ 569 */
524int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) 570fastcall void * __kprobes trampoline_handler(struct pt_regs *regs)
525{ 571{
526 struct kretprobe_instance *ri = NULL; 572 struct kretprobe_instance *ri = NULL;
527 struct hlist_head *head, empty_rp; 573 struct hlist_head *head, empty_rp;
@@ -532,6 +578,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
532 INIT_HLIST_HEAD(&empty_rp); 578 INIT_HLIST_HEAD(&empty_rp);
533 spin_lock_irqsave(&kretprobe_lock, flags); 579 spin_lock_irqsave(&kretprobe_lock, flags);
534 head = kretprobe_inst_table_head(current); 580 head = kretprobe_inst_table_head(current);
581 /* fixup rt_regs */
582 regs->cs = __KERNEL_CS;
583 regs->ip = trampoline_address;
584 regs->orig_ax = 0xffffffffffffffff;
535 585
536 /* 586 /*
537 * It is possible to have multiple instances associated with a given 587 * It is possible to have multiple instances associated with a given
@@ -551,8 +601,12 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
551 /* another task is sharing our hash bucket */ 601 /* another task is sharing our hash bucket */
552 continue; 602 continue;
553 603
554 if (ri->rp && ri->rp->handler) 604 if (ri->rp && ri->rp->handler) {
605 __get_cpu_var(current_kprobe) = &ri->rp->kp;
606 get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
555 ri->rp->handler(ri, regs); 607 ri->rp->handler(ri, regs);
608 __get_cpu_var(current_kprobe) = NULL;
609 }
556 610
557 orig_ret_address = (unsigned long)ri->ret_addr; 611 orig_ret_address = (unsigned long)ri->ret_addr;
558 recycle_rp_inst(ri, &empty_rp); 612 recycle_rp_inst(ri, &empty_rp);
@@ -567,22 +621,14 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
567 } 621 }
568 622
569 kretprobe_assert(ri, orig_ret_address, trampoline_address); 623 kretprobe_assert(ri, orig_ret_address, trampoline_address);
570 regs->ip = orig_ret_address;
571 624
572 reset_current_kprobe();
573 spin_unlock_irqrestore(&kretprobe_lock, flags); 625 spin_unlock_irqrestore(&kretprobe_lock, flags);
574 preempt_enable_no_resched();
575 626
576 hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { 627 hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
577 hlist_del(&ri->hlist); 628 hlist_del(&ri->hlist);
578 kfree(ri); 629 kfree(ri);
579 } 630 }
580 /* 631 return (void *)orig_ret_address;
581 * By returning a non-zero value, we are telling
582 * kprobe_handler() that we don't want the post_handler
583 * to run (and have re-enabled preemption)
584 */
585 return 1;
586} 632}
587 633
588/* 634/*
@@ -881,20 +927,12 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
881 return 0; 927 return 0;
882} 928}
883 929
884static struct kprobe trampoline_p = {
885 .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
886 .pre_handler = trampoline_probe_handler
887};
888
889int __init arch_init_kprobes(void) 930int __init arch_init_kprobes(void)
890{ 931{
891 return register_kprobe(&trampoline_p); 932 return 0;
892} 933}
893 934
894int __kprobes arch_trampoline_kprobe(struct kprobe *p) 935int __kprobes arch_trampoline_kprobe(struct kprobe *p)
895{ 936{
896 if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline)
897 return 1;
898
899 return 0; 937 return 0;
900} 938}