2 * otst: one-time stacktrace module
3 * Copyright (C) 2011 Daniel Borkmann <borkmann@iogearbox.net>
4 * Emmanuel Roullit <emmanuel@netsniff-ng.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * cat /proc/driver/otst ... to show currently traced syms
17 * echo -n "netif_rx" > /proc/driver/otst ... to add a symbol for trace
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/kprobes.h>
23 #include <linux/proc_fs.h>
24 #include <linux/seq_file.h>
25 #include <linux/uaccess.h>
26 #include <linux/rcupdate.h>
27 #include <linux/list.h>
28 #include <linux/slab.h>
29 #include <linux/spinlock.h>
30 #include <linux/kallsyms.h>
32 #define MODULE_NAME "otst"
33 #define MODULE_PROC "driver/"MODULE_NAME
34 #define MODULE_DESC "one-time stacktrace driver"
36 struct otst_kprobes_elem
{
39 struct list_head list
;
42 static LIST_HEAD(otst_kprobes
);
43 static DEFINE_SPINLOCK(otst_kprobes_lock
);
45 static int otst_handler(struct kprobe
*kp
, struct pt_regs
*regs
)
47 printk(KERN_INFO
"%s: triggered stacktrace for symbol %s at 0x%p:\n",
48 MODULE_NAME
, kp
->symbol_name
, kp
->addr
);
53 static void otst_handler_post_work(struct kprobe
*kp
, struct pt_regs
*regs
,
59 static void otst_collect_garbage(void)
62 struct otst_kprobes_elem
*elem
;
67 list_for_each_entry_rcu(elem
, &otst_kprobes
, list
) {
68 if (kprobe_disabled(&elem
->probe
)) {
70 unregister_kprobe(&elem
->probe
);
76 spin_lock(&otst_kprobes_lock
);
77 list_del_rcu(&elem
->list
);
78 spin_unlock(&otst_kprobes_lock
);
81 "%s: symbol %s unregistered!\n",
82 MODULE_NAME
, elem
->symname
);
88 static int otst_proc_show(struct seq_file
*m
, void *v
)
90 struct otst_kprobes_elem
*elem
;
92 list_for_each_entry_rcu(elem
, &otst_kprobes
, list
) {
93 seq_printf(m
, "%s\n", elem
->probe
.symbol_name
);
99 static int otst_proc_open(struct inode
*inode
, struct file
*file
)
101 return single_open(file
, otst_proc_show
, NULL
);
104 static ssize_t
otst_proc_write(struct file
*file
, const char __user
* buffer
,
105 size_t count
, loff_t
* pos
)
109 struct otst_kprobes_elem
*elem
= NULL
;
111 otst_collect_garbage();
113 elem
= kzalloc(sizeof(*elem
), GFP_KERNEL
);
120 strncpy_from_user(elem
->symname
, buffer
,
121 min(count
, sizeof(elem
->symname
) - 1));
128 elem
->symname
[len
] = '\0';
130 elem
->probe
.pre_handler
= otst_handler
;
131 elem
->probe
.post_handler
= otst_handler_post_work
;
132 elem
->probe
.symbol_name
= elem
->symname
;
134 if (!kallsyms_lookup_name(elem
->probe
.symbol_name
)) {
135 printk(KERN_INFO
"%s: %s is no symbol!\n",
136 MODULE_NAME
, elem
->probe
.symbol_name
);
140 ret
= register_kprobe(&elem
->probe
);
142 printk(KERN_INFO
"%s: register_kprobe for %s failed "
143 "with %d\n", MODULE_NAME
, elem
->probe
.symbol_name
, ret
);
146 printk(KERN_INFO
"%s: symbol %s registered!\n",
147 MODULE_NAME
, elem
->probe
.symbol_name
);
150 spin_lock(&otst_kprobes_lock
);
151 list_add_rcu(&elem
->list
, &otst_kprobes
);
152 spin_unlock(&otst_kprobes_lock
);
159 return ret
? ret
: count
;
162 static const struct file_operations otst_fops
= {
163 .owner
= THIS_MODULE
,
164 .open
= otst_proc_open
,
167 .write
= otst_proc_write
,
168 .release
= single_release
,
171 static int __init
otst_init(void)
173 if (!proc_create(MODULE_PROC
, S_IWUSR
| S_IRUSR
, NULL
, &otst_fops
))
176 printk(KERN_INFO
"%s: %s loaded!\n", MODULE_NAME
, MODULE_DESC
);
180 static void __exit
otst_exit(void)
182 otst_collect_garbage();
183 remove_proc_entry(MODULE_PROC
, NULL
);
184 printk(KERN_INFO
"%s: removed!\n", MODULE_NAME
);
187 module_init(otst_init
);
188 module_exit(otst_exit
);
190 MODULE_LICENSE("GPL");
191 MODULE_DESCRIPTION(MODULE_DESC
);
192 MODULE_AUTHOR("Daniel Borkmann <borkmann@iogearbox.net>");
193 MODULE_AUTHOR("Emmanuel Roullit <emmanuel@netsniff-ng.org>");