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]

[Patch 3/5][Djprobe]Djprobe Coexist with Kprobes


Hi,

This patch is an i386 architecture dependent code
of djprobe.

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

 arch/i386/kernel/Makefile       |    2
 arch/i386/kernel/kprobes.c      |  134 ++++++++++++++++++++++++++++++++++++++++
 arch/i386/kernel/stub_djprobe.S |   77 ++++++++++++++++++++++
 include/asm-i386/kprobes.h      |   26 +++++++
 4 files changed, 238 insertions(+), 1 deletion(-)

diff -Narup linux-2.6.13-mm1.djp.2/arch/i386/kernel/Makefile linux-2.6.13-mm1.djp.3/arch/i386/kernel/Makefile
--- linux-2.6.13-mm1.djp.2/arch/i386/kernel/Makefile	2005-09-05 19:11:16.000000000 +0900
+++ linux-2.6.13-mm1.djp.3/arch/i386/kernel/Makefile	2005-09-09 19:05:41.000000000 +0900
@@ -28,7 +28,7 @@ obj-$(CONFIG_X86_REBOOTFIXUPS)	+= reboot
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o crash.o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
 obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit.o
-obj-$(CONFIG_KPROBES)		+= kprobes.o
+obj-$(CONFIG_KPROBES)		+= kprobes.o stub_djprobe.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
diff -Narup linux-2.6.13-mm1.djp.2/arch/i386/kernel/kprobes.c linux-2.6.13-mm1.djp.3/arch/i386/kernel/kprobes.c
--- linux-2.6.13-mm1.djp.2/arch/i386/kernel/kprobes.c	2005-09-12 20:07:55.000000000 +0900
+++ linux-2.6.13-mm1.djp.3/arch/i386/kernel/kprobes.c	2005-09-12 20:08:48.000000000 +0900
@@ -36,6 +36,7 @@
 #include <asm/cacheflush.h>
 #include <asm/kdebug.h>
 #include <asm/desc.h>
+#include <asm/processor.h>

 static struct kprobe *current_kprobe;
 static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags;
@@ -558,3 +559,136 @@ int __init arch_init_kprobes(void)
 {
 	return register_kprobe(&trampoline_p);
 }
