kprobe是SystemTap对内核函数进行probing的功能在内核中的实现,由于内核中提供了正式的API来使用kprobe,所以对很多内核程序员来说,也许直接使用kprobe比使用SystemTap更方便. 内核中提供了三种类型的kprobe处理函数,分别是jprobe, kprobe, kretprobe, 下面的代码用这三个probe观察在TCP/IP的arp_process函数执行中对ip_route_input()调用的返回结果.这个代码还展示了在同一个函数probe的Entry handler和Ret handler之间共享参数的方法. 代码如下:
arp_probe.c /*
* arp_probe.c, by Qianfeng Zhang (frzhang@redhat.com)
*/
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_AUTHOR("frzhang@redhat.com");
MODULE_DESCRIPTION("A module to track the call results of ip_route_input() inside arp_process using jprobe and kretprobe");
MODULE_LICENSE("GPL");
static int j_arp_process(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
struct in_device *in_dev;
int no_addr, rpf;
in_dev = in_dev_get(dev);
no_addr = ( in_dev->ifa_list == NULL );
rpf = IN_DEV_RPFILTER(in_dev);
in_dev_put(in_dev);
printk("\narp_process() is called with interface device %s, in_dev(no_addr=%d,rpf=%d) \n", dev->name, no_addr, rpf);
jprobe_return();
return(0);
};
static int j_fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
struct net_device *dev, __be32 *spec_dst, u32 *itag, u32 mark)
{
printk("fib_validate_source() is called with dst=0x%x, oif=%d \n", dst, oif);
jprobe_return();
return(0);
};
static struct jprobe my_jp1 = {
.entry = j_arp_process,
.kp.symbol_name = "arp_process"
};
static struct jprobe my_jp2 = {
.entry = j_fib_validate_source,
.kp.symbol_name = "fib_validate_source"
};
static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
printk("Calling: %s()\n", ri->rp->kp.symbol_name);
return(0);
};
static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
int eax;
eax = regs->ax & 0xffff ;
printk("Returning: %s() with a return value: 0x%lx(64bit) 0x%x(32bit)\n", ri->rp->kp.symbol_name, regs->ax, eax);
return(0);
};
static int fib_lookup_entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
struct fib_result *resp;
resp = (struct fib_result *) regs->dx;
printk("Calling: %s()\n", ri->rp->kp.symbol_name);
*((struct fib_result **)ri->data) = resp;
return(0);
};
static int fib_lookup_return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
struct fib_result *resp;
int eax;
eax = regs->ax & 0xffff ;
resp = *((struct fib_result **) ri->data);
printk("Returning: fib_lookup() with a return value: 0x%lx(64bit) 0x%x(32bit), result->type: %d\n", regs->ax, eax, resp->type);
return(0);
}
static struct kretprobe my_rp1 = {
.handler = return_handler,
.entry_handler = entry_handler,
.kp.symbol_name = "ip_route_input_slow"
};
static struct kretprobe my_rp2 = {
.handler = return_handler,
.entry_handler = entry_handler,
.kp.symbol_name = "fib_validate_source"
};
static struct kretprobe my_rp3 = {
.handler = fib_lookup_return_handler,
.entry_handler = fib_lookup_entry_handler,
.kp.symbol_name = "fib_lookup",
.data_size = sizeof(struct fib_result *)
};
static int __init init_myprobe(void)
{
int ret;
printk("RTN_UNICAST is %d\n", RTN_UNICAST);
if ( (ret = register_jprobe(&my_jp1)) < 0) {
printk("register_jprobe %s failed, returned %d\n", my_jp1.kp.symbol_name, ret);
return(-1);
}
if ( (ret = register_jprobe(&my_jp2)) < 0) {
printk("register_jprobe %s failed, returned %d\n", my_jp2.kp.symbol_name, ret);
return(-1);
}
if ( (ret = register_kretprobe(&my_rp1)) < 0 ) {
printk("register_kretprobe %s failed, returned %d\n", my_rp1.kp.symbol_name, ret);
unregister_jprobe(&my_jp1);
unregister_jprobe(&my_jp2);
return(-1);
}
if ( (ret = register_kretprobe(&my_rp2)) < 0 ) {
printk("register_kretprobe %s failed, returned %d\n", my_rp2.kp.symbol_name, ret);
unregister_jprobe(&my_jp1);
unregister_jprobe(&my_jp2);
unregister_kretprobe(&my_rp1);
return(-1);
}
if ( (ret = register_kretprobe(&my_rp3)) < 0 ) {
printk("register_kretprobe %s failed, returned %d\n", my_rp3.kp.symbol_name, ret);
unregister_jprobe(&my_jp1);
unregister_jprobe(&my_jp2);
unregister_kretprobe(&my_rp1);
unregister_kretprobe(&my_rp2);
return(-1);
}
return 0;
}