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 4/5][djprobe] djprobe for i386 architecture code


Hi,

This patch is i386 architecture dependent part of the djprobe.
I updated the stub code to access stack pointer correctly.

-- 
Masami HIRAMATSU
Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

 arch/i386/Kconfig               |    8 ++
 arch/i386/kernel/Makefile       |    1
 arch/i386/kernel/djprobe.c      |  143 ++++++++++++++++++++++++++++++++++++++++
 arch/i386/kernel/stub_djprobe.S |   72 ++++++++++++++++++++
 include/asm-i386/djprobe.h      |   65 ++++++++++++++++++
 5 files changed, 289 insertions(+)
Index: linux-2.6.19-rc1-mm1/arch/i386/Kconfig
===================================================================
--- linux-2.6.19-rc1-mm1.orig/arch/i386/Kconfig	2006-10-16 22:13:44.000000000 +0900
+++ linux-2.6.19-rc1-mm1/arch/i386/Kconfig	2006-10-16 22:22:34.000000000 +0900
@@ -1185,6 +1185,14 @@
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+config DJPROBE
+        bool "Direct Jump probe (EXPERIMENTAL)"
+	depends on KPROBES && (!PREEMPT || PM)
+	help
+	 Djprobe allows you to dynamically hook at any kernel function
+	 entry points and collect the debugging or performance analysis
+	 information non-disruptively.
 endmenu

 source "arch/i386/Kconfig.debug"
Index: linux-2.6.19-rc1-mm1/arch/i386/kernel/Makefile
===================================================================
--- linux-2.6.19-rc1-mm1.orig/arch/i386/kernel/Makefile	2006-10-16 22:13:44.000000000 +0900
+++ linux-2.6.19-rc1-mm1/arch/i386/kernel/Makefile	2006-10-16 22:22:34.000000000 +0900
@@ -29,6 +29,7 @@
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
 obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
