This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[RFC][kprobe](djprobe) djprobe examples
- 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>, Ingo Molnar <mingo at redhat dot com>, SystemTAP <systemtap at sources dot redhat dot com>, Ananth N Mavinakayanahalli <ananth at in dot ibm dot com>, Prasanna S Panchamukhi <prasanna at in dot ibm 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>, Jim Keniston <jkenisto at us dot ibm dot com>, Martin Bligh <mbligh at google dot com>, Greg Kroah-Hartman <gregkh at suse dot de>
- Date: Tue, 21 Nov 2006 15:59:11 +0900
- Subject: [RFC][kprobe](djprobe) djprobe examples
- Organization: Systems Development Lab., Hitachi, Ltd., Japan
- References: <4562A150.2030606@hitachi.com>
Hi,
I also updated djprobe example code.
I attached it and a helper script.
NOTE:
Currently, this helper script can ONLY measure the *LENGTH* of the
instruction-block which will be overwritten by a jump code. It can
*NOT CHECK* whether this instruction-block can be executed out of
line (relocatable) and no branch jumps into the target area.
However, now we're developing more useful helper tool which can
check it.
Here is the example of usage;
1) Analyze the kernel code by using the helper script.
$ ./disym.sh sys_symlink
sys_symlink
0xc017bbe0
/lib/modules/2.6.19-rc1-mm1/build/vmlinux: file format elf32-i386
Disassembly of section .text:
c017bbe0 <sys_symlink>:
c017bbe0: 83 ec 0c sub $0xc,%esp
c017bbe3: 8b 44 24 14 mov 0x14(%esp),%eax
Please be sure that the above-disassembled instructions are relocatable.
Parameter: addr=0xc017bbe0 size=7
2) If the instructions can be executed out of line (ex. load/store,
compare, add/sub, etc.) and no branch jumps into it (you can dump whole
of the function by using disym.sh with '-a' option),
Install the example module with the above parameters.
$ sudo /sbin/insmod ./djprobe_ex.ko addr=0xc017bbe0 size=7
3) and test it.
$ ln -s foo bar
$ dmesg | tail -n 4
probe install at c017bbe0, size 7
Stopping tasks: =======================================|
Restarting tasks... done
probe call:c017bbe0, caller:c01030c5
$ rm bar
$ ln -s foo bar
$ dmesg | tail -n 5
probe install at c017bbe0, size 7
Stopping tasks: =======================================|
Restarting tasks... done
probe call:c017bbe0, caller:c01030c5
probe call:c017bbe0, caller:c01030c5
4) Finally, remove the module.
$ sudo /sbin/rmmod djprobe_ex.ko
$ dmesg | tail -n 8
probe install at c017bbe0, size 7
Stopping tasks: =======================================|
Restarting tasks... done
probe call:c017bbe0, caller:c01030c5
probe call:c017bbe0, caller:c01030c5
probe uninstall at c017bbe0
Stopping tasks: =======================================|
Restarting tasks... done
Thanks,
--
Masami HIRAMATSU
Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com
#!/bin/sh
# Copyright (C) HITACHI, Ltd. 2005
# Created by M.Hiramatsu <hiramatu@sdl.hitachi.co.jp>
[ $# -gt 3 -o $# -lt 1 ] && echo "usage: disym.sh [-a] <kernel_symbol> [kernel-version]" && exit 0
DISALL=0
if [ $1 = "-a" ] ;then
DISALL=1
shift 1
fi
SYM=$1
KVER=$2
[ -z "$KVER" ] && KVER=`uname -r`
function cntarg () {
return $#
}
SYSMAP=/lib/modules/$KVER/build/System.map
[ -f $SYSMAP ] || SYSMAP=/boot/System.map-`uname -r`
[ -f $SYSMAP ] || SYSMAP=/proc/kallsyms
VMLINUX=/lib/modules/$KVER/build/vmlinux
[ -f $VMLINUX ] || VMLINUX=/boot/vmlinux-`uname -r`
[ -f $VMLINUX ] || VMLINUX=/usr/lib/debug/lib/modules/$KVER/vmlinux
setaddrs () {
XADDR=$1
XEADDR=$2
}
echo $SYM
case $SYM in
0x*)
XADDR=$SYM
SADDR=`printf "%d" $SYM`
EADDR=`expr $SADDR + 5`
;;
*)
if [ $DISALL -eq 1 ] ;then
setaddrs `sort $SYSMAP | grep -A1 " $SYM"$ | cut -f 1 -d\ `
if [ -z "$XADDR" ] ; then
echo "Error : $SYM was not found in "$SYSMAP
exit 0;
fi
XADDR=0x$XADDR
XEADDR=0x$XEADDR
SADDR=`printf "%d" $XADDR`
EADDR=`printf "%d" $XEADDR`
else
XADDR=0x`grep " $SYM"$ $SYSMAP | cut -f 1 -d\ `
if [ "$XADDR" = "0x" ] ; then
echo "Error : $SYM was not found in "$SYSMAP
exit 0;
fi
SADDR=`printf "%d" $XADDR`
EADDR=`expr $SADDR + 5`
fi
;;
esac
echo $XADDR
objdump -w --start-address=$SADDR --stop-address=$EADDR -j ".text" -d $VMLINUX
echo
LLINE=`objdump -w --start-address=$SADDR --stop-address=$EADDR -j ".text" -d $VMLINUX | tail -n 1 | sed s/" "/\:/g`
EXADDR=`echo $LLINE | cut -f 1 -d:`
cntarg `echo $LLINE | cut -f 3 -d:`
DIFF=$?
EADDR=`printf "%d" 0x$EXADDR`
SIZE=`expr $EADDR - $SADDR + $DIFF`
echo "Please be sure that the above-disassembled instructions are relocatable."
echo "Parameter: addr=$XADDR size=$SIZE"
/*
djprobe_ex.c -- Direct Jump Probe Example
Copyright (c) 2005,2006 Hitachi,Ltd.,
Created by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
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
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/rcupdate.h>
#include <linux/kprobes.h>
static long addr=0;
module_param(addr, long, 0444);
static long offs=0;
module_param(offs, long, 0444);
static long size=0;
module_param(size, long, 0444);
static long show_arg=0;
module_param(show_arg, long, 0444);
#define CALLER(regs) (((unsigned long *)®s->esp)[0])
#define ARG(n,regs) (((unsigned long *)®s->esp)[n]) /*arg1: ARG(1,stadr)*/
static int probe_func(struct kprobe *kp, struct pt_regs *regs)
{
int i;
printk("probe call:%p, caller:%lx",
(void*)kp->addr, CALLER(regs));
for (i = 1; i <= show_arg; i++) {
printk(" arg[%d]:%lx", i, ARG(i, regs));
}
printk("\n");
return 0;
}
static struct kprobe kp;
static int install_probe(void)
{
if (addr == 0) {
return -EINVAL;
}
printk("probe install at 0x%p+0x%lx, size %ld\n",
(void*)addr, offs, size);
kp.pre_handler = probe_func;
kp.addr = (void *)addr;
kp.length = size;
if (register_kprobe(&kp) != 0) return -1;
commit_kprobes();
return 0;
}
static void uninstall_probe(void)
{
unregister_kprobe(&kp);
printk("probe uninstall at %p\n", (void*)addr);
commit_kprobes(); /* commit for safety */
}
module_init(install_probe);
module_exit(uninstall_probe);
MODULE_AUTHOR("M.Hiramatsu <masami.hiramatsu.pt@hitachi.com>");
MODULE_LICENSE("GPL");