architectures:
- i386
-- x86_64 (AMD-64, E64MT)
+- x86_64 (AMD-64, EM64T)
- ppc64
-- ia64 (Support for probes on certain instruction types is still in progress.)
+- ia64 (Does not support probes on instruction slot1.)
- sparc64 (Return probes not yet implemented.)
3. Configuring Kprobes
When configuring the kernel using make menuconfig/xconfig/oldconfig,
-ensure that CONFIG_KPROBES is set to "y". Under "Kernel hacking",
-look for "Kprobes". You may have to enable "Kernel debugging"
-(CONFIG_DEBUG_KERNEL) before you can enable Kprobes.
+ensure that CONFIG_KPROBES is set to "y". Under "Instrumentation
+Support", look for "Kprobes".
-You may also want to ensure that CONFIG_KALLSYMS and perhaps even
-CONFIG_KALLSYMS_ALL are set to "y", since kallsyms_lookup_name()
-is a handy, version-independent way to find a function's address.
+So that you can load and unload Kprobes-based instrumentation modules,
+make sure "Loadable module support" (CONFIG_MODULES) and "Module
+unloading" (CONFIG_MODULE_UNLOAD) are set to "y".
+
+Also make sure that CONFIG_KALLSYMS and perhaps even CONFIG_KALLSYMS_ALL
+are set to "y", since kallsyms_lookup_name() is used by the in-kernel
+kprobe address resolution code.
If you need to insert a probe in the middle of a function, you may find
it useful to "Compile the kernel with debug info" (CONFIG_DEBUG_INFO),
or during single-stepping of the probed instruction, Kprobes calls
kp->fault_handler. Any or all handlers can be NULL.
+NOTE:
+1. With the introduction of the "symbol_name" field to struct kprobe,
+the probepoint address resolution will now be taken care of by the kernel.
+The following will now work:
+
+ kp.symbol_name = "symbol_name";
+
+(64-bit powerpc intricacies such as function descriptors are handled
+transparently)
+
+2. Use the "offset" field of struct kprobe if the offset into the symbol
+to install a probepoint is known. This field is used to calculate the
+probepoint.
+
+3. Specify either the kprobe "symbol_name" OR the "addr". If both are
+specified, kprobe registration will fail with -EINVAL.
+
+4. With CISC architectures (such as i386 and x86_64), the kprobes code
+does not validate if the kprobe.addr is at an instruction boundary.
+Use "offset" with caution.
+
register_kprobe() returns 0 on success, or a negative errno otherwise.
User's pre-handler (kp->pre_handler):
fastcall, or anything else that affects how args are passed, the
handler's declaration must match.
+NOTE: A macro JPROBE_ENTRY is provided to handle architecture-specific
+aliasing of jp->entry. In the interest of portability, it is advised
+to use:
+
+ jp->entry = JPROBE_ENTRY(handler);
+
register_jprobe() returns 0 on success, or a negative errno otherwise.
4.3 register_kretprobe
- ret_addr: the return address
- rp: points to the corresponding kretprobe object
- task: points to the corresponding task struct
+
+The regs_return_value(regs) macro provides a simple abstraction to
+extract the return value from the appropriate register as defined by
+the architecture's ABI.
+
The handler's return value is currently ignored.
4.4 unregister_*probe
5. Kprobes Features and Limitations
-As of Linux v2.6.12, Kprobes allows multiple probes at the same
-address. Currently, however, there cannot be multiple jprobes on
-the same function at the same time.
+Kprobes allows multiple probes at the same address. Currently,
+however, there cannot be multiple jprobes on the same function at
+the same time.
In general, you can install a probe anywhere in the kernel.
In particular, you can probe interrupt handlers. Known exceptions
are discussed in this section.
-For obvious reasons, it's a bad idea to install a probe in
-the code that implements Kprobes (mostly kernel/kprobes.c and
-arch/*/kernel/kprobes.c). A patch in the v2.6.13 timeframe instructs
-Kprobes to reject such requests.
+The register_*probe functions will return -EINVAL if you attempt
+to install a probe in the code that implements Kprobes (mostly
+kernel/kprobes.c and arch/*/kernel/kprobes.c, but also functions such
+as do_page_fault and notifier_call_chain).
If you install a probe in an inline-able function, Kprobes makes
no attempt to chase down all inline instances of the function and
Kprobes makes no attempt to prevent probe handlers from stepping on
each other -- e.g., probing printk() and then calling printk() from a
-probe handler. As of Linux v2.6.12, if a probe handler hits a probe,
-that second probe's handlers won't be run in that instance.
-
-In Linux v2.6.12 and previous versions, Kprobes' data structures are
-protected by a single lock that is held during probe registration and
-unregistration and while handlers are run. Thus, no two handlers
-can run simultaneously. To improve scalability on SMP systems,
-this restriction will probably be removed soon, in which case
-multiple handlers (or multiple instances of the same handler) may
-run concurrently on different CPUs. Code your handlers accordingly.
-
-Kprobes does not use semaphores or allocate memory except during
+probe handler. If a probe handler hits a probe, that second probe's
+handlers won't be run in that instance, and the kprobe.nmissed member
+of the second probe will be incremented.
+
+As of Linux v2.6.15-rc1, multiple handlers (or multiple instances of
+the same handler) may run concurrently on different CPUs.
+
+Kprobes does not use mutexes or allocate memory except during
registration and unregistration.
Probe handlers are run with preemption disabled. Depending on the
(As far as we can tell, __builtin_return_address() is used only
for instrumentation and error reporting.)
-If the number of times a function is called does not match the
-number of times it returns, registering a return probe on that
-function may produce undesirable results. We have the do_exit()
-and do_execve() cases covered. do_fork() is not an issue. We're
-unaware of other specific cases where this could be a problem.
+If the number of times a function is called does not match the number
+of times it returns, registering a return probe on that function may
+produce undesirable results. We have the do_exit() case covered.
+do_execve() and do_fork() are not an issue. We're unaware of other
+specific cases where this could be a problem.
+
+If, upon entry to or exit from a function, the CPU is running on
+a stack other than that of the current task, registering a return
+probe on that function may produce undesirable results. For this
+reason, Kprobes doesn't support return probes (or kprobes or jprobes)
+on the x86_64 version of __switch_to(); the registration functions
+return -EINVAL.
6. Probe Overhead
7. TODO
-a. SystemTap (http://sourceware.org/systemtap): Work in progress
-to provide a simplified programming interface for probe-based
-instrumentation.
-b. Improved SMP scalability: Currently, work is in progress to handle
-multiple kprobes in parallel.
-c. Kernel return probes for sparc64.
-d. Support for other architectures.
-e. User-space probes.
+a. SystemTap (http://sourceware.org/systemtap): Provides a simplified
+programming interface for probe-based instrumentation. Try it out.
+b. Kernel return probes for sparc64.
+c. Support for other architectures.
+d. User-space probes.
+e. Watchpoint probes (which fire on data references).
8. Kprobes Example
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
-#include <linux/kallsyms.h>
#include <linux/sched.h>
/*For each probe you need to allocate a kprobe structure*/
return 0;
}
-int init_module(void)
+static int __init kprobe_init(void)
{
int ret;
kp.pre_handler = handler_pre;
kp.post_handler = handler_post;
kp.fault_handler = handler_fault;
- kp.addr = (kprobe_opcode_t*) kallsyms_lookup_name("do_fork");
- /* register the kprobe now */
- if (!kp.addr) {
- printk("Couldn't find %s to plant kprobe\n", "do_fork");
- return -1;
- }
+ kp.symbol_name = "do_fork";
+
if ((ret = register_kprobe(&kp) < 0)) {
printk("register_kprobe failed, returned %d\n", ret);
return -1;
return 0;
}
-void cleanup_module(void)
+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 -----
#include <linux/fs.h>
#include <linux/uio.h>
#include <linux/kprobes.h>
-#include <linux/kallsyms.h>
/*
* Jumper probe for do_fork.
}
static struct jprobe my_jprobe = {
- .entry = (kprobe_opcode_t *) jdo_fork
+ .entry = JPROBE_ENTRY(jdo_fork)
};
-int init_module(void)
+static int __init jprobe_init(void)
{
int ret;
- 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;
- }
+ my_jprobe.kp.symbol_name = "do_fork";
if ((ret = register_jprobe(&my_jprobe)) <0) {
printk("register_jprobe failed, returned %d\n", ret);
return 0;
}
-void cleanup_module(void)
+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 -----
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
-#include <linux/kallsyms.h>
static const char *probed_func = "sys_open";
/* Return-probe handler: If the probed function fails, log the return value. */
static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
- // Substitute the appropriate register name for your architecture --
- // e.g., regs->rax for x86_64, regs->gpr[3] for ppc64.
- int retval = (int) regs->eax;
+ int retval = regs_return_value(regs);
if (retval < 0) {
printk("%s returns %d\n", probed_func, retval);
}
.maxactive = 20
};
-int init_module(void)
+static int __init kretprobe_init(void)
{
int ret;
- my_kretprobe.kp.addr =
- (kprobe_opcode_t *) kallsyms_lookup_name(probed_func);
- if (!my_kretprobe.kp.addr) {
- printk("Couldn't find %s to plant return probe\n", probed_func);
- return -1;
- }
+ 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;
return 0;
}
-void cleanup_module(void)
+static void __exit kretprobe_exit(void)
{
unregister_kretprobe(&my_kretprobe);
printk("kretprobe unregistered\n");
my_kretprobe.nmissed, probed_func);
}
+module_init(kretprobe_init)
+module_exit(kretprobe_exit)
MODULE_LICENSE("GPL");
----- cut here -----
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.redhat.com/magazine/005mar05/features/kprobes/
+http://www-users.cs.umn.edu/~boutcher/kprobes/
+http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)