aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorHien Nguyen <hien@us.ibm.com>2005-06-23 03:09:19 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 12:45:21 -0400
commitb94cce926b2b902b79380ccba370d6f9f2980de0 (patch)
treeda2680b1ec36eae6423ba446d09284d2642ae82b /include
parent2fa389c5eb8c97d621653184d2adf5fdbd4a3167 (diff)
[PATCH] kprobes: function-return probes
This patch adds function-return probes to kprobes for the i386 architecture. This enables you to establish a handler to be run when a function returns. 1. API Two new functions are added to kprobes: int register_kretprobe(struct kretprobe *rp); void unregister_kretprobe(struct kretprobe *rp); 2. Registration and unregistration 2.1 Register To register a function-return probe, the user populates the following fields in a kretprobe object and calls register_kretprobe() with the kretprobe address as an argument: kp.addr - the function's address handler - this function is run after the ret instruction executes, but before control returns to the return address in the caller. maxactive - The maximum number of instances of the probed function that can be active concurrently. For example, if the function is non- recursive and is called with a spinlock or mutex held, maxactive = 1 should be enough. If the function is non-recursive and can never relinquish the CPU (e.g., via a semaphore or preemption), NR_CPUS should be enough. maxactive is used to determine how many kretprobe_instance objects to allocate for this particular probed function. If maxactive <= 0, it is set to a default value (if CONFIG_PREEMPT maxactive=max(10, 2 * NR_CPUS) else maxactive=NR_CPUS) For example: struct kretprobe rp; rp.kp.addr = /* entrypoint address */ rp.handler = /*return probe handler */ rp.maxactive = /* e.g., 1 or NR_CPUS or 0, see the above explanation */ register_kretprobe(&rp); The following field may also be of interest: nmissed - Initialized to zero when the function-return probe is registered, and incremented every time the probed function is entered but there is no kretprobe_instance object available for establishing the function-return probe (i.e., because maxactive was set too low). 2.2 Unregister To unregiter a function-return probe, the user calls unregister_kretprobe() with the same kretprobe object as registered previously. If a probed function is running when the return probe is unregistered, the function will return as expected, but the handler won't be run. 3. Limitations 3.1 This patch supports only the i386 architecture, but patches for x86_64 and ppc64 are anticipated soon. 3.2 Return probes operates by replacing the return address in the stack (or in a known register, such as the lr register for ppc). This may cause __builtin_return_address(0), when invoked from the return-probed function, to return the address of the return-probes trampoline. 3.3 This implementation uses the "Multiprobes at an address" feature in 2.6.12-rc3-mm3. 3.4 Due to a limitation in multi-probes, you cannot currently establish a return probe and a jprobe on the same function. A patch to remove this limitation is being tested. This feature is required by SystemTap (http://sourceware.org/systemtap), and reflects ideas contributed by several SystemTap developers, including Will Cohen and Ananth Mavinakayanahalli. Signed-off-by: Hien Nguyen <hien@us.ibm.com> Signed-off-by: Prasanna S Panchamukhi <prasanna@in.ibm.com> Signed-off-by: Frederik Deweerdt <frederik.deweerdt@laposte.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include')
-rw-r--r--include/asm-i386/kprobes.h3
-rw-r--r--include/linux/kprobes.h90
2 files changed, 91 insertions, 2 deletions
diff --git a/include/asm-i386/kprobes.h b/include/asm-i386/kprobes.h
index 4092f68d123a..8b6d3a90cd78 100644
--- a/include/asm-i386/kprobes.h
+++ b/include/asm-i386/kprobes.h
@@ -39,6 +39,9 @@ typedef u8 kprobe_opcode_t;
39 : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR))) 39 : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
40 40
41#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry 41#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
42#define ARCH_SUPPORTS_KRETPROBES
43
44void kretprobe_trampoline(void);
42 45
43/* Architecture specific copy of original instruction*/ 46/* Architecture specific copy of original instruction*/
44struct arch_specific_insn { 47struct arch_specific_insn {
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 99ddba5a4e00..fba39f87efec 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -25,21 +25,31 @@
25 * Rusty Russell). 25 * Rusty Russell).
26 * 2004-July Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes 26 * 2004-July Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes
27 * interface to access function arguments. 27 * interface to access function arguments.
28 * 2005-May Hien Nguyen <hien@us.ibm.com> and Jim Keniston
29 * <jkenisto@us.ibm.com> and Prasanna S Panchamukhi
30 * <prasanna@in.ibm.com> added function-return probes.
28 */ 31 */
29#include <linux/config.h> 32#include <linux/config.h>
30#include <linux/list.h> 33#include <linux/list.h>
31#include <linux/notifier.h> 34#include <linux/notifier.h>
32#include <linux/smp.h> 35#include <linux/smp.h>
36#include <linux/spinlock.h>
37
33#include <asm/kprobes.h> 38#include <asm/kprobes.h>
34 39
35struct kprobe; 40struct kprobe;
36struct pt_regs; 41struct pt_regs;
42struct kretprobe;
43struct kretprobe_instance;
37typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *); 44typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *);
38typedef int (*kprobe_break_handler_t) (struct kprobe *, struct pt_regs *); 45typedef int (*kprobe_break_handler_t) (struct kprobe *, struct pt_regs *);
39typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *, 46typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *,
40 unsigned long flags); 47 unsigned long flags);
41typedef int (*kprobe_fault_handler_t) (struct kprobe *, struct pt_regs *, 48typedef int (*kprobe_fault_handler_t) (struct kprobe *, struct pt_regs *,
42 int trapnr); 49 int trapnr);
50typedef int (*kretprobe_handler_t) (struct kretprobe_instance *,
51 struct pt_regs *);
52
43struct kprobe { 53struct kprobe {
44 struct hlist_node hlist; 54 struct hlist_node hlist;
45 55
@@ -85,6 +95,62 @@ struct jprobe {
85 kprobe_opcode_t *entry; /* probe handling code to jump to */ 95 kprobe_opcode_t *entry; /* probe handling code to jump to */
86}; 96};
87 97
98#ifdef ARCH_SUPPORTS_KRETPROBES
99extern int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs);
100extern void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
101 unsigned long flags);
102extern struct task_struct *arch_get_kprobe_task(void *ptr);
103extern void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs);
104extern void arch_kprobe_flush_task(struct task_struct *tk, spinlock_t *kp_lock);
105#else /* ARCH_SUPPORTS_KRETPROBES */
106static inline void kretprobe_trampoline(void)
107{
108}
109static inline int trampoline_probe_handler(struct kprobe *p,
110 struct pt_regs *regs)
111{
112 return 0;
113}
114static inline void trampoline_post_handler(struct kprobe *p,
115 struct pt_regs *regs, unsigned long flags)
116{
117}
118static inline void arch_prepare_kretprobe(struct kretprobe *rp,
119 struct pt_regs *regs)
120{
121}
122static inline void arch_kprobe_flush_task(struct task_struct *tk)
123{
124}
125#define arch_get_kprobe_task(ptr) ((struct task_struct *)NULL)
126#endif /* ARCH_SUPPORTS_KRETPROBES */
127/*
128 * Function-return probe -
129 * Note:
130 * User needs to provide a handler function, and initialize maxactive.
131 * maxactive - The maximum number of instances of the probed function that
132 * can be active concurrently.
133 * nmissed - tracks the number of times the probed function's return was
134 * ignored, due to maxactive being too low.
135 *
136 */
137struct kretprobe {
138 struct kprobe kp;
139 kretprobe_handler_t handler;
140 int maxactive;
141 int nmissed;
142 struct hlist_head free_instances;
143 struct hlist_head used_instances;
144};
145
146struct kretprobe_instance {
147 struct hlist_node uflist; /* either on free list or used list */
148 struct hlist_node hlist;
149 struct kretprobe *rp;
150 void *ret_addr;
151 void *stack_addr;
152};
153
88#ifdef CONFIG_KPROBES 154#ifdef CONFIG_KPROBES
89/* Locks kprobe: irq must be disabled */ 155/* Locks kprobe: irq must be disabled */
90void lock_kprobes(void); 156void lock_kprobes(void);
@@ -104,6 +170,7 @@ extern void show_registers(struct pt_regs *regs);
104 170
105/* Get the kprobe at this addr (if any). Must have called lock_kprobes */ 171/* Get the kprobe at this addr (if any). Must have called lock_kprobes */
106struct kprobe *get_kprobe(void *addr); 172struct kprobe *get_kprobe(void *addr);
173struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk);
107 174
108int register_kprobe(struct kprobe *p); 175int register_kprobe(struct kprobe *p);
109void unregister_kprobe(struct kprobe *p); 176void unregister_kprobe(struct kprobe *p);
@@ -113,7 +180,16 @@ int register_jprobe(struct jprobe *p);
113void unregister_jprobe(struct jprobe *p); 180void unregister_jprobe(struct jprobe *p);
114void jprobe_return(void); 181void jprobe_return(void);
115 182
116#else 183int register_kretprobe(struct kretprobe *rp);
184void unregister_kretprobe(struct kretprobe *rp);
185
186struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp);
187struct kretprobe_instance *get_rp_inst(void *sara);
188struct kretprobe_instance *get_rp_inst_tsk(struct task_struct *tk);
189void add_rp_inst(struct kretprobe_instance *ri);
190void kprobe_flush_task(struct task_struct *tk);
191void recycle_rp_inst(struct kretprobe_instance *ri);
192#else /* CONFIG_KPROBES */
117static inline int kprobe_running(void) 193static inline int kprobe_running(void)
118{ 194{
119 return 0; 195 return 0;
@@ -135,5 +211,15 @@ static inline void unregister_jprobe(struct jprobe *p)
135static inline void jprobe_return(void) 211static inline void jprobe_return(void)
136{ 212{
137} 213}
138#endif 214static inline int register_kretprobe(struct kretprobe *rp)
215{
216 return -ENOSYS;
217}
218static inline void unregister_kretprobe(struct kretprobe *rp)
219{
220}
221static inline void kprobe_flush_task(struct task_struct *tk)
222{
223}
224#endif /* CONFIG_KPROBES */
139#endif /* _LINUX_KPROBES_H */ 225#endif /* _LINUX_KPROBES_H */