Jumper Probes patch to provide function arguments
PATCH 3/4 Jumper Probes patch to provide function arguments
Hi,
Below is [3/4] kprobes-func-args-268-rc4.patch.
A special kprobe type which can be placed on function entry points, and employs a simple mirroring principle to allow seamless access to the arguments of a function being probed. The probe handler routine should have the same prototype as the function being probed. Currently implemented for x86.
Your comments are welcome!
Thanks
Prasanna
Signature · 5 lines
Prasanna S Panchamukhi Linux Technology Center India Software Labs, IBM Bangalore Ph: 91-80-25044636 <[email protected]>
A special kprobe type which can be placed on function entry points, and employs a simple mirroring principle to allow seamless access to the arguments of a function being probed. The probe handler routine should have the same prototype as the function being probed. Currently implemented for x86.
The way it works is that when the probe is hit, the breakpoint handler simply irets to the probe handler's eip while retaining register and stack state corresponding to the function entry. After it is done, the probe handler calls jprobe_return() which traps again to restore processor state and switch back to the probed function. Linus noted correctly at KS that we need to be careful as gcc assumes that the callee owns arguments. We save and restore enough stack bytes to cover argument space.
Sample Usage:
static int jip_queue_xmit(struct sk_buff *skb, int ipfragok)
{
... whatever ...
jprobe_return();
return 0;
}
struct jprobe jp = {
{.addr = (kprobe_opcode_t *) ip_queue_xmit},
.entry = (kprobe_opcode_t *) jip_queue_xmit
};
register_jprobe(&jp);---
---
---
linux-2.6.8-rc4-prasanna/arch/i386/kernel/kprobes.c | 77 +++++++++++++++++++- linux-2.6.8-rc4-prasanna/include/asm-i386/kprobes.h | 4 + linux-2.6.8-rc4-prasanna/include/linux/kprobes.h | 43 ++++++++++- linux-2.6.8-rc4-prasanna/kernel/kprobes.c | 19 ++++ 4 files changed, 139 insertions(+), 4 deletions(-)
arch/i386/kernel/kprobes.c renamed from arch/i386/kernel/kprobes.c~kprobes-func-args-268-rc4 +75 -2
@@ -16,11 +16,13 @@* along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -* Copyright (C) IBM Corporation, 2002 +* Copyright (C) IBM Corporation, 2002, 2004 * * 2002-Oct Created by Vamsi Krishna S <[email protected]> Kernel * Probes initial implementation ( includes contributions from * Rusty Russell). +* 2004-July Suparna Bhattacharya <[email protected]> added jumper probes +* interface to access function arguments. */ #include <linux/config.h>
@@ -30,12 +32,17 @@#include <linux/preempt.h> #include <asm/kdebug.h> +/* kprobe_status settings */ #define KPROBE_HIT_ACTIVE 0x00000001#define KPROBE_HIT_SS 0x00000002static struct kprobe *current_kprobe;static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags; +static struct pt_regs jprobe_saved_regs; +static long *jprobe_saved_esp; +/* copy of the kernel stack at the probe fire time */ +static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE ];/* * returns non-zero if opcode modifies the interrupt flag.
@@ -91,6 +98,11 @@ static inline int kprobe_handler(structif (p) {disarm_kprobe (p, regs); ret =1 ; + }else { + p = current_kprobe; +if (p->break_handler && p->break_handler (p, regs)) { + goto ss_probe; + } }/* If it's not ours, can't be delete race, (we hold lock). */ goto no_kprobe;
@@ -121,8 +133,12 @@ static inline int kprobe_handler(structif (is_IF_modifier (p->opcode)) kprobe_saved_eflags &= ~IF_MASK ; - p->pre_handler (p, regs); +if (p->pre_handler (p, regs)) { +/* handler has already set things up, so skip ss setup */ +return 1 ; + } + ss_probe:prepare_singlestep (p, regs); kprobe_status =KPROBE_HIT_SS ;return 1 ;
@@ -273,3 +289,60 @@ int kprobe_exceptions_notify(struct noti }return NOTIFY_BAD ; } + +int setjmp_pre_handler (struct kprobe *p,struct pt_regs *regs) +{ + struct jprobe *jp = container_of(p, struct jprobe, kp); + jprobe_saved_regs = *regs; + jprobe_saved_esp = ®s->esp; +unsigned long addr = (unsigned long )jprobe_saved_esp; +/* +* TBD: As Linus pointed out, gcc assumes that the callee +* owns the argument space and could overwrite it, e.g. +* tailcall optimization. So, to be absolutely safe +* we also save and restore enough stack bytes to cover +* the argument area. +*/ +memcpy (jprobes_stack, (kprobe_opcode_t *) addr, +MIN_STACK_SIZE (addr)); + regs->eflags &= ~IF_MASK ; + regs->eip = (unsigned long )(jp->entry); +return 1 ; +} + +void jprobe_return (void ) +{ +preempt_enable_no_resched (); + asmvolatile (" xchgl %%ebx,%%esp \n" +" int3 \n" ::"b" + (jprobe_saved_esp):"memory" ); +} +void jprobe_return_end (void ) +{ +}; + +int longjmp_break_handler (struct kprobe *p,struct pt_regs *regs) +{ +u8 *addr = (u8 *) (regs->eip -1 ); +unsigned long stack_addr = (unsigned long )jprobe_saved_esp; + struct jprobe *jp = container_of(p, struct jprobe, kp); + +if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) { +if (®s->esp != jprobe_saved_esp) { +struct pt_regs *saved_regs = + container_of(jprobe_saved_esp, struct pt_regs, esp); +printk ("current esp %p does not match saved esp %p\n" , + ®s->esp, jprobe_saved_esp); +printk ("Saved registers for jprobe %p\n" , jp); +show_registers (saved_regs); +printk ("Current registers\n" ); +show_registers (regs); +BUG (); + } + *regs = jprobe_saved_regs; +memcpy ((kprobe_opcode_t *) stack_addr, jprobes_stack, +MIN_STACK_SIZE (stack_addr)); +return 1 ; + } +return 0 ; +}
include/asm-i386/kprobes.h renamed from include/asm-i386/kprobes.h~kprobes-func-args-268-rc4 +4 -0
@@ -32,6 +32,10 @@ struct pt_regs;typedef u8 kprobe_opcode_t ;#define BREAKPOINT_INSTRUCTION 0xcc#define MAX_INSN_SIZE 16 +#define MAX_STACK_SIZE 64 +#define MIN_STACK_SIZE (ADDR ) ((((ADDR) + MAX_STACK_SIZE) < \ + (((ADDR) & PAGE_MASK) + PAGE_SIZE) ? ((ADDR) + MAX_STACK_SIZE) \ + : (((ADDR) & PAGE_MASK) + PAGE_SIZE )) - (ADDR))/* trap3/1 are intr gates for kprobes. So, restore the status of IF, * if necessary, before executing the original int3/1 (trap) handler.
include/linux/kprobes.h renamed from include/linux/kprobes.h~kprobes-func-args-268-rc4 +41 -2
88 lines not on this page · raw message
kernel/kprobes.c renamed from kernel/kprobes.c~kprobes-func-args-268-rc4 +19 -0
@@ -23,6 +23,8 @@* Rusty Russell). * 2004-Aug Updated by Prasanna S Panchamukhi <[email protected]> with * hlists and exceptions notifier as suggested by Andi Kleen. +* 2004-July Suparna Bhattacharya <[email protected]> added jumper probes +* interface to access function arguments. */ #include <linux/kprobes.h> #include <linux/spinlock.h>
@@ -106,6 +108,20 @@ static struct notifier_block kprobe_exce .notifier_call = kprobe_exceptions_notify, }; +int register_jprobe (struct jprobe *jp) +{ +/* Todo: Verify probepoint is a function entry point */ + jp->kp.pre_handler = setjmp_pre_handler; + jp->kp.break_handler = longjmp_break_handler; + +return register_kprobe (&jp->kp); +} + +void unregister_jprobe (struct jprobe *jp) +{ +unregister_kprobe (&jp->kp); +} +static int __init init_kprobes (void ) {int i, err =0 ;
@@ -123,3 +139,6 @@ __initcall(init_kprobes);EXPORT_SYMBOL_GPL (register_kprobe);EXPORT_SYMBOL_GPL (unregister_kprobe); +EXPORT_SYMBOL_GPL (register_jprobe); +EXPORT_SYMBOL_GPL (unregister_jprobe); +EXPORT_SYMBOL_GPL (jprobe_return);
_