diff options
author | Abhishek Sagar <sagar.abhishek@gmail.com> | 2008-02-06 04:38:22 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-06 13:41:11 -0500 |
commit | f47cd9b553aaada602449204513b5a5b29cba263 (patch) | |
tree | 079ddd399b1aa00a8c413ef51f3b8681a19a6e7e | |
parent | 5beec4aa2ac261b0b4992fb41df40a7ab91e4fad (diff) |
kprobes: kretprobe user entry-handler
Provide support to add an optional user defined callback to be run at
function entry of a kretprobe'd function. Also modify the kprobe smoke
tests to include an entry-handler during the kretprobe sanity test.
Signed-off-by: Abhishek Sagar <sagar.abhishek@gmail.com>
Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Acked-by: Jim Keniston <jkenisto@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | Documentation/kprobes.txt | 81 | ||||
-rw-r--r-- | include/linux/kprobes.h | 3 | ||||
-rw-r--r-- | kernel/kprobes.c | 9 | ||||
-rw-r--r-- | kernel/test_kprobes.c | 16 |
4 files changed, 94 insertions, 15 deletions
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 53a63890aea4..30c101761d0d 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt | |||
@@ -96,7 +96,9 @@ or in registers (e.g., for x86_64 or for an i386 fastcall function). | |||
96 | The jprobe will work in either case, so long as the handler's | 96 | The jprobe will work in either case, so long as the handler's |
97 | prototype matches that of the probed function. | 97 | prototype matches that of the probed function. |
98 | 98 | ||
99 | 1.3 How Does a Return Probe Work? | 99 | 1.3 Return Probes |
100 | |||
101 | 1.3.1 How Does a Return Probe Work? | ||
100 | 102 | ||
101 | When you call register_kretprobe(), Kprobes establishes a kprobe at | 103 | When you call register_kretprobe(), Kprobes establishes a kprobe at |
102 | the entry to the function. When the probed function is called and this | 104 | the entry to the function. When the probed function is called and this |
@@ -107,9 +109,9 @@ At boot time, Kprobes registers a kprobe at the trampoline. | |||
107 | 109 | ||
108 | When the probed function executes its return instruction, control | 110 | When the probed function executes its return instruction, control |
109 | passes to the trampoline and that probe is hit. Kprobes' trampoline | 111 | passes to the trampoline and that probe is hit. Kprobes' trampoline |
110 | handler calls the user-specified handler associated with the kretprobe, | 112 | handler calls the user-specified return handler associated with the |
111 | then sets the saved instruction pointer to the saved return address, | 113 | kretprobe, then sets the saved instruction pointer to the saved return |
112 | and that's where execution resumes upon return from the trap. | 114 | address, and that's where execution resumes upon return from the trap. |
113 | 115 | ||
114 | While the probed function is executing, its return address is | 116 | While the probed function is executing, its return address is |
115 | stored in an object of type kretprobe_instance. Before calling | 117 | stored in an object of type kretprobe_instance. Before calling |
@@ -131,6 +133,30 @@ zero when the return probe is registered, and is incremented every | |||
131 | time the probed function is entered but there is no kretprobe_instance | 133 | time the probed function is entered but there is no kretprobe_instance |
132 | object available for establishing the return probe. | 134 | object available for establishing the return probe. |
133 | 135 | ||
136 | 1.3.2 Kretprobe entry-handler | ||
137 | |||
138 | Kretprobes also provides an optional user-specified handler which runs | ||
139 | on function entry. This handler is specified by setting the entry_handler | ||
140 | field of the kretprobe struct. Whenever the kprobe placed by kretprobe at the | ||
141 | function entry is hit, the user-defined entry_handler, if any, is invoked. | ||
142 | If the entry_handler returns 0 (success) then a corresponding return handler | ||
143 | is guaranteed to be called upon function return. If the entry_handler | ||
144 | returns a non-zero error then Kprobes leaves the return address as is, and | ||
145 | the kretprobe has no further effect for that particular function instance. | ||
146 | |||
147 | Multiple entry and return handler invocations are matched using the unique | ||
148 | kretprobe_instance object associated with them. Additionally, a user | ||
149 | may also specify per return-instance private data to be part of each | ||
150 | kretprobe_instance object. This is especially useful when sharing private | ||
151 | data between corresponding user entry and return handlers. The size of each | ||
152 | private data object can be specified at kretprobe registration time by | ||
153 | setting the data_size field of the kretprobe struct. This data can be | ||
154 | accessed through the data field of each kretprobe_instance object. | ||
155 | |||
156 | In case probed function is entered but there is no kretprobe_instance | ||
157 | object available, then in addition to incrementing the nmissed count, | ||
158 | the user entry_handler invocation is also skipped. | ||
159 | |||
134 | 2. Architectures Supported | 160 | 2. Architectures Supported |
135 | 161 | ||
136 | Kprobes, jprobes, and return probes are implemented on the following | 162 | Kprobes, jprobes, and return probes are implemented on the following |
@@ -274,6 +300,8 @@ of interest: | |||
274 | - ret_addr: the return address | 300 | - ret_addr: the return address |
275 | - rp: points to the corresponding kretprobe object | 301 | - rp: points to the corresponding kretprobe object |
276 | - task: points to the corresponding task struct | 302 | - task: points to the corresponding task struct |
303 | - data: points to per return-instance private data; see "Kretprobe | ||
304 | entry-handler" for details. | ||
277 | 305 | ||
278 | The regs_return_value(regs) macro provides a simple abstraction to | 306 | The regs_return_value(regs) macro provides a simple abstraction to |
279 | extract the return value from the appropriate register as defined by | 307 | extract the return value from the appropriate register as defined by |
@@ -556,23 +584,52 @@ report failed calls to sys_open(). | |||
556 | #include <linux/kernel.h> | 584 | #include <linux/kernel.h> |
557 | #include <linux/module.h> | 585 | #include <linux/module.h> |
558 | #include <linux/kprobes.h> | 586 | #include <linux/kprobes.h> |
587 | #include <linux/ktime.h> | ||
588 | |||
589 | /* per-instance private data */ | ||
590 | struct my_data { | ||
591 | ktime_t entry_stamp; | ||
592 | }; | ||
559 | 593 | ||
560 | static const char *probed_func = "sys_open"; | 594 | static const char *probed_func = "sys_open"; |
561 | 595 | ||
562 | /* Return-probe handler: If the probed function fails, log the return value. */ | 596 | /* Timestamp function entry. */ |
563 | static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | 597 | static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) |
598 | { | ||
599 | struct my_data *data; | ||
600 | |||
601 | if(!current->mm) | ||
602 | return 1; /* skip kernel threads */ | ||
603 | |||
604 | data = (struct my_data *)ri->data; | ||
605 | data->entry_stamp = ktime_get(); | ||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | /* If the probed function failed, log the return value and duration. | ||
610 | * Duration may turn out to be zero consistently, depending upon the | ||
611 | * granularity of time accounting on the platform. */ | ||
612 | static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | ||
564 | { | 613 | { |
565 | int retval = regs_return_value(regs); | 614 | int retval = regs_return_value(regs); |
615 | struct my_data *data = (struct my_data *)ri->data; | ||
616 | s64 delta; | ||
617 | ktime_t now; | ||
618 | |||
566 | if (retval < 0) { | 619 | if (retval < 0) { |
567 | printk("%s returns %d\n", probed_func, retval); | 620 | now = ktime_get(); |
621 | delta = ktime_to_ns(ktime_sub(now, data->entry_stamp)); | ||
622 | printk("%s: return val = %d (duration = %lld ns)\n", | ||
623 | probed_func, retval, delta); | ||
568 | } | 624 | } |
569 | return 0; | 625 | return 0; |
570 | } | 626 | } |
571 | 627 | ||
572 | static struct kretprobe my_kretprobe = { | 628 | static struct kretprobe my_kretprobe = { |
573 | .handler = ret_handler, | 629 | .handler = return_handler, |
574 | /* Probe up to 20 instances concurrently. */ | 630 | .entry_handler = entry_handler, |
575 | .maxactive = 20 | 631 | .data_size = sizeof(struct my_data), |
632 | .maxactive = 20, /* probe up to 20 instances concurrently */ | ||
576 | }; | 633 | }; |
577 | 634 | ||
578 | static int __init kretprobe_init(void) | 635 | static int __init kretprobe_init(void) |
@@ -584,7 +641,7 @@ static int __init kretprobe_init(void) | |||
584 | printk("register_kretprobe failed, returned %d\n", ret); | 641 | printk("register_kretprobe failed, returned %d\n", ret); |
585 | return -1; | 642 | return -1; |
586 | } | 643 | } |
587 | printk("Planted return probe at %p\n", my_kretprobe.kp.addr); | 644 | printk("Kretprobe active on %s\n", my_kretprobe.kp.symbol_name); |
588 | return 0; | 645 | return 0; |
589 | } | 646 | } |
590 | 647 | ||
@@ -594,7 +651,7 @@ static void __exit kretprobe_exit(void) | |||
594 | printk("kretprobe unregistered\n"); | 651 | printk("kretprobe unregistered\n"); |
595 | /* nmissed > 0 suggests that maxactive was set too low. */ | 652 | /* nmissed > 0 suggests that maxactive was set too low. */ |
596 | printk("Missed probing %d instances of %s\n", | 653 | printk("Missed probing %d instances of %s\n", |
597 | my_kretprobe.nmissed, probed_func); | 654 | my_kretprobe.nmissed, probed_func); |
598 | } | 655 | } |
599 | 656 | ||
600 | module_init(kretprobe_init) | 657 | module_init(kretprobe_init) |
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 6168c0a44172..4a6ce82ba039 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
@@ -152,8 +152,10 @@ static inline int arch_trampoline_kprobe(struct kprobe *p) | |||
152 | struct kretprobe { | 152 | struct kretprobe { |
153 | struct kprobe kp; | 153 | struct kprobe kp; |
154 | kretprobe_handler_t handler; | 154 | kretprobe_handler_t handler; |
155 | kretprobe_handler_t entry_handler; | ||
155 | int maxactive; | 156 | int maxactive; |
156 | int nmissed; | 157 | int nmissed; |
158 | size_t data_size; | ||
157 | struct hlist_head free_instances; | 159 | struct hlist_head free_instances; |
158 | struct hlist_head used_instances; | 160 | struct hlist_head used_instances; |
159 | }; | 161 | }; |
@@ -164,6 +166,7 @@ struct kretprobe_instance { | |||
164 | struct kretprobe *rp; | 166 | struct kretprobe *rp; |
165 | kprobe_opcode_t *ret_addr; | 167 | kprobe_opcode_t *ret_addr; |
166 | struct task_struct *task; | 168 | struct task_struct *task; |
169 | char data[0]; | ||
167 | }; | 170 | }; |
168 | 171 | ||
169 | struct kretprobe_blackpoint { | 172 | struct kretprobe_blackpoint { |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index d0493eafea3e..7a86e6432338 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -699,6 +699,12 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p, | |||
699 | struct kretprobe_instance, uflist); | 699 | struct kretprobe_instance, uflist); |
700 | ri->rp = rp; | 700 | ri->rp = rp; |
701 | ri->task = current; | 701 | ri->task = current; |
702 | |||
703 | if (rp->entry_handler && rp->entry_handler(ri, regs)) { | ||
704 | spin_unlock_irqrestore(&kretprobe_lock, flags); | ||
705 | return 0; | ||
706 | } | ||
707 | |||
702 | arch_prepare_kretprobe(ri, regs); | 708 | arch_prepare_kretprobe(ri, regs); |
703 | 709 | ||
704 | /* XXX(hch): why is there no hlist_move_head? */ | 710 | /* XXX(hch): why is there no hlist_move_head? */ |
@@ -745,7 +751,8 @@ int __kprobes register_kretprobe(struct kretprobe *rp) | |||
745 | INIT_HLIST_HEAD(&rp->used_instances); | 751 | INIT_HLIST_HEAD(&rp->used_instances); |
746 | INIT_HLIST_HEAD(&rp->free_instances); | 752 | INIT_HLIST_HEAD(&rp->free_instances); |
747 | for (i = 0; i < rp->maxactive; i++) { | 753 | for (i = 0; i < rp->maxactive; i++) { |
748 | inst = kmalloc(sizeof(struct kretprobe_instance), GFP_KERNEL); | 754 | inst = kmalloc(sizeof(struct kretprobe_instance) + |
755 | rp->data_size, GFP_KERNEL); | ||
749 | if (inst == NULL) { | 756 | if (inst == NULL) { |
750 | free_rp_inst(rp); | 757 | free_rp_inst(rp); |
751 | return -ENOMEM; | 758 | return -ENOMEM; |
diff --git a/kernel/test_kprobes.c b/kernel/test_kprobes.c index 88cdb109e13c..06b6395b45b2 100644 --- a/kernel/test_kprobes.c +++ b/kernel/test_kprobes.c | |||
@@ -135,6 +135,12 @@ static int test_jprobe(void) | |||
135 | #ifdef CONFIG_KRETPROBES | 135 | #ifdef CONFIG_KRETPROBES |
136 | static u32 krph_val; | 136 | static u32 krph_val; |
137 | 137 | ||
138 | static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | ||
139 | { | ||
140 | krph_val = (rand1 / div_factor); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
138 | static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | 144 | static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) |
139 | { | 145 | { |
140 | unsigned long ret = regs_return_value(regs); | 146 | unsigned long ret = regs_return_value(regs); |
@@ -144,13 +150,19 @@ static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | |||
144 | printk(KERN_ERR "Kprobe smoke test failed: " | 150 | printk(KERN_ERR "Kprobe smoke test failed: " |
145 | "incorrect value in kretprobe handler\n"); | 151 | "incorrect value in kretprobe handler\n"); |
146 | } | 152 | } |
153 | if (krph_val == 0) { | ||
154 | handler_errors++; | ||
155 | printk(KERN_ERR "Kprobe smoke test failed: " | ||
156 | "call to kretprobe entry handler failed\n"); | ||
157 | } | ||
147 | 158 | ||
148 | krph_val = (rand1 / div_factor); | 159 | krph_val = rand1; |
149 | return 0; | 160 | return 0; |
150 | } | 161 | } |
151 | 162 | ||
152 | static struct kretprobe rp = { | 163 | static struct kretprobe rp = { |
153 | .handler = return_handler, | 164 | .handler = return_handler, |
165 | .entry_handler = entry_handler, | ||
154 | .kp.symbol_name = "kprobe_target" | 166 | .kp.symbol_name = "kprobe_target" |
155 | }; | 167 | }; |
156 | 168 | ||
@@ -167,7 +179,7 @@ static int test_kretprobe(void) | |||
167 | 179 | ||
168 | ret = kprobe_target(rand1); | 180 | ret = kprobe_target(rand1); |
169 | unregister_kretprobe(&rp); | 181 | unregister_kretprobe(&rp); |
170 | if (krph_val == 0) { | 182 | if (krph_val != rand1) { |
171 | printk(KERN_ERR "Kprobe smoke test failed: " | 183 | printk(KERN_ERR "Kprobe smoke test failed: " |
172 | "kretprobe handler not called\n"); | 184 | "kretprobe handler not called\n"); |
173 | handler_errors++; | 185 | handler_errors++; |