+
+/*
+ * When kernel full preemption is enabled, we can't ensure that no threads
+ * are executing the modified code. It may be stored in the stack of the
+ * threads. In this case, the djprobe interfaces are emulated by using
+ * kprobe.
+ * When kernel full preemption is disabled, threads are scheduled
+ * from only limited addresses. So it is easy to check whether the
+ * preemption can occur in the modified code.
+ */
+#ifndef CONFIG_PREEMPT
+/*
+ * On pentium series, Unsynchronized cross-modifying code
+ * operations can cause unexpected instruction execution results.
+ * So after code modified, we should synchronize it on each processor.
+ */
+static void __local_serialize_cpu(void * info)
+{
+	serialize_cpu();
+}
+
+static inline void smp_serialize_cpus(void)
+{
+	on_each_cpu(__local_serialize_cpu, NULL, 1,1);
+}
+
+/* jmp code manipulators */
+struct __arch_jmp_op {
+	char op;
+	long raddr;
+} __attribute__((packed));
+/* insert jmp code */
+static inline void __set_jmp_op(void *from, void *to)
+{
+	struct __arch_jmp_op *jop;
+	jop = (struct __arch_jmp_op *)from;
+	jop->raddr=(long)(to) - ((long)(from) + 5);
+	smp_serialize_cpus();
+	jop->op = RELATIVEJUMP_INSTRUCTION;
+}
+/* switch back to the kprobe */
+static inline void __set_breakpoint_op(void *dest, void *orig)
+{
+	struct __arch_jmp_op *jop = (struct __arch_jmp_op *)dest,
+		*jop2 = (struct __arch_jmp_op *)orig;
+
+	jop->op = BREAKPOINT_INSTRUCTION;
+	smp_serialize_cpus();
+	jop->raddr = jop2->raddr;
+}
+
+/* djprobe call back function: called from stub code */
+static void asmlinkage djprobe_callback(struct djprobe_instance * djpi,
+					struct pt_regs *regs)
+{
+	/*TODO: use list*/
+	if (djpi->djp && djpi->djp->handler)
+		djpi->djp->handler(djpi->djp, regs);
+}
+
+/*
+ * Copy post processing instructions
+ * Target instructions MUST be relocatable.
+ */
+int __kprobes arch_prepare_djprobe_instance(struct djprobe_instance *djpi,
+				  unsigned long size)
+{
+	kprobe_opcode_t *stub;
+	stub = djpi->stub.insn;
+
+	/* copy arch-dep-instance from template */
+	memcpy((void*)stub, (void*)&arch_tmpl_stub_entry, ARCH_STUB_SIZE);
+
+	/* set probe information */
+	*((long*)(stub + ARCH_STUB_VAL_IDX)) = (long)djpi;
+	/* set probe function */
+	*((long*)(stub + ARCH_STUB_CALL_IDX)) = (long)djprobe_callback;
+
+	/* copy instructions into the middle of axporbe instance */
+	memcpy((void*)(stub + ARCH_STUB_INST_IDX),
+	       (void*)djpi->kp.addr, size);
+	djpi->stub.size = size;
+
+	/* set returning jmp instruction at the tail of axporbe instance*/
+	__set_jmp_op(stub + ARCH_STUB_INST_IDX + size,
+		     (void*)((long)djpi->kp.addr + size));
+
+	return 0;
+}
+
+/* Insert "jmp" instruction into the probing point. */
+void __kprobes arch_install_djprobe_instance(struct djprobe_instance *djpi)
+{
+	kprobe_opcode_t *stub;
+	stub = djpi->stub.insn;
+	__set_jmp_op((void*)djpi->kp.addr, (void*)stub);
+}
+
+/* Write back original instructions & kprobe */
+void __kprobes arch_uninstall_djprobe_instance(struct djprobe_instance *djpi)
+{
+	kprobe_opcode_t *stub;
+	stub = &djpi->stub.insn[ARCH_STUB_INST_IDX];
+	__set_breakpoint_op((void*)djpi->kp.addr, (void*)stub);
+	/* fixup dummy instruction */
+	djpi->kp.ainsn.insn[0] = djpi->stub.insn[ARCH_STUB_INST_IDX];
+}
+
+/* djprobe handler : switch to a bypass code */
+int __kprobes djprobe_bypass_handler(struct kprobe * kp, struct pt_regs * regs)
+{
+	struct djprobe_instance *djpi =
+		container_of(kp,struct djprobe_instance, kp);
+	kprobe_opcode_t *stub = djpi->stub.insn;
+
+	if (DJPI_EMPTY(djpi)) {
+		/* fixup dummy instruction */
+		kp->ainsn.insn[0] = djpi->stub.insn[ARCH_STUB_INST_IDX];
+		return 0;
+	} else {
+		regs->eip = (unsigned long)stub;
+		regs->eflags |= TF_MASK;
+		regs->eflags &= ~IF_MASK;
+		/*
+		 * dummy return code :
+		 * This code is to avoid to be changed eip value by
+		 * resume_execute() of kprobes
+		 */
+		kp->ainsn.insn[0] = RETURN_INSTRUCTION;
+		return 1; /* already prepared */
+	}
+}
+#endif /*!CONFIG_PREEMPT*/
diff -Narup linux-2.6.13-mm1.djp.2/arch/i386/kernel/stub_djprobe.S linux-2.6.13-mm1.djp.3/arch/i386/kernel/stub_djprobe.S
--- linux-2.6.13-mm1.djp.2/arch/i386/kernel/stub_djprobe.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.13-mm1.djp.3/arch/i386/kernel/stub_djprobe.S	2005-09-09 19:05:41.000000000 +0900
@@ -0,0 +1,77 @@
+/*
+ *  linux/arch/i386/stub_djprobe.S
+ *
+ *  Copyright (C) HITACHI,LTD. 2005
+ *  Created by Masami Hiramatsu <hiramatu@sdl.hitachi.co.jp>
+ */
+
+#include <linux/config.h>
+
+# jmp into this function from other functions.
+.global arch_tmpl_stub_entry
+arch_tmpl_stub_entry:
+	nop
+	subl $8, %esp	#skip segment registers.
+	pushf
+	subl $20, %esp	#skip segment registers.
+	pushl %eax
+	pushl %ebp
+	pushl %edi
+	pushl %esi
+	pushl %edx
+	pushl %ecx
+	pushl %ebx
+
+	movl %esp, %eax
+	pushl %eax
+	addl $60, %eax
+	movl %eax, 56(%esp)
+.global arch_tmpl_stub_val
+arch_tmpl_stub_val:
+	movl $0xffffffff, %eax
+	pushl %eax
+.global arch_tmpl_stub_call
+arch_tmpl_stub_call:
+	movl $0xffffffff, %eax
+	call *%eax
+	addl $8, %esp
+
+	popl %ebx
+	popl %ecx
+	popl %edx
+	popl %esi
+	popl %edi
+	popl %ebp
+	popl %eax
+	addl $20, %esp
+	popf
+	addl $8, %esp
+.global arch_tmpl_stub_inst
+arch_tmpl_stub_inst:
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+.global arch_tmpl_stub_end
+arch_tmpl_stub_end:
diff -Narup linux-2.6.13-mm1.djp.2/include/asm-i386/kprobes.h linux-2.6.13-mm1.djp.3/include/asm-i386/kprobes.h
--- linux-2.6.13-mm1.djp.2/include/asm-i386/kprobes.h	2005-09-05 19:11:16.000000000 +0900
+++ linux-2.6.13-mm1.djp.3/include/asm-i386/kprobes.h	2005-09-12 14:07:34.000000000 +0900
@@ -31,6 +31,8 @@ struct pt_regs;

 typedef u8 kprobe_opcode_t;
 #define BREAKPOINT_INSTRUCTION	0xcc
