This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[PATCH 4/5][djprobe] djprobe for i386 architecture code
- From: Masami Hiramatsu <masami dot hiramatsu dot pt at hitachi dot com>
- To: "Keshavamurthy, Anil S" <anil dot s dot keshavamurthy at intel dot com>, Ananth N Mavinakayanahalli <ananth at in dot ibm dot com>, Prasanna S Panchamukhi <prasanna at in dot ibm dot com>, Ingo Molnar <mingo at redhat dot com>, SystemTAP <systemtap at sources dot redhat dot com>
- Cc: Masami Hiramatsu <masami dot hiramatsu dot pt at hitachi dot com>, Satoshi Oshima <soshima at redhat dot com>, Hideo Aoki <haoki at redhat dot com>, Yumiko Sugita <yumiko dot sugita dot yf at hitachi dot com>
- Date: Thu, 19 Oct 2006 18:03:17 +0900
- Subject: [PATCH 4/5][djprobe] djprobe for i386 architecture code
- Organization: Systems Development Lab., Hitachi, Ltd., Japan
- References: <45338593.6090207@hitachi.com>
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 */