From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9485 invoked by alias); 19 Oct 2006 09:03:50 -0000 Received: (qmail 9470 invoked by uid 22791); 19 Oct 2006 09:03:47 -0000 X-Spam-Status: No, hits=0.2 required=5.0 tests=AWL,BAYES_00,TW_DJ,TW_JP,UNPARSEABLE_RELAY X-Spam-Check-By: sourceware.org Received: from mail9.hitachi.co.jp (HELO mail9.hitachi.co.jp) (133.145.228.44) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 19 Oct 2006 09:03:44 +0000 Received: from mlsv7.hitachi.co.jp (unknown [133.145.228.16]) by mail9.hitachi.co.jp (Postfix) with ESMTP id CB6EA37C9A for ; Thu, 19 Oct 2006 18:03:41 +0900 (JST) Received: from mfilter-s3.hitachi.co.jp by mlsv7.hitachi.co.jp (8.12.11/8.12.11) id k9J93e06021218; Thu, 19 Oct 2006 18:03:40 +0900 Received: from vshuts5.hitachi.co.jp (unverified) by mfilter-s3.hitachi.co.jp (Content Technologies SMTPRS 4.3.17) with SMTP id ; Thu, 19 Oct 2006 18:03:40 +0900 Received: from hsdlgw92.sdl.hitachi.co.jp ([133.144.7.20]) by vshuts5.hitachi.co.jp with SMTP id M2006101918033818488 ; Thu, 19 Oct 2006 18:03:40 +0900 Received: from vgate2.sdl.hitachi.co.jp by hsdlgw92.sdl.hitachi.co.jp (8.9.3/3.7W06061314) id SAA20854; Thu, 19 Oct 2006 18:03:36 +0900 Received: from maila.sdl.hitachi.co.jp ([133.144.14.196]) by vgate2.sdl.hitachi.co.jp (SAVSMTP 3.1.1.32) with SMTP id M2006101918033704267 ; Thu, 19 Oct 2006 18:03:37 +0900 Received: from [127.0.0.1] ([10.232.9.172]) by maila.sdl.hitachi.co.jp (8.13.1/3.7W04031011) with ESMTP id k9J93bm8006553; Thu, 19 Oct 2006 18:03:37 +0900 Message-ID: <45373F55.80206@hitachi.com> Date: Thu, 19 Oct 2006 09:03:00 -0000 From: Masami Hiramatsu Organization: Systems Development Lab., Hitachi, Ltd., Japan User-Agent: Thunderbird 1.5.0.7 (Windows/20060909) MIME-Version: 1.0 To: "Keshavamurthy, Anil S" , Ananth N Mavinakayanahalli , Prasanna S Panchamukhi , Ingo Molnar , SystemTAP Cc: Masami Hiramatsu , Satoshi Oshima , Hideo Aoki , Yumiko Sugita Subject: [PATCH 4/5][djprobe] djprobe for i386 architecture code References: <45338593.6090207@hitachi.com> In-Reply-To: <45338593.6090207@hitachi.com> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Mailing-List: contact systemtap-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Post: List-Help: , Sender: systemtap-owner@sourceware.org X-SW-Source: 2006-q4/txt/msg00180.txt.bz2 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 + * Initial implementation of Direct jump probe (djprobe) + * to reduce overhead. + */ + +#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) +{ + 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 + */ + +#include + +# 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 + * Initial implementation of Direct jump probe (djprobe) + * to reduce overhead. + */ + +#include + +/* 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 */