diff options
author | Ananth N Mavinakayanahalli <ananth@in.ibm.com> | 2008-03-04 17:28:38 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-03-04 19:35:11 -0500 |
commit | 804defea1c020d5c52985685e56986f1a399acde (patch) | |
tree | dd91b81d272522ec8e5e482408734dd290fed152 /samples | |
parent | 9edddaa200df18e08fe0cf21036e8ae467b1363c (diff) |
Kprobes: move kprobe examples to samples/
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 <randy.dunlap@oracle.com>
Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Acked-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'samples')
-rw-r--r-- | samples/Kconfig | 11 | ||||
-rw-r--r-- | samples/Makefile | 2 | ||||
-rw-r--r-- | samples/kprobes/Makefile | 5 | ||||
-rw-r--r-- | samples/kprobes/jprobe_example.c | 68 | ||||
-rw-r--r-- | samples/kprobes/kprobe_example.c | 91 | ||||
-rw-r--r-- | samples/kprobes/kretprobe_example.c | 106 |
6 files changed, 282 insertions, 1 deletions
diff --git a/samples/Kconfig b/samples/Kconfig index 74d97cc2478..e1fb471cc50 100644 --- a/samples/Kconfig +++ b/samples/Kconfig | |||
@@ -22,5 +22,16 @@ config SAMPLE_KOBJECT | |||
22 | 22 | ||
23 | If in doubt, say "N" here. | 23 | If in doubt, say "N" here. |
24 | 24 | ||
25 | config SAMPLE_KPROBES | ||
26 | tristate "Build kprobes examples -- loadable modules only" | ||
27 | depends on KPROBES && m | ||
28 | help | ||
29 | This build several kprobes example modules. | ||
30 | |||
31 | config SAMPLE_KRETPROBES | ||
32 | tristate "Build kretprobes example -- loadable modules only" | ||
33 | default m | ||
34 | depends on SAMPLE_KPROBES && KRETPROBES | ||
35 | |||
25 | endif # SAMPLES | 36 | endif # SAMPLES |
26 | 37 | ||
diff --git a/samples/Makefile b/samples/Makefile index 8652d0f268a..2e02575f779 100644 --- a/samples/Makefile +++ b/samples/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | # Makefile for Linux samples code | 1 | # Makefile for Linux samples code |
2 | 2 | ||
3 | obj-$(CONFIG_SAMPLES) += markers/ kobject/ | 3 | obj-$(CONFIG_SAMPLES) += markers/ kobject/ kprobes/ |
diff --git a/samples/kprobes/Makefile b/samples/kprobes/Makefile new file mode 100644 index 00000000000..68739bc4fc6 --- /dev/null +++ b/samples/kprobes/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # builds the kprobes example kernel modules; | ||
2 | # then to use one (as root): insmod <module_name.ko> | ||
3 | |||
4 | obj-$(CONFIG_SAMPLE_KPROBES) += kprobe_example.o jprobe_example.o | ||
5 | obj-$(CONFIG_SAMPLE_KRETPROBES) += kretprobe_example.o | ||
diff --git a/samples/kprobes/jprobe_example.c b/samples/kprobes/jprobe_example.c new file mode 100644 index 00000000000..b7541355b92 --- /dev/null +++ b/samples/kprobes/jprobe_example.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Here's a sample kernel module showing the use of jprobes to dump | ||
3 | * the arguments of do_fork(). | ||
4 | * | ||
5 | * For more information on theory of operation of jprobes, see | ||
6 | * Documentation/kprobes.txt | ||
7 | * | ||
8 | * Build and insert the kernel module as done in the kprobe example. | ||
9 | * You will see the trace data in /var/log/messages and on the | ||
10 | * console whenever do_fork() is invoked to create a new process. | ||
11 | * (Some messages may be suppressed if syslogd is configured to | ||
12 | * eliminate duplicate messages.) | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kprobes.h> | ||
18 | |||
19 | /* | ||
20 | * Jumper probe for do_fork. | ||
21 | * Mirror principle enables access to arguments of the probed routine | ||
22 | * from the probe handler. | ||
23 | */ | ||
24 | |||
25 | /* Proxy routine having the same arguments as actual do_fork() routine */ | ||
26 | static long jdo_fork(unsigned long clone_flags, unsigned long stack_start, | ||
27 | struct pt_regs *regs, unsigned long stack_size, | ||
28 | int __user *parent_tidptr, int __user *child_tidptr) | ||
29 | { | ||
30 | printk(KERN_INFO "jprobe: clone_flags = 0x%lx, stack_size = 0x%lx," | ||
31 | " regs = 0x%p\n", | ||
32 | clone_flags, stack_size, regs); | ||
33 | |||
34 | /* Always end with a call to jprobe_return(). */ | ||
35 | jprobe_return(); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static struct jprobe my_jprobe = { | ||
40 | .entry = jdo_fork, | ||
41 | .kp = { | ||
42 | .symbol_name = "do_fork", | ||
43 | }, | ||
44 | }; | ||
45 | |||
46 | static int __init jprobe_init(void) | ||
47 | { | ||
48 | int ret; | ||
49 | |||
50 | ret = register_jprobe(&my_jprobe); | ||
51 | if (ret < 0) { | ||
52 | printk(KERN_INFO "register_jprobe failed, returned %d\n", ret); | ||
53 | return -1; | ||
54 | } | ||
55 | printk(KERN_INFO "Planted jprobe at %p, handler addr %p\n", | ||
56 | my_jprobe.kp.addr, my_jprobe.entry); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static void __exit jprobe_exit(void) | ||
61 | { | ||
62 | unregister_jprobe(&my_jprobe); | ||
63 | printk(KERN_INFO "jprobe at %p unregistered\n", my_jprobe.kp.addr); | ||
64 | } | ||
65 | |||
66 | module_init(jprobe_init) | ||
67 | module_exit(jprobe_exit) | ||
68 | MODULE_LICENSE("GPL"); | ||
diff --git a/samples/kprobes/kprobe_example.c b/samples/kprobes/kprobe_example.c new file mode 100644 index 00000000000..a681998a871 --- /dev/null +++ b/samples/kprobes/kprobe_example.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * NOTE: This example is works on x86 and powerpc. | ||
3 | * Here's a sample kernel module showing the use of kprobes to dump a | ||
4 | * stack trace and selected registers when do_fork() is called. | ||
5 | * | ||
6 | * For more information on theory of operation of kprobes, see | ||
7 | * Documentation/kprobes.txt | ||
8 | * | ||
9 | * You will see the trace data in /var/log/messages and on the console | ||
10 | * whenever do_fork() is invoked to create a new process. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/kprobes.h> | ||
16 | |||
17 | /* For each probe you need to allocate a kprobe structure */ | ||
18 | static struct kprobe kp = { | ||
19 | .symbol_name = "do_fork", | ||
20 | }; | ||
21 | |||
22 | /* kprobe pre_handler: called just before the probed instruction is executed */ | ||
23 | static int handler_pre(struct kprobe *p, struct pt_regs *regs) | ||
24 | { | ||
25 | #ifdef CONFIG_X86 | ||
26 | printk(KERN_INFO "pre_handler: p->addr = 0x%p, ip = %lx," | ||
27 | " flags = 0x%lx\n", | ||
28 | p->addr, regs->ip, regs->flags); | ||
29 | #endif | ||
30 | #ifdef CONFIG_PPC | ||
31 | printk(KERN_INFO "pre_handler: p->addr = 0x%p, nip = 0x%lx," | ||
32 | " msr = 0x%lx\n", | ||
33 | p->addr, regs->nip, regs->msr); | ||
34 | #endif | ||
35 | |||
36 | /* A dump_stack() here will give a stack backtrace */ | ||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | /* kprobe post_handler: called after the probed instruction is executed */ | ||
41 | static void handler_post(struct kprobe *p, struct pt_regs *regs, | ||
42 | unsigned long flags) | ||
43 | { | ||
44 | #ifdef CONFIG_X86 | ||
45 | printk(KERN_INFO "post_handler: p->addr = 0x%p, flags = 0x%lx\n", | ||
46 | p->addr, regs->flags); | ||
47 | #endif | ||
48 | #ifdef CONFIG_PPC | ||
49 | printk(KERN_INFO "post_handler: p->addr = 0x%p, msr = 0x%lx\n", | ||
50 | p->addr, regs->msr); | ||
51 | #endif | ||
52 | } | ||
53 | |||
54 | /* | ||
55 | * fault_handler: this is called if an exception is generated for any | ||
56 | * instruction within the pre- or post-handler, or when Kprobes | ||
57 | * single-steps the probed instruction. | ||
58 | */ | ||
59 | static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr) | ||
60 | { | ||
61 | printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn", | ||
62 | p->addr, trapnr); | ||
63 | /* Return 0 because we don't handle the fault. */ | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int __init kprobe_init(void) | ||
68 | { | ||
69 | int ret; | ||
70 | kp.pre_handler = handler_pre; | ||
71 | kp.post_handler = handler_post; | ||
72 | kp.fault_handler = handler_fault; | ||
73 | |||
74 | ret = register_kprobe(&kp); | ||
75 | if (ret < 0) { | ||
76 | printk(KERN_INFO "register_kprobe failed, returned %d\n", ret); | ||
77 | return ret; | ||
78 | } | ||
79 | printk(KERN_INFO "Planted kprobe at %p\n", kp.addr); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static void __exit kprobe_exit(void) | ||
84 | { | ||
85 | unregister_kprobe(&kp); | ||
86 | printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr); | ||
87 | } | ||
88 | |||
89 | module_init(kprobe_init) | ||
90 | module_exit(kprobe_exit) | ||
91 | MODULE_LICENSE("GPL"); | ||
diff --git a/samples/kprobes/kretprobe_example.c b/samples/kprobes/kretprobe_example.c new file mode 100644 index 00000000000..4e764b317d6 --- /dev/null +++ b/samples/kprobes/kretprobe_example.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * kretprobe_example.c | ||
3 | * | ||
4 | * Here's a sample kernel module showing the use of return probes to | ||
5 | * report the return value and total time taken for probed function | ||
6 | * to run. | ||
7 | * | ||
8 | * usage: insmod kretprobe_example.ko func=<func_name> | ||
9 | * | ||
10 | * If no func_name is specified, do_fork is instrumented | ||
11 | * | ||
12 | * For more information on theory of operation of kretprobes, see | ||
13 | * Documentation/kprobes.txt | ||
14 | * | ||
15 | * Build and insert the kernel module as done in the kprobe example. | ||
16 | * You will see the trace data in /var/log/messages and on the console | ||
17 | * whenever the probed function returns. (Some messages may be suppressed | ||
18 | * if syslogd is configured to eliminate duplicate messages.) | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/kprobes.h> | ||
24 | #include <linux/ktime.h> | ||
25 | #include <linux/limits.h> | ||
26 | |||
27 | static char func_name[NAME_MAX] = "do_fork"; | ||
28 | module_param_string(func, func_name, NAME_MAX, S_IRUGO); | ||
29 | MODULE_PARM_DESC(func, "Function to kretprobe; this module will report the" | ||
30 | " function's execution time"); | ||
31 | |||
32 | /* per-instance private data */ | ||
33 | struct my_data { | ||
34 | ktime_t entry_stamp; | ||
35 | }; | ||
36 | |||
37 | /* Here we use the entry_hanlder to timestamp function entry */ | ||
38 | static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | ||
39 | { | ||
40 | struct my_data *data; | ||
41 | |||
42 | if (!current->mm) | ||
43 | return 1; /* Skip kernel threads */ | ||
44 | |||
45 | data = (struct my_data *)ri->data; | ||
46 | data->entry_stamp = ktime_get(); | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * Return-probe handler: Log the return value and duration. Duration may turn | ||
52 | * out to be zero consistently, depending upon the granularity of time | ||
53 | * accounting on the platform. | ||
54 | */ | ||
55 | static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | ||
56 | { | ||
57 | int retval = regs_return_value(regs); | ||
58 | struct my_data *data = (struct my_data *)ri->data; | ||
59 | s64 delta; | ||
60 | ktime_t now; | ||
61 | |||
62 | now = ktime_get(); | ||
63 | delta = ktime_to_ns(ktime_sub(now, data->entry_stamp)); | ||
64 | printk(KERN_INFO "%s returned %d and took %lld ns to execute\n", | ||
65 | func_name, retval, (long long)delta); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static struct kretprobe my_kretprobe = { | ||
70 | .handler = ret_handler, | ||
71 | .entry_handler = entry_handler, | ||
72 | .data_size = sizeof(struct my_data), | ||
73 | /* Probe up to 20 instances concurrently. */ | ||
74 | .maxactive = 20, | ||
75 | }; | ||
76 | |||
77 | static int __init kretprobe_init(void) | ||
78 | { | ||
79 | int ret; | ||
80 | |||
81 | my_kretprobe.kp.symbol_name = func_name; | ||
82 | ret = register_kretprobe(&my_kretprobe); | ||
83 | if (ret < 0) { | ||
84 | printk(KERN_INFO "register_kretprobe failed, returned %d\n", | ||
85 | ret); | ||
86 | return -1; | ||
87 | } | ||
88 | printk(KERN_INFO "Planted return probe at %s: %p\n", | ||
89 | my_kretprobe.kp.symbol_name, my_kretprobe.kp.addr); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static void __exit kretprobe_exit(void) | ||
94 | { | ||
95 | unregister_kretprobe(&my_kretprobe); | ||
96 | printk(KERN_INFO "kretprobe at %p unregistered\n", | ||
97 | my_kretprobe.kp.addr); | ||
98 | |||
99 | /* nmissed > 0 suggests that maxactive was set too low. */ | ||
100 | printk(KERN_INFO "Missed probing %d instances of %s\n", | ||
101 | my_kretprobe.nmissed, my_kretprobe.kp.symbol_name); | ||
102 | } | ||
103 | |||
104 | module_init(kretprobe_init) | ||
105 | module_exit(kretprobe_exit) | ||
106 | MODULE_LICENSE("GPL"); | ||