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 ([email protected])
*/
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_AUTHOR("[email protected]");
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;
}