+#define RELATIVEJUMP_INSTRUCTION 0xe9
+#define RETURN_INSTRUCTION 0xc3
 #define MAX_INSN_SIZE 16
 #define MAX_STACK_SIZE 64
 #define MIN_STACK_SIZE(ADDR) (((MAX_STACK_SIZE) < \
@@ -40,6 +42,30 @@ typedef u8 kprobe_opcode_t;

 #define JPROBE_ENTRY(pentry)	(kprobe_opcode_t *)pentry
 #define ARCH_SUPPORTS_KRETPROBES
+#ifndef CONFIG_PREEMPT
+#define ARCH_SUPPORTS_DJPROBES
+#endif /* CONFIG_PREEMPT */
+
+/* stub template code */
+extern kprobe_opcode_t arch_tmpl_stub_entry;
+extern kprobe_opcode_t arch_tmpl_stub_val;
+extern kprobe_opcode_t arch_tmpl_stub_call;
+extern kprobe_opcode_t arch_tmpl_stub_inst;
+extern kprobe_opcode_t arch_tmpl_stub_end;
+
+#define ARCH_STUB_VAL_IDX ((long)&arch_tmpl_stub_val - (long)&arch_tmpl_stub_entry + 1)
+#define ARCH_STUB_CALL_IDX ((long)&arch_tmpl_stub_call - (long)&arch_tmpl_stub_entry + 1)
+#define ARCH_STUB_INST_IDX ((long)&arch_tmpl_stub_inst - (long)&arch_tmpl_stub_entry)
+#define ARCH_STUB_SIZE ((long)&arch_tmpl_stub_end - (long)&arch_tmpl_stub_entry)
+
+#define ARCH_STUB_INSN_MAX 20
+#define ARCH_STUB_INSN_MIN 5
+
+struct arch_djprobe_stub {
+	kprobe_opcode_t *insn;
+	int size;
+};
+#define DJPI_ARCH_SIZE(djpi) (djpi->stub.size)

 void kretprobe_trampoline(void);



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