aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/kprobes.c')
-rw-r--r--arch/i386/kernel/kprobes.c102
1 files changed, 101 insertions, 1 deletions
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index 59ff9b455069..048f754bbe23 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -23,6 +23,9 @@
23 * Rusty Russell). 23 * Rusty Russell).
24 * 2004-July Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes 24 * 2004-July Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes
25 * interface to access function arguments. 25 * interface to access function arguments.
26 * 2005-May Hien Nguyen <hien@us.ibm.com>, Jim Keniston
27 * <jkenisto@us.ibm.com> and Prasanna S Panchamukhi
28 * <prasanna@in.ibm.com> added function-return probes.
26 */ 29 */
27 30
28#include <linux/config.h> 31#include <linux/config.h>
@@ -91,6 +94,53 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
91 regs->eip = (unsigned long)&p->ainsn.insn; 94 regs->eip = (unsigned long)&p->ainsn.insn;
92} 95}
93 96
97struct task_struct *arch_get_kprobe_task(void *ptr)
98{
99 return ((struct thread_info *) (((unsigned long) ptr) &
100 (~(THREAD_SIZE -1))))->task;
101}
102
103void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
104{
105 unsigned long *sara = (unsigned long *)&regs->esp;
106 struct kretprobe_instance *ri;
107 static void *orig_ret_addr;
108
109 /*
110 * Save the return address when the return probe hits
111 * the first time, and use it to populate the (krprobe
112 * instance)->ret_addr for subsequent return probes at
113 * the same addrress since stack address would have
114 * the kretprobe_trampoline by then.
115 */
116 if (((void*) *sara) != kretprobe_trampoline)
117 orig_ret_addr = (void*) *sara;
118
119 if ((ri = get_free_rp_inst(rp)) != NULL) {
120 ri->rp = rp;
121 ri->stack_addr = sara;
122 ri->ret_addr = orig_ret_addr;
123 add_rp_inst(ri);
124 /* Replace the return addr with trampoline addr */
125 *sara = (unsigned long) &kretprobe_trampoline;
126 } else {
127 rp->nmissed++;
128 }
129}
130
131void arch_kprobe_flush_task(struct task_struct *tk, spinlock_t *kp_lock)
132{
133 unsigned long flags = 0;
134 struct kretprobe_instance *ri;
135 spin_lock_irqsave(kp_lock, flags);
136 while ((ri = get_rp_inst_tsk(tk)) != NULL) {
137 *((unsigned long *)(ri->stack_addr)) =
138 (unsigned long) ri->ret_addr;
139 recycle_rp_inst(ri);
140 }
141 spin_unlock_irqrestore(kp_lock, flags);
142}
143
94/* 144/*
95 * Interrupts are disabled on entry as trap3 is an interrupt gate and they 145 * Interrupts are disabled on entry as trap3 is an interrupt gate and they
96 * remain disabled thorough out this function. 146 * remain disabled thorough out this function.
@@ -184,6 +234,55 @@ no_kprobe:
184} 234}
185 235
186/* 236/*
237 * For function-return probes, init_kprobes() establishes a probepoint
238 * here. When a retprobed function returns, this probe is hit and
239 * trampoline_probe_handler() runs, calling the kretprobe's handler.
240 */
241 void kretprobe_trampoline_holder(void)
242 {
243 asm volatile ( ".global kretprobe_trampoline\n"
244 "kretprobe_trampoline: \n"
245 "nop\n");
246 }
247
248/*
249 * Called when we hit the probe point at kretprobe_trampoline
250 */
251int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
252{
253 struct task_struct *tsk;
254 struct kretprobe_instance *ri;
255 struct hlist_head *head;
256 struct hlist_node *node;
257 unsigned long *sara = ((unsigned long *) &regs->esp) - 1;
258
259 tsk = arch_get_kprobe_task(sara);
260 head = kretprobe_inst_table_head(tsk);
261
262 hlist_for_each_entry(ri, node, head, hlist) {
263 if (ri->stack_addr == sara && ri->rp) {
264 if (ri->rp->handler)
265 ri->rp->handler(ri, regs);
266 }
267 }
268 return 0;
269}
270
271void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
272 unsigned long flags)
273{
274 struct kretprobe_instance *ri;
275 /* RA already popped */
276 unsigned long *sara = ((unsigned long *)&regs->esp) - 1;
277
278 while ((ri = get_rp_inst(sara))) {
279 regs->eip = (unsigned long)ri->ret_addr;
280 recycle_rp_inst(ri);
281 }
282 regs->eflags &= ~TF_MASK;
283}
284
285/*
187 * Called after single-stepping. p->addr is the address of the 286 * Called after single-stepping. p->addr is the address of the
188 * instruction whose first byte has been replaced by the "int 3" 287 * instruction whose first byte has been replaced by the "int 3"
189 * instruction. To avoid the SMP problems that can occur when we 288 * instruction. To avoid the SMP problems that can occur when we
@@ -266,7 +365,8 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
266 if (current_kprobe->post_handler) 365 if (current_kprobe->post_handler)
267 current_kprobe->post_handler(current_kprobe, regs, 0); 366 current_kprobe->post_handler(current_kprobe, regs, 0);
268 367
269 resume_execution(current_kprobe, regs); 368 if (current_kprobe->post_handler != trampoline_post_handler)
369 resume_execution(current_kprobe, regs);
270 regs->eflags |= kprobe_saved_eflags; 370 regs->eflags |= kprobe_saved_eflags;
271 371
272 unlock_kprobes(); 372 unlock_kprobes();