+obj-$(CONFIG_DJPROBE)		+= stub_djprobe.o djprobe.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
Index: linux-2.6.19-rc1-mm1/arch/i386/kernel/djprobe.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.19-rc1-mm1/arch/i386/kernel/djprobe.c	2006-10-16 22:22:34.000000000 +0900
@@ -0,0 +1,143 @@
+/*
+ *  Kernel Direct Jump Probe (Djprobes)
+ *  arch/i386/kernel/djprobe.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * 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) Hitachi, Ltd. 2005,2006
+ *
+ * 2005-Aug	Created by Masami HIRAMATSU <masami.hiramatsu.pt@hitachi.com>
+ * 		Initial implementation of Direct jump probe (djprobe)
+ *              to reduce overhead.
+ */
+
+#include <linux/djprobe.h>
+#include <linux/ptrace.h>
+#include <linux/spinlock.h>
+#include <linux/preempt.h>
+#include <asm/cacheflush.h>
+#include <asm/kdebug.h>
+#include <asm/desc.h>
+#include <asm/processor.h>
+
+/*
+ * 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)
+{
+	sync_core();
+}
+
+void arch_serialize_cpus(void)
+{
+	on_each_cpu(__local_serialize_cpu, NULL, 1, 1);
+}
+
+static __always_inline void __codecopy(void *dest, const void *src, size_t size)
+{
+	memcpy(dest, src, size);
+	flush_icache_range((unsigned long)dest, (unsigned long)dest + size);
+}
+
+/* djprobe call back function: called from stub code */
+static void asmlinkage djprobe_callback(struct djprobe_instance *djpi,
+					struct pt_regs *regs)
+{
+	struct djprobe *djp;
+	rcu_read_lock();
+	list_for_each_entry_rcu(djp, &djpi->plist, plist) {
+		if (djp->handler)
+			djp->handler(djp, regs);
+	}
+	rcu_read_unlock();
+}
+
+/*
+ * Copy post processing instructions
+ * Target instructions MUST be relocatable.
+ */
+int __kprobes arch_prepare_djprobe_instance(struct djprobe_instance *djpi,
+					    struct arch_djprobe_param *param)
+{
+	kprobe_opcode_t *stub;
+	stub = djpi->stub.insn;
+	djpi->stub.size = djprobe_param_length(param);
+
+	/* 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 djporbe instance */
+	memcpy((void *)(stub + ARCH_STUB_INST_IDX),
+	       (void *)djprobe_param_address(param), djpi->stub.size);
+
+	/* set returning jmp instruction at the tail of djporbe instance */
+	set_jmp_op(stub + ARCH_STUB_INST_IDX + djpi->stub.size,
+		   djprobe_param_address(param) + djpi->stub.size);
+
+	return 0;
+}
+
+#define INT3_SIZE 1
+#define ADDR_SIZE 4
+#define JMPOP_SIZE 5
+
+void __kprobes arch_install_djprobe_instance(struct djprobe_instance *djpi)
+{
+	long rel =
+	    (long)(djpi->stub.insn) - ((long)(djpi->kp.addr) + JMPOP_SIZE);
+	/* insert the destination address only */
+	__codecopy((void *)((long)djpi->kp.addr + INT3_SIZE), (void *)&rel,
+		   ADDR_SIZE);
+}
+
+void __kprobes arch_post_install_djprobe_instance(struct djprobe_instance *djpi)
+{
+	kprobe_opcode_t op = RELATIVEJUMP_INSTRUCTION;
+	__codecopy((void *)djpi->kp.addr, (void *)&op, sizeof(kprobe_opcode_t));
+}
+
+void __kprobes arch_pre_remove_djprobe_instance(struct djprobe_instance *djpi)
+{
+	/* change (the 1st byte of) jump to int3. */
+	arch_arm_kprobe(&djpi->kp);
+}
+
+void __kprobes arch_remove_djprobe_instance(struct djprobe_instance *djpi)
+{
+	/*
+	 * recover the instructions covered by the destination address.
+	 * the int3 will be removed by unregister_kprobe()
+	 */
+	__codecopy((void *)((long)djpi->kp.addr + INT3_SIZE),
+		   (void *)((long)&djpi->stub.insn[ARCH_STUB_INST_IDX] +
+			    INT3_SIZE), ADDR_SIZE);
+}
+
+/* djprobe handler : switch to a bypass code */
+int __kprobes arch_switch_to_stub(struct djprobe_instance *djpi,
+				  struct pt_regs *regs)
+{
+	regs->eip = (unsigned long)djpi->stub.insn;
+	reset_current_kprobe();
+	preempt_enable_no_resched();
+	return 1;		/* already prepared */
+}
Index: linux-2.6.19-rc1-mm1/arch/i386/kernel/stub_djprobe.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.19-rc1-mm1/arch/i386/kernel/stub_djprobe.S	2006-10-18 11:37:28.000000000 +0900
@@ -0,0 +1,72 @@
+/*
+ *  linux/arch/i386/stub_djprobe.S
+ *
+ *  Copyright (C) Hitachi, Ltd. 2005,2006
+ *  Created by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+ */
+
+#include <linux/autoconf.h>
+
+# jmp into this function from other functions.
+.global arch_tmpl_stub_entry
+arch_tmpl_stub_entry:
+	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
+.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
+.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:
Index: linux-2.6.19-rc1-mm1/include/asm-i386/djprobe.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.19-rc1-mm1/include/asm-i386/djprobe.h	2006-10-16 22:22:34.000000000 +0900
@@ -0,0 +1,65 @@
+#ifndef _ASM_DJPROBE_H
+#define _ASM_DJPROBE_H
+/*
+ *  Kernel Direct Jump Probe (Djprobe)
+ *  include/asm-i386/djprobe.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * 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) Hitachi, Ltd. 2005,2006
+ *
+ * 2005-Aug	Created by Masami HIRAMATSU <masami.hiramatsu.pt@hitachi.com>
+ * 		Initial implementation of Direct jump probe (djprobe)
+ *              to reduce overhead.
+ */
+
+#include <asm/kprobes.h>
+
+/* 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)/sizeof(kprobe_opcode_t))
+
+#define ARCH_STUB_INSN_MAX 20
+#define ARCH_STUB_INSN_MIN 5
+
+struct arch_djprobe_stub {
+	kprobe_opcode_t *insn;
+	int size;
+};
+
+struct arch_djprobe_param {
+	kprobe_opcode_t * addr;
+	int size;
+};
+
+#define djprobe_param_address(p) ((p)->addr)
+#define djprobe_param_length(p) ((p)->size)
+
+#define DJPI_ARCH_SIZE(djpi) ((djpi)->stub.size)
+
+#endif				/* _ASM_DJPROBE_H */






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