Reputation: 21
I'm now practicing with Linux tracepoint. Basically, I'm trying to make a kernel module where a probe function is defined and connected to a tracepoint("trace_netif_receive_skb" in kernel source file dev.c) in Linux Kernel. When I compiled and ran the kernel module on SLES11, it works well. But when I did the same things on SLES12, it complained that the symbol is undefined. The kernel module source code is:
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/skbuff.h>
5 #include <trace/events/net.h>
6
7 static void probe(void *ignore, struct sk_buff *skb)
8 {
9 printk(KERN_INFO "probe, protocol[0X%04X]\n", ntohs(skb->protocol));
10 }
11
12 static int __init init_tracepoint(void)
13 {
14 if (0 != register_trace_netif_receive_skb(probe, NULL))
15 {
16 printk(KERN_INFO "tracepoint init fails\n");
17 }
18
19 printk(KERN_INFO "tracepoint init succeeds\n");
20 return 0;
21 }
22
23 static void __exit cleanup_tracepoint(void)
24 {
25 unregister_trace_netif_receive_skb(probe, NULL);
26 tracepoint_synchronize_unregister();
27
28 printk(KERN_INFO "tracepoint exit\n");
29 }
30
31 module_init(init_tracepoint);
32 module_exit(cleanup_tracepoint);
33
34 MODULE_LICENSE("GPL");
This is the output on SLES11, no error is reported.
suse11-1:~/works/tracepoint # make
make -C /lib/modules/3.0.76-0.11-default/build M=/root/works/tracepoint modules
make[1]: Entering directory `/usr/src/linux-3.0.76-0.11-obj/x86_64/default'
make -C ../../../linux-3.0.76-0.11 O=/usr/src/linux-3.0.76-0.11-obj/x86_64/default/. modules
CC [M] /root/works/tracepoint/tracepoint.o
Building modules, stage 2.
MODPOST 1 modules
CC /root/works/tracepoint/tracepoint.mod.o
LD [M] /root/works/tracepoint/tracepoint.ko
make[1]: Leaving directory `/usr/src/linux-3.0.76-0.11-obj/x86_64/default'
suse11-1:~/works/tracepoint # insmod tracepoint.ko
This is the output on SLES12, it says: WARNING: "__tracepoint_netif_receive_skb" [/root/works/codes/tracepoint/tracepoint.ko] undefined! And I can find "Unknown symbol __tracepoint_netif_receive_skb (err 0)" in /var/log/messages.
suse12-1:~/works/codes/tracepoint # make
make -C /lib/modules/4.4.21-69-default/build M=/root/works/codes/tracepoint modules
make[1]: Entering directory '/usr/src/linux-4.4.21-69-obj/x86_64/default'
CC [M] /root/works/codes/tracepoint/tracepoint.o
Building modules, stage 2.
MODPOST 1 modules
WARNING: "__tracepoint_netif_receive_skb" [/root/works/codes/tracepoint/tracepoint.ko] undefined!
CC /root/works/codes/tracepoint/tracepoint.mod.o
LD [M] /root/works/codes/tracepoint/tracepoint.ko
make[1]: Leaving directory '/usr/src/linux-4.4.21-69-obj/x86_64/default'
suse12-1:~/works/codes/tracepoint #
suse12-1:~/works/codes/tracepoint # insmod tracepoint.ko
insmod: ERROR: could not insert module tracepoint.ko: Unknown symbol in module
I checked the kernel source code of tracepoint framework of both SLES11 and SLES12, the "__tracepoint_##name" defined "include/linux/tracepoint.h" is not exported unless EXPORT_TRACEPOINT_SYMBOL() or EXPORT_TRACEPOINT_SYMBOL_GPL() is called, but I didn't find any place in linux kernel codes where EXPORT_TRACEPOINT_SYMBOL(netif_receive_skb) or EXPORT_TRACEPOINT_SYMBOL_GPL(netif_receive_skb) is called to export symbol __tracepoint_netif_receive_skb. Then why I didn't meet the problem on SLES11? And how can I get it work on SLES12?
Upvotes: 2
Views: 1194
Reputation: 1
Use for_each_kernel_tracepoint
to find target tracepoint and register probe, works for me, good luck.
struct tp_reg {
const char *name;
struct tracepoint *tp;
void *fn;
};
static void each_tracepoint(struct tracepoint *tp, void *priv)
{
struct tp_reg *regs = (struct tp_reg *)priv;
int i;
for (i = 0; regs[i].name; ++i) {
if (strcmp(tp->name, regs[i].name) == 0) {
if (tracepoint_probe_register(tp, regs[i].fn, NULL) == 0) {
regs[i].tp = tp;
}
}
}
}
static void unregister_tp(struct tp_reg *regs)
{
int i;
for (i = 0; regs[i].name; ++i) {
if (regs[i].tp) {
tracepoint_probe_unregister(regs[i].tp, regs[i].fn, NULL);
regs[i].tp = NULL;
}
}
tracepoint_synchronize_unregister();
}
static int register_tp(struct tp_reg *regs)
{
int i;
for_each_kernel_tracepoint(each_tracepoint, regs);
for (i = 0; regs[i].name; ++i) {
if (regs[i].tp == NULL) {
printk(KERN_ALERT "trace point %s not found.\n", regs[i].name);
unregister_tp(regs);
return 1;
}
}
return 0;
}
Sample code:
static void probe_callback(void *ignore, struct pt_regs *regs, long id)
{
if (id == __NR_execve) {
char file[100];
if (strncpy_from_user(file, (void *)PT_REGS_PARM1(regs), sizeof(file)) < 0)
return;
printk(KERN_INFO "execve %s", file);
}
}
static struct tp_reg myreg[] = {
{ .name = "sys_enter", .fn = (void *)probe_callback },
{ .name = NULL }
};
static int __init init_tracepoint(void)
{
return register_tp(myreg);
}
static void __exit cleanup_tracepoint(void)
{
unregister_tp(myreg);
}
Upvotes: 0