aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMasami Hiramatsu <hiramatu@sdl.hitachi.co.jp>2006-03-26 04:38:19 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-26 11:57:04 -0500
commitc9becf58d935265919bf1cb348b2c04492c8949d (patch)
tree57ec897e82bdd4c30eb19112be425fe4d64a1029 /arch
parent311ac88fd2d4194a95e9e38d2fe08917be98723c (diff)
[PATCH] kretprobe: kretprobe-booster
In normal operation, kretprobe makes a target function return to trampoline code. A kprobe (called trampoline_probe) has been inserted in the trampoline code. When the kernel hits this kprobe, it calls kretprobe's handler and it returns to the original return address. Kretprobe-booster removes the trampoline_probe. It allows the trampoline code to call kretprobe's handler directly instead of invoking kprobe. The trampoline code returns to the original return address. (changelog from Chuck Ebbert <76306.1226@compuserve.com> - thanks ;)) Signed-off-by: Masami Hiramatsu <hiramatu@sdl.hitachi.co.jp> 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> Cc: David S. Miller <davem@davemloft.net> Cc: Chuck Ebbert <76306.1226@compuserve.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/kernel/kprobes.c61
1 files changed, 39 insertions, 22 deletions
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index 137bf612141..acdcc640a72 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -333,17 +333,44 @@ no_kprobe:
333 * here. When a retprobed function returns, this probe is hit and 333 * here. When a retprobed function returns, this probe is hit and
334 * trampoline_probe_handler() runs, calling the kretprobe's handler. 334 * trampoline_probe_handler() runs, calling the kretprobe's handler.
335 */ 335 */
336 void kretprobe_trampoline_holder(void) 336 void __kprobes kretprobe_trampoline_holder(void)
337 { 337 {
338 asm volatile ( ".global kretprobe_trampoline\n" 338 asm volatile ( ".global kretprobe_trampoline\n"
339 "kretprobe_trampoline: \n" 339 "kretprobe_trampoline: \n"
340 "nop\n"); 340 " pushf\n"
341 } 341 /* skip cs, eip, orig_eax, es, ds */
342 " subl $20, %esp\n"
343 " pushl %eax\n"
344 " pushl %ebp\n"
345 " pushl %edi\n"
346 " pushl %esi\n"
347 " pushl %edx\n"
348 " pushl %ecx\n"
349 " pushl %ebx\n"
350 " movl %esp, %eax\n"
351 " call trampoline_handler\n"
352 /* move eflags to cs */
353 " movl 48(%esp), %edx\n"
354 " movl %edx, 44(%esp)\n"
355 /* save true return address on eflags */
356 " movl %eax, 48(%esp)\n"
357 " popl %ebx\n"
358 " popl %ecx\n"
359 " popl %edx\n"
360 " popl %esi\n"
361 " popl %edi\n"
362 " popl %ebp\n"
363 " popl %eax\n"
364 /* skip eip, orig_eax, es, ds */
365 " addl $16, %esp\n"
366 " popf\n"
367 " ret\n");
368}
342 369
343/* 370/*
344 * Called when we hit the probe point at kretprobe_trampoline 371 * Called from kretprobe_trampoline
345 */ 372 */
346int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) 373fastcall void *__kprobes trampoline_handler(struct pt_regs *regs)
347{ 374{
348 struct kretprobe_instance *ri = NULL; 375 struct kretprobe_instance *ri = NULL;
349 struct hlist_head *head; 376 struct hlist_head *head;
@@ -372,8 +399,11 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
372 /* another task is sharing our hash bucket */ 399 /* another task is sharing our hash bucket */
373 continue; 400 continue;
374 401
375 if (ri->rp && ri->rp->handler) 402 if (ri->rp && ri->rp->handler){
403 __get_cpu_var(current_kprobe) = &ri->rp->kp;
376 ri->rp->handler(ri, regs); 404 ri->rp->handler(ri, regs);
405 __get_cpu_var(current_kprobe) = NULL;
406 }
377 407
378 orig_ret_address = (unsigned long)ri->ret_addr; 408 orig_ret_address = (unsigned long)ri->ret_addr;
379 recycle_rp_inst(ri); 409 recycle_rp_inst(ri);
@@ -388,18 +418,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
388 } 418 }
389 419
390 BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); 420 BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
391 regs->eip = orig_ret_address;
392 421
393 reset_current_kprobe();
394 spin_unlock_irqrestore(&kretprobe_lock, flags); 422 spin_unlock_irqrestore(&kretprobe_lock, flags);
395 preempt_enable_no_resched();
396 423
397 /* 424 return (void*)orig_ret_address;
398 * By returning a non-zero value, we are telling
399 * kprobe_handler() that we don't want the post_handler
400 * to run (and have re-enabled preemption)
401 */
402 return 1;
403} 425}
404 426
405/* 427/*
@@ -646,12 +668,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
646 return 0; 668 return 0;
647} 669}
648 670
649static struct kprobe trampoline_p = {
650 .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
651 .pre_handler = trampoline_probe_handler
652};
653
654int __init arch_init_kprobes(void) 671int __init arch_init_kprobes(void)
655{ 672{
656 return register_kprobe(&trampoline_p); 673 return 0;
657} 674}