From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30751 invoked by alias); 8 Nov 2005 13:26:40 -0000 Mailing-List: contact systemtap-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Post: List-Help: , Sender: systemtap-owner@sourceware.org Received: (qmail 30704 invoked by uid 22791); 8 Nov 2005 13:26:36 -0000 Message-ID: <4370A78A.5080609@sdl.hitachi.co.jp> Date: Tue, 08 Nov 2005 13:26:00 -0000 From: Masami Hiramatsu User-Agent: Mozilla Thunderbird 1.0.7 (Windows/20050923) X-Accept-Language: ja, en-us, en MIME-Version: 1.0 To: systemtap@sources.redhat.com Cc: Satoshi Oshima , Yumiko Sugita , Hideo Aoki Subject: [Patch 3/3][Djprobe] Djprobe update for linux-2.6.14-mm1 References: <436812F0.1080705@sdl.hitachi.co.jp> <43681B98.4020805@sdl.hitachi.co.jp> <43681BD5.2070002@sdl.hitachi.co.jp> <43681C3B.6000605@sdl.hitachi.co.jp> <436B624A.8000108@sdl.hitachi.co.jp> In-Reply-To: <436B624A.8000108@sdl.hitachi.co.jp> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-SW-Source: 2005-q4/txt/msg00164.txt.bz2 Hi, This patch is the i386 architecture dependent codes of djprobe. I removed djprobe_post_handler and djprobe_handler_lock. -- Masami HIRAMATSU 2nd Research Dept. Hitachi, Ltd., Systems Development Laboratory E-mail: hiramatu@sdl.hitachi.co.jp arch/i386/Kconfig | 8 ++ arch/i386/kernel/Makefile | 1 arch/i386/kernel/djprobe.c | 147 ++++++++++++++++++++++++++++++++++++++++ arch/i386/kernel/stub_djprobe.S | 77 ++++++++++++++++++++ include/asm-i386/djprobe.h | 51 +++++++++++++ 5 files changed, 284 insertions(+) diff -Narup linux-2.6.14-mm1.djp.2/arch/i386/Kconfig linux-2.6.14-mm1.djp.3/arch/i386/Kconfig --- linux-2.6.14-mm1.djp.2/arch/i386/Kconfig 2005-11-08 11:50:46.000000000 +0900 +++ linux-2.6.14-mm1.djp.3/arch/i386/Kconfig 2005-11-08 12:01:19.000000000 +0900 @@ -1010,6 +1010,14 @@ config KPROBES 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 + 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" diff -Narup linux-2.6.14-mm1.djp.2/arch/i386/kernel/Makefile linux-2.6.14-mm1.djp.3/arch/i386/kernel/Makefile --- linux-2.6.14-mm1.djp.2/arch/i386/kernel/Makefile 2005-11-08 11:50:46.000000000 +0900 +++ linux-2.6.14-mm1.djp.3/arch/i386/kernel/Makefile 2005-11-08 12:00:50.000000000 +0900 @@ -29,6 +29,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o 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 diff -Narup linux-2.6.14-mm1.djp.2/arch/i386/kernel/djprobe.c linux-2.6.14-mm1.djp.3/arch/i386/kernel/djprobe.c --- linux-2.6.14-mm1.djp.2/arch/i386/kernel/djprobe.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.14-mm1.djp.3/arch/i386/kernel/djprobe.c 2005-11-08 12:00:50.000000000 +0900 @@ -0,0 +1,147 @@ +/* + * 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 + * + * 2005-Aug Created by Masami HIRAMATSU + * Initial implementation of Direct jump probe (djprobe) + * to reduce overhead. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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, int sync) +{ + struct __arch_jmp_op *jop; + jop = (struct __arch_jmp_op *)from; + jop->raddr=(long)(to) - ((long)(from) + 5); + mb(); + if (sync) 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; + jop->raddr = jop2->raddr; + mb(); + smp_serialize_cpus(); +} + +/* 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, + unsigned long size) +{ + kprobe_opcode_t *stub; + stub = djpi->stub.insn; + djpi->stub.size = size; + + /* 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*)djpi->kp.addr, size); + + /* set returning jmp instruction at the tail of djporbe instance*/ + __set_jmp_op(stub + ARCH_STUB_INST_IDX + size, + (void*)((long)djpi->kp.addr + size), 0); + + return 0; +} + +/* Insert "jmp" instruction into the probing point. */ +void __kprobes arch_install_djprobe_instance(struct djprobe_instance *djpi) +{ + __set_jmp_op((void*)djpi->kp.addr, (void*)djpi->stub.insn, 1); +} + +/* Write back original instructions & kprobe */ +void __kprobes arch_uninstall_djprobe_instance(struct djprobe_instance *djpi) +{ + __set_breakpoint_op((void*)djpi->kp.addr, + (void*)&djpi->stub.insn[ARCH_STUB_INST_IDX]); +} + +/* djprobe handler : switch to a bypass code */ +int __kprobes djprobe_pre_handler(struct kprobe * kp, struct pt_regs * regs) +{ + struct djprobe_instance *djpi = + container_of(kp,struct djprobe_instance, kp); + + if (!DJPI_EMPTY(djpi)) { + regs->eip = (unsigned long)djpi->stub.insn; + reset_current_kprobe(); + preempt_enable_no_resched(); + return 1; /* already prepared */ + } + return 0; +} diff -Narup linux-2.6.14-mm1.djp.2/arch/i386/kernel/stub_djprobe.S linux-2.6.14-mm1.djp.3/arch/i386/kernel/stub_djprobe.S --- linux-2.6.14-mm1.djp.2/arch/i386/kernel/stub_djprobe.S 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.14-mm1.djp.3/arch/i386/kernel/stub_djprobe.S 2005-11-08 12:00:50.000000000 +0900 @@ -0,0 +1,77 @@ +/* + * linux/arch/i386/stub_djprobe.S + * + * Copyright (C) HITACHI,LTD. 2005 + * Created by Masami Hiramatsu + */ + +#include + +# 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.14-mm1.djp.2/include/asm-i386/djprobe.h linux-2.6.14-mm1.djp.3/include/asm-i386/djprobe.h --- linux-2.6.14-mm1.djp.2/include/asm-i386/djprobe.h 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.14-mm1.djp.3/include/asm-i386/djprobe.h 2005-11-08 12:00:50.000000000 +0900 @@ -0,0 +1,51 @@ +#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 + * + * 2005-Aug Created by Masami HIRAMATSU + * Initial implementation of Direct jump probe (djprobe) + * to reduce overhead. + */ + +#define RELATIVEJUMP_INSTRUCTION 0xe9 + +/* 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) + +#endif /* _ASM_DJPROBE_H */