Skip to content

Commit

Permalink
Kprobes: move kprobe examples to samples/
Browse files Browse the repository at this point in the history
Move kprobes examples from Documentation/kprobes.txt to under samples/.
Patch originally by Randy Dunlap.

o Updated the patch to apply on 2.6.25-rc3
o Modified examples code to build on multiple architectures. Currently,
  the kprobe and jprobe examples code works for x86 and powerpc
o Cleaned up unneeded #includes
o Cleaned up Kconfig per Sam Ravnborg's suggestions to fix build break
  on archs that don't have kretprobes
o Implemented suggestions by Mathieu Desnoyers on CONFIG_KRETPROBES
o Included Andrew Morton's cleanup based on x86-git
o Modified kretprobe_example to act as a arch-agnostic module to
  determine routine execution times:
	Use 'modprobe kretprobe_example func=<func_name>' to determine
	execution time of func_name in nanoseconds.

Signed-off-by: Randy Dunlap <[email protected]>
Signed-off-by: Ananth N Mavinakayanahalli <[email protected]>
Acked-by: Mathieu Desnoyers <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Ananth N Mavinakayanahalli authored and Linus Torvalds committed Mar 5, 2008
1 parent 9edddaa commit 804defe
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 239 deletions.
243 changes: 5 additions & 238 deletions Documentation/kprobes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ code mapping.
The Kprobes API includes a "register" function and an "unregister"
function for each type of probe. Here are terse, mini-man-page
specifications for these functions and the associated probe handlers
that you'll write. See the latter half of this document for examples.
that you'll write. See the files in the samples/kprobes/ sub-directory
for examples.

4.1 register_kprobe

Expand Down Expand Up @@ -420,249 +421,15 @@ e. Watchpoint probes (which fire on data references).

8. Kprobes Example

Here's a sample kernel module showing the use of kprobes to dump a
stack trace and selected i386 registers when do_fork() is called.
----- cut here -----
/*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, eip=%lx, eflags=0x%lx\n",
p->addr, regs->eip, 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 pre- or post-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, trap #%dn",
p->addr, trapnr);
/* Return 0 because we don't handle the fault. */
return 0;
}

static int __init kprobe_init(void)
{
int ret;
kp.pre_handler = handler_pre;
kp.post_handler = handler_post;
kp.fault_handler = handler_fault;
kp.symbol_name = "do_fork";

ret = register_kprobe(&kp);
if (ret < 0) {
printk("register_kprobe failed, returned %d\n", ret);
return ret;
}
printk("kprobe registered\n");
return 0;
}

static void __exit kprobe_exit(void)
{
unregister_kprobe(&kp);
printk("kprobe unregistered\n");
}

module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");
----- cut here -----

You can build the kernel module, kprobe-example.ko, using the following
Makefile:
----- cut here -----
obj-m := kprobe-example.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -f *.mod.c *.ko *.o
----- cut here -----

$ make
$ su -
...
# insmod kprobe-example.ko

You will see the trace data in /var/log/messages and on the console
whenever do_fork() is invoked to create a new process.
See samples/kprobes/kprobe_example.c

9. Jprobes Example

Here's a sample kernel module showing the use of jprobes to dump
the arguments of do_fork().
----- cut here -----
/*jprobe-example.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 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%lx, stack_size=0x%lx, regs=0x%p\n",
clone_flags, stack_size, regs);
/* Always end with a call to jprobe_return(). */
jprobe_return();
/*NOTREACHED*/
return 0;
}

static struct jprobe my_jprobe = {
.entry = jdo_fork
};

static int __init jprobe_init(void)
{
int ret;
my_jprobe.kp.symbol_name = "do_fork";

if ((ret = register_jprobe(&my_jprobe)) <0) {
printk("register_jprobe failed, returned %d\n", ret);
return -1;
}
printk("Planted jprobe at %p, handler addr %p\n",
my_jprobe.kp.addr, my_jprobe.entry);
return 0;
}

static void __exit jprobe_exit(void)
{
unregister_jprobe(&my_jprobe);
printk("jprobe unregistered\n");
}

module_init(jprobe_init)
module_exit(jprobe_exit)
MODULE_LICENSE("GPL");
----- cut here -----

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 whenever do_fork() is invoked to create a new process.
(Some messages may be suppressed if syslogd is configured to
eliminate duplicate messages.)
See samples/kprobes/jprobe_example.c

10. Kretprobes Example

Here's a sample kernel module showing the use of return probes to
report failed calls to sys_open().
----- cut here -----
/*kretprobe-example.c*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/ktime.h>

/* per-instance private data */
struct my_data {
ktime_t entry_stamp;
};

static const char *probed_func = "sys_open";

/* Timestamp function entry. */
static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
struct my_data *data;

