Commit f47cd9b553aaada602449204513b5a5b29cba263
Committed by
Linus Torvalds
1 parent
5beec4aa2a
Exists in
master
and in
39 other branches
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>
Showing 4 changed files with 94 additions and 15 deletions Side-by-side Diff
Documentation/kprobes.txt
... | ... | @@ -96,8 +96,10 @@ |
96 | 96 | The jprobe will work in either case, so long as the handler's |
97 | 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 | 100 | |
101 | +1.3.1 How Does a Return Probe Work? | |
102 | + | |
101 | 103 | When you call register_kretprobe(), Kprobes establishes a kprobe at |
102 | 104 | the entry to the function. When the probed function is called and this |
103 | 105 | probe is hit, Kprobes saves a copy of the return address, and replaces |
... | ... | @@ -107,9 +109,9 @@ |
107 | 109 | |
108 | 110 | When the probed function executes its return instruction, control |
109 | 111 | passes to the trampoline and that probe is hit. Kprobes' trampoline |
110 | -handler calls the user-specified handler associated with the kretprobe, | |
111 | -then sets the saved instruction pointer to the saved return address, | |
112 | -and that's where execution resumes upon return from the trap. | |
112 | +handler calls the user-specified return handler associated with the | |
113 | +kretprobe, then sets the saved instruction pointer to the saved return | |
114 | +address, and that's where execution resumes upon return from the trap. | |
113 | 115 | |
114 | 116 | While the probed function is executing, its return address is |
115 | 117 | stored in an object of type kretprobe_instance. Before calling |
... | ... | @@ -131,6 +133,30 @@ |
131 | 133 | time the probed function is entered but there is no kretprobe_instance |
132 | 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 | 160 | 2. Architectures Supported |
135 | 161 | |
136 | 162 | Kprobes, jprobes, and return probes are implemented on the following |
... | ... | @@ -274,6 +300,8 @@ |
274 | 300 | - ret_addr: the return address |
275 | 301 | - rp: points to the corresponding kretprobe object |
276 | 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 | 306 | The regs_return_value(regs) macro provides a simple abstraction to |
279 | 307 | extract the return value from the appropriate register as defined by |
280 | 308 | |
281 | 309 | |
282 | 310 | |
283 | 311 | |
284 | 312 | |
285 | 313 | |
... | ... | @@ -556,23 +584,52 @@ |
556 | 584 | #include <linux/kernel.h> |
557 | 585 | #include <linux/module.h> |
558 | 586 | #include <linux/kprobes.h> |
587 | +#include <linux/ktime.h> | |
559 | 588 | |
589 | +/* per-instance private data */ | |
590 | +struct my_data { | |
591 | + ktime_t entry_stamp; | |
592 | +}; | |
593 | + | |
560 | 594 | static const char *probed_func = "sys_open"; |
561 | 595 | |
562 | -/* Return-probe handler: If the probed function fails, log the return value. */ | |
563 | -static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | |
596 | +/* Timestamp function entry. */ | |
597 | +static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | |
564 | 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) | |
613 | +{ | |
565 | 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 | 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 | 625 | return 0; |
570 | 626 | } |
571 | 627 | |
572 | 628 | static struct kretprobe my_kretprobe = { |
573 | - .handler = ret_handler, | |
574 | - /* Probe up to 20 instances concurrently. */ | |
575 | - .maxactive = 20 | |
629 | + .handler = return_handler, | |
630 | + .entry_handler = entry_handler, | |
631 | + .data_size = sizeof(struct my_data), | |
632 | + .maxactive = 20, /* probe up to 20 instances concurrently */ | |
576 | 633 | }; |
577 | 634 | |
578 | 635 | static int __init kretprobe_init(void) |
... | ... | @@ -584,7 +641,7 @@ |
584 | 641 | printk("register_kretprobe failed, returned %d\n", ret); |
585 | 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 | 645 | return 0; |
589 | 646 | } |
590 | 647 | |
... | ... | @@ -594,7 +651,7 @@ |
594 | 651 | printk("kretprobe unregistered\n"); |
595 | 652 | /* nmissed > 0 suggests that maxactive was set too low. */ |
596 | 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 | 657 | module_init(kretprobe_init) |
include/linux/kprobes.h
... | ... | @@ -152,8 +152,10 @@ |
152 | 152 | struct kretprobe { |
153 | 153 | struct kprobe kp; |
154 | 154 | kretprobe_handler_t handler; |
155 | + kretprobe_handler_t entry_handler; | |
155 | 156 | int maxactive; |
156 | 157 | int nmissed; |
158 | + size_t data_size; | |
157 | 159 | struct hlist_head free_instances; |
158 | 160 | struct hlist_head used_instances; |
159 | 161 | }; |
... | ... | @@ -164,6 +166,7 @@ |
164 | 166 | struct kretprobe *rp; |
165 | 167 | kprobe_opcode_t *ret_addr; |
166 | 168 | struct task_struct *task; |
169 | + char data[0]; | |
167 | 170 | }; |
168 | 171 | |
169 | 172 | struct kretprobe_blackpoint { |
kernel/kprobes.c
... | ... | @@ -699,6 +699,12 @@ |
699 | 699 | struct kretprobe_instance, uflist); |
700 | 700 | ri->rp = rp; |
701 | 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 | 708 | arch_prepare_kretprobe(ri, regs); |
703 | 709 | |
704 | 710 | /* XXX(hch): why is there no hlist_move_head? */ |
... | ... | @@ -745,7 +751,8 @@ |
745 | 751 | INIT_HLIST_HEAD(&rp->used_instances); |
746 | 752 | INIT_HLIST_HEAD(&rp->free_instances); |
747 | 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 | 756 | if (inst == NULL) { |
750 | 757 | free_rp_inst(rp); |
751 | 758 | return -ENOMEM; |
kernel/test_kprobes.c
... | ... | @@ -135,6 +135,12 @@ |
135 | 135 | #ifdef CONFIG_KRETPROBES |
136 | 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 | 144 | static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) |
139 | 145 | { |
140 | 146 | unsigned long ret = regs_return_value(regs); |
141 | 147 | |
142 | 148 | |
... | ... | @@ -144,13 +150,19 @@ |
144 | 150 | printk(KERN_ERR "Kprobe smoke test failed: " |
145 | 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 | 160 | return 0; |
150 | 161 | } |
151 | 162 | |
152 | 163 | static struct kretprobe rp = { |
153 | 164 | .handler = return_handler, |
165 | + .entry_handler = entry_handler, | |
154 | 166 | .kp.symbol_name = "kprobe_target" |
155 | 167 | }; |
156 | 168 | |
... | ... | @@ -167,7 +179,7 @@ |
167 | 179 | |
168 | 180 | ret = kprobe_target(rand1); |
169 | 181 | unregister_kretprobe(&rp); |
170 | - if (krph_val == 0) { | |
182 | + if (krph_val != rand1) { | |
171 | 183 | printk(KERN_ERR "Kprobe smoke test failed: " |
172 | 184 | "kretprobe handler not called\n"); |
173 | 185 | handler_errors++; |