This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC][Patch 2/2]kprobe: kprobe-booster against 2.6.14-mm1 for i386


Hi,

This patch adds kprobe-booster function for i386 arch.

-- 
Masami HIRAMATSU
2nd Research Dept.
Hitachi, Ltd., Systems Development Laboratory
E-mail: hiramatu@sdl.hitachi.co.jp

 arch/i386/kernel/kprobes.c |   46 +++++++++++++++++++++++++++++++++++++++++----
 include/asm-i386/kprobes.h |    4 +++
 2 files changed, 46 insertions(+), 4 deletions(-)

diff -Narup linux-2.6.14-mm1.opt/arch/i386/kernel/kprobes.c linux-2.6.14-mm1.booster/arch/i386/kernel/kprobes.c
--- linux-2.6.14-mm1.opt/arch/i386/kernel/kprobes.c	2005-11-18 21:27:54.000000000 +0900
+++ linux-2.6.14-mm1.booster/arch/i386/kernel/kprobes.c	2005-11-18 21:26:07.000000000 +0900
@@ -41,6 +41,18 @@ void jprobe_return_end(void);
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);

+/* insert a jmp code */
+static inline void set_jmp_op(void *from, void *to)
+{
+	struct __arch_jmp_op {
+		char op;
+		long raddr;
+	} __attribute__((packed)) *jop;
+	jop = (struct __arch_jmp_op *)from;
+	jop->raddr = (long)(to) - ((long)(from) + 5);
+	jop->op = RELATIVEJUMP_INSTRUCTION;
+}
+
 /*
  * returns non-zero if opcode modifies the interrupt flag.
  */
@@ -65,6 +77,7 @@ void __kprobes arch_copy_kprobe(struct k
 {
 	memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
 	p->opcode = *p->addr;
+	p->ainsn.boostable = 0;
 }

 void __kprobes arch_arm_kprobe(struct kprobe *p)
@@ -235,6 +248,13 @@ static int __kprobes kprobe_handler(stru
 		/* handler has already set things up, so skip ss setup */
 		return 1;

+	if (p->ainsn.boostable && !p->post_handler && !p->break_handler ) {
+		/* Boost up -- we can execute copied instructions directly */
+		reset_current_kprobe();
+		regs->eip = (unsigned long)&p->ainsn.insn;
+		return 1;
+	}
+
 ss_probe:
 	prepare_singlestep(p, regs);
 	kcb->kprobe_status = KPROBE_HIT_SS;
@@ -340,6 +360,8 @@ int __kprobes trampoline_probe_handler(s
  * 2) If the single-stepped instruction was a call, the return address
  * that is atop the stack is the address following the copied instruction.
  * We need to make it the address following the original instruction.
+ *
+ * This function also prepares direct execution.
  */
 static void __kprobes resume_execution(struct kprobe *p,
 		struct pt_regs *regs, struct kprobe_ctlblk *kcb)
@@ -367,22 +389,38 @@ static void __kprobes resume_execution(s
 	case 0xff:
 		if ((p->ainsn.insn[1] & 0x30) == 0x10) {
 			/* call absolute, indirect */
-			/* Fix return addr; eip is correct. */
+			/* Fix return addr; eip is correct
+			   But this is not boostable */
 			*tos = orig_eip + (*tos - copy_eip);
-			goto no_change;
+			return ;
 		} else if (((p->ainsn.insn[1] & 0x31) == 0x20) ||	/* jmp near, absolute indirect */
 			   ((p->ainsn.insn[1] & 0x31) == 0x21)) {	/* jmp far, absolute indirect */
-			/* eip is correct. */
+			/* eip is correct. And this is boostable */
 			goto no_change;
 		}
+		/* other indirect instructions can not be executed directly */
+	case BREAKPOINT_INSTRUCTION:
+		/* breakpoint instruction can not be executed directly */
+		break;
 	default:
+		if (p->ainsn.boostable == 0 && regs->eip > copy_eip &&
+		    (regs->eip - copy_eip) + 5 < MAX_INSN_SIZE) {
+			/* these instructions can be executed directly if it
+			   jumps back to correct address. */
+			set_jmp_op((void *)regs->eip,
+				   (void *)orig_eip + (regs->eip - copy_eip));
+			p->ainsn.boostable = 1;
+		}
 		break;
 	}

 	regs->eip = orig_eip + (regs->eip - copy_eip);
+	return ;

        no_change:
-	return ;
+	/* If eip is already adjusted, it can be executed directly. */
+	p->ainsn.boostable = 1;
+	return;
 }

 /*
diff -Narup linux-2.6.14-mm1.opt/include/asm-i386/kprobes.h linux-2.6.14-mm1.booster/include/asm-i386/kprobes.h
--- linux-2.6.14-mm1.opt/include/asm-i386/kprobes.h	2005-11-08 16:45:06.000000000 +0900
+++ linux-2.6.14-mm1.booster/include/asm-i386/kprobes.h	2005-11-17 02:48:49.000000000 +0900
@@ -31,6 +31,7 @@ struct pt_regs;

 typedef u8 kprobe_opcode_t;
 #define BREAKPOINT_INSTRUCTION	0xcc
+#define RELATIVEJUMP_INSTRUCTION 0xe9
 #define MAX_INSN_SIZE 16
 #define MAX_STACK_SIZE 64
 #define MIN_STACK_SIZE(ADDR) (((MAX_STACK_SIZE) < \
@@ -47,6 +48,9 @@ void kretprobe_trampoline(void);
 struct arch_specific_insn {
 	/* copy of the original instruction */
 	kprobe_opcode_t insn[MAX_INSN_SIZE];
+	/* If this flag is not 0, this kprobe can be boost when its
+	   post_handler and break_handler is not set. */
+	int boostable;
 };

 struct prev_kprobe {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]