if(!current->mm)
return 1; /* skip kernel threads */

data = (struct my_data *)ri->data;
data->entry_stamp = ktime_get();
return 0;
}

/* If the probed function failed, log the return value and duration.
* Duration may turn out to be zero consistently, depending upon the
* granularity of time accounting on the platform. */
static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
int retval = regs_return_value(regs);
struct my_data *data = (struct my_data *)ri->data;
s64 delta;
ktime_t now;

if (retval < 0) {
now = ktime_get();
delta = ktime_to_ns(ktime_sub(now, data->entry_stamp));
printk("%s: return val = %d (duration = %lld ns)\n",
probed_func, retval, delta);
}
return 0;
}

static struct kretprobe my_kretprobe = {
.handler = return_handler,
.entry_handler = entry_handler,
.data_size = sizeof(struct my_data),
.maxactive = 20, /* probe up to 20 instances concurrently */
};

static int __init kretprobe_init(void)
{
int ret;
my_kretprobe.kp.symbol_name = (char *)probed_func;

if ((ret = register_kretprobe(&my_kretprobe)) < 0) {
printk("register_kretprobe failed, returned %d\n", ret);
return -1;
}
printk("Kretprobe active on %s\n", my_kretprobe.kp.symbol_name);
return 0;
}

static void __exit kretprobe_exit(void)
{
unregister_kretprobe(&my_kretprobe);
printk("kretprobe unregistered\n");
/* nmissed > 0 suggests that maxactive was set too low. */
printk("Missed probing %d instances of %s\n",
my_kretprobe.nmissed, probed_func);
}

module_init(kretprobe_init)
module_exit(kretprobe_exit)
MODULE_LICENSE("GPL");
----- cut here -----

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 whenever sys_open() returns a negative value. (Some messages
may be suppressed if syslogd is configured to eliminate duplicate
messages.)
See samples/kprobes/kretprobe_example.c

For additional information on Kprobes, refer to the following URLs:
http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe
Expand Down
11 changes: 11 additions & 0 deletions samples/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,16 @@ config SAMPLE_KOBJECT

If in doubt, say "N" here.

config SAMPLE_KPROBES
tristate "Build kprobes examples -- loadable modules only"
depends on KPROBES && m
help
This build several kprobes example modules.

config SAMPLE_KRETPROBES
tristate "Build kretprobes example -- loadable modules only"
default m
depends on SAMPLE_KPROBES && KRETPROBES

endif # SAMPLES

2 changes: 1 addition & 1 deletion samples/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Makefile for Linux samples code

obj-$(CONFIG_SAMPLES) += markers/ kobject/
obj-$(CONFIG_SAMPLES) += markers/ kobject/ kprobes/
5 changes: 5 additions & 0 deletions samples/kprobes/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# builds the kprobes example kernel modules;
# then to use one (as root): insmod <module_name.ko>

obj-$(CONFIG_SAMPLE_KPROBES) += kprobe_example.o jprobe_example.o
obj-$(CONFIG_SAMPLE_KRETPROBES) += kretprobe_example.o
68 changes: 68 additions & 0 deletions samples/kprobes/jprobe_example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Here's a sample kernel module showing the use of jprobes to dump
* the arguments of do_fork().
*
* For more information on theory of operation of jprobes, see
* Documentation/kprobes.txt
*
* Build and insert the kernel module as done in the kprobe example.
* You will see the trace data in /var/log/messages and on the
* console whenever do_fork() is invoked to create a new process.
* (Some messages may be suppressed if syslogd is configured to
* eliminate duplicate messages.)
*/

#include <linux/kernel.h>
#include <linux/module.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 actual do_fork() routine */
static 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(KERN_INFO "jprobe: clone_flags = 0x%lx, stack_size = 0x%lx,"
" regs = 0x%p\n",
clone_flags, stack_size, regs);

/* Always end with a call to jprobe_return(). */
jprobe_return();
return 0;
}

static struct jprobe my_jprobe = {
.entry = jdo_fork,
.kp = {
.symbol_name = "do_fork",
},
};

static int __init jprobe_init(void)
{
int ret;

ret = register_jprobe(&my_jprobe);
if (ret < 0) {
printk(KERN_INFO "register_jprobe failed, returned %d\n", ret);
return -1;
}
printk(KERN_INFO "Planted jprobe at %p, handler addr %p\n",
my_jprobe.kp.addr, my_jprobe.entry);
return 0;
}

static void __exit jprobe_exit(void)
{
unregister_jprobe(&my_jprobe);
printk(KERN_INFO "jprobe at %p unregistered\n", my_jprobe.kp.addr);
}

module_init(jprobe_init)
module_exit(jprobe_exit)
MODULE_LICENSE("GPL");
Loading

0 comments on commit 804defe

Please sign in to comment.