|
@@ -192,7 +192,8 @@ code mapping.
|
|
The Kprobes API includes a "register" function and an "unregister"
|
|
The Kprobes API includes a "register" function and an "unregister"
|
|
function for each type of probe. Here are terse, mini-man-page
|
|
function for each type of probe. Here are terse, mini-man-page
|
|
specifications for these functions and the associated probe handlers
|
|
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
|
|
4.1 register_kprobe
|
|
|
|
|
|
@@ -420,249 +421,15 @@ e. Watchpoint probes (which fire on data references).
|
|
|
|
|
|
8. Kprobes Example
|
|
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
|
|
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
|
|
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:
|
|
For additional information on Kprobes, refer to the following URLs:
|
|
http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe
|
|
http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe
|