aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAbhishek Sagar <sagar.abhishek@gmail.com>2008-02-06 04:38:22 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-06 13:41:11 -0500
commitf47cd9b553aaada602449204513b5a5b29cba263 (patch)
tree079ddd399b1aa00a8c413ef51f3b8681a19a6e7e
parent5beec4aa2ac261b0b4992fb41df40a7ab91e4fad (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.txt81
-rw-r--r--include/linux/kprobes.h3
-rw-r--r--kernel/kprobes.c9
-rw-r--r--kernel/test_kprobes.c16
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).
96The jprobe will work in either case, so long as the handler's 96The jprobe will work in either case, so long as the handler's
97prototype matches that of the probed function. 97prototype matches that of the probed function.
98 98
991.3 How Does a Return Probe Work? 991.3 Return Probes
100
1011.3.1 How Does a Return Probe Work?
100 102
101When you call register_kretprobe(), Kprobes establishes a kprobe at 103When you call register_kretprobe(), Kprobes establishes a kprobe at
102the entry to the function. When the probed function is called and this 104the 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
108When the probed function executes its return instruction, control 110When the probed function executes its return instruction, control
109passes to the trampoline and that probe is hit. Kprobes' trampoline 111passes to the trampoline and that probe is hit. Kprobes' trampoline
110handler calls the user-specified handler associated with the kretprobe, 112handler calls the user-specified return handler associated with the
111then sets the saved instruction pointer to the saved return address, 113kretprobe, then sets the saved instruction pointer to the saved return
112and that's where execution resumes upon return from the trap. 114address, and that's where execution resumes upon return from the trap.
113 115
114While the probed function is executing, its return address is 116While the probed function is executing, its return address is
115stored in an object of type kretprobe_instance. Before calling 117stored in an object of type kretprobe_instance. Before calling
@@ -131,6 +133,30 @@ zero when the return probe is registered, and is incremented every
131time the probed function is entered but there is no kretprobe_instance 133time the probed function is entered but there is no kretprobe_instance
132object available for establishing the return probe. 134object available for establishing the return probe.
133 135
1361.3.2 Kretprobe entry-handler
137
138Kretprobes also provides an optional user-specified handler which runs
139on function entry. This handler is specified by setting the entry_handler
140field of the kretprobe struct. Whenever the kprobe placed by kretprobe at the
141function entry is hit, the user-defined entry_handler, if any, is invoked.
142If the entry_handler returns 0 (success) then a corresponding return handler
143is guaranteed to be called upon function return. If the entry_handler
144returns a non-zero error then Kprobes leaves the return address as is, and
145the kretprobe has no further effect for that particular function instance.
146
147Multiple entry and return handler invocations are matched using the unique
148kretprobe_instance object associated with them. Additionally, a user
149may also specify per return-instance private data to be part of each
150kretprobe_instance object. This is especially useful when sharing private
151data between corresponding user entry and return handlers. The size of each
152private data object can be specified at kretprobe registration time by
153setting the data_size field of the kretprobe struct. This data can be
154accessed through the data field of each kretprobe_instance object.
155
156In case probed function is entered but there is no kretprobe_instance
157object available, then in addition to incrementing the nmissed count,
158the user entry_handler invocation is also skipped.
159
1342. Architectures Supported 1602. Architectures Supported
135 161
136Kprobes, jprobes, and return probes are implemented on the following 162Kprobes, 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
278The regs_return_value(regs) macro provides a simple abstraction to 306The regs_return_value(regs) macro provides a simple abstraction to
279extract the return value from the appropriate register as defined by 307extract 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 */
590struct my_data {
591 ktime_t entry_stamp;
592};
559 593
560static const char *probed_func = "sys_open"; 594static 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. */
563static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) 597static 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. */
612static 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
572static struct kretprobe my_kretprobe = { 628static 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
578static int __init kretprobe_init(void) 635static 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
600module_init(kretprobe_init) 657module_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)
152struct kretprobe { 152struct 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
169struct kretprobe_blackpoint { 172struct 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
136static u32 krph_val; 136static u32 krph_val;
137 137
138static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
139{
140 krph_val = (rand1 / div_factor);
141 return 0;
142}
143
138static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) 144static 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
152static struct kretprobe rp = { 163static 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++;