This is the mail archive of the systemtap@sources.redhat.com 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]

Kprobes document


Hi Jim,

Few months back I had written a template document on kprobes.
Please review and update the contents. I have not added an example
 and description for kretprobes. Could you please add the description
and example for kretprobes.

Thanks
Prasanna

Authors : Prasanna S Panchamukhi <prasanna@in.ibm.com>
	: James Keniston <kenistoj@us.ibm.com>

INDEX

1. Kprobes and Jprobes concepts
2. Configuration and Build 
3. Kprobes Features
4. Architectures Supported
5. TODO
6. Kprobes example
7. Jprobes example
8. Kretprobes example (required to be added).

Kprobes and Jprobes concepts

The basic idea of Kprobes is to dynamically break into any kernel routine
and collect the debugging information non-disruptively. Developers can trap
at almost any kernel code address, specifying a handler routine to be invoked
when the breakpoint is hit. Employs single-stepping out-of-line to avoid probe
misses on SMP and may be especially useful in aiding debugging elusive races
and problems on live systems. More elaborate dynamic tracing tools can be built
over the kprobes interface.

A special kprobe type which can be placed on function entry points, and employs
a simple mirroring principle to allow seamless access to the arguments of a
function being probed. The probe handler routine should have the same prototype
as the function being probed.

The way it works is that when the probe is hit, the breakpoint handler simply
irets to the probe handler's eip while retaining register and stack state
corresponding to the function entry. After it is done, the probe handler calls
jprobe_return() which traps again to restore processor state and switch back to
the probed function. Linus noted correctly at KS that we need to be careful as
gcc assumes that the callee owns arguments. We save and restore enough stack
bytes to cover argument space.

Configuration and Build kernel
Ensure CONFIG_KPROBES is set to "y" while configuring the kernel using
make menuconfig/xconfig/oldconfig. 
Build the kernel and reboot with the new kernel.
$make oldconfig
$make bzImage

Kprobes Features :

1. Multiple handlers can be registered at the same probe address.
2. Kretprobes-probes can also be placed on the function exit, to track the
   return values.
3. Now reentrant probes are temporarily disarmed instead of disarming it
   permantently. 

Architectures Supported :
1. i386
2. x86_64/AMD64
3. PPC64
4. IA64
5. sparc64

TODO:

1. Systemtap: Work in progress to provide simple programming interface to write
   probes handlers.
2. Scalability support : Currently work is in progress to run multiple kprobes 
   in parallel.
3. Kernel return probes for sparc64.
4. Support for other architectures.

Example: Kprobes

A sample kernel module to show usage of kprobes to dump the stack trace,
processor register when do_fork() routine is called.
/*kprobe_example.c*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/sched.h>
/*For each probe you need to allocate a kprobe structure*/

static struct kprobe kp;

/*kprobe pre_handler: called just before the probed instruction is executed*/

int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
	printk("pre_handler: p->addr=0x%p, eflags=0x%lx\n", p->addr,
	       regs->eflags);
	dump_stack();
	return 0;
}

/*kprobe post_handler: called after the probed instruction is executed*/

void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
{
	printk("post_handler: p->addr=0x%p, eflags=0x%lx \n", p->addr,
	       regs->eflags);
}

/* fault_handler: this is called if an exception is generated for any
 * instruction within the fault-handler, or when Kprobes
 * single-steps the probed instruction.
 */
int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
	printk("fault_handler:p->addr=0x%p, eflags=0x%lx\n", p->addr,
	       regs->eflags);
	return 0;
}

int init_module(void)
{
	int ret;
	kp.pre_handler = handler_pre;
	kp.post_handler = handler_post;
	kp.fault_handler = handler_fault;
	kp.addr = kallsyms_lookup_name("do_fork");
	/* register the kprobe now */
	if (!kp.addr) {
		printk("kprobe not registered\n");
		return -1;
	}
	if ((ret = register_kprobe(&kp) < 0))
		return ~ENOSYS;
	printk("kprobe registered\n");
	return 0;
}

void cleanup_module(void)
{
	unregister_kprobe(&kp);
	printk("kprobe unregistered\n");
}

MODULE_LICENSE("GPL");

Build the kernel module kprobe-example.o.

$mkdir MOD
$cp kprobe-example.c /home/kprobe/MOD/.
$cd /home/kprobe/MOD/
$echo "obj-m := kprobe-example.o" > Makefile
$make -C /usr/src/linux SUBDIRS=$PWD modules
Now insert the kernel module. 
$insmod kprobe-example.ko

You will see the trace data in /var/log/messages and on the console when 
do_fork() is invoked.

For additional information on kprobes refer to the following URL:
www.ibm.com/developerworks/linux/library/l-kprobes.htm

Example: Jprobes
A sample kernel module to show usage of jprobes to dump the arguments of the
routine do_fork(). 

/*jprobes-sample.c */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uio.h>
#include <linux/kprobes.h>

/* 
 * Jumper probe for do_fork. 
 * Mirror principle enables access to arguments of the probed routine 
 * from the probe handler.
 */

/* Proxy routine having the same arguments as that of actual do_fork() routine */

long jdo_fork(unsigned long clone_flags, unsigned long stack_start,
	      struct pt_regs *regs, unsigned long stack_size,
	      int __user * parent_tidptr, int __user * child_tidptr)
{
	printk("jprobe: clone_flags=0x%x,  stack_size=0x%x, pt_regs=0x%x",
	       clone_flags, stack_size, pt_regs);
	/* dont forget to do a jprobe_return() */
	jprobe_return();
}

static struct jprobe my_jprobe = {
	.entry = (kprobe_opcode_t *) jdo_fork
};

int init_module(void)
{
	int ret;
	/* first time invokation to initialize probe handler */

	my_jprobe.kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name("do_fork");
	if (!my_jprobe.kp.addr) {
		printk("couldn't find %s to plant jprobe\n", "do_fork");
		return -1;
	}

	/* now we are all set to register the probe */
	if ((ret = register_jprobe(&my_jprobe)) <0)
		return -ENOSYS;
	printk("plant jprobe at %p, handler addr %p\n",
	       my_jprobe.kp.addr, my_jprobe.entry);
	return 0;
}

void cleanup_module(void)
{
	unregister_jprobe(&my_jprobe);
	printk("jprobe unregistered\n");
}

MODULE_LICENSE("GPL");

Build and insert the kernel module as shown in the above kprobe example. You
will see the trace data in /var/log/messages and on the console when do_fork()
invoked.
-- 

Prasanna S Panchamukhi
Linux Technology Center
India Software Labs, IBM Bangalore
Ph: 91-80-25044636
<prasanna@in.ibm.com>


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