Kprobes /proc entry
PATCH 1/1 Kprobes /proc entry
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
This simple patch adds a new file in /proc, listing every kprobe which is currently registered in the kernel. This patch is checked against kernel 2.6.10
- --- ./kernel/kprobes.c 2005-01-03 20:40:52.000000000 +0100
+++ ./kernel/kprobes.c 2005-01-10 15:19:17.000000000 +0100
@@ -32,6 +32,7 @@
#include <linux/spinlock.h>
#include <linux/hash.h>
#include <linux/init.h>
+#include <linux/kallsyms.h>
#include <linux/module.h>
#include <asm/cacheflush.h>
#include <asm/errno.h>
@@ -131,6 +132,70 @@
unregister_kprobe(&jp->kp);
}
+void get_kprobes_info(struct kprobe *k, char *p) +{
+ int len = 0;
+ char *module, namebuf[KSYM_NAME_LEN+1];
+ const char *hook, *func;
+ unsigned long off, size, handler, addr = (unsigned long)k->addr;
+
+ if(k->pre_handler) {
+ handler = (unsigned long)k->pre_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "PRE 0x%lx(%s+%#lx)\t",
+ addr, func, off);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "0x%lx(%s)\t%s\n", handler, hook,
+ strlen(module) ? module : "[built-in]");
+ }
+ if(k->post_handler) {
+ handler = (unsigned long)k->pre_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "POST\t0x%lx(%s)\t0x%lx(%s)\t%s\n",
+ handler, hook, addr, func,
+ strlen(module) ? module : "[built-in]");
+ }
+ if(k->fault_handler) {
+ handler = (unsigned long)k->pre_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "FAULT\t0x%lx(%s)\t0x%lx(%s)\t%s\n",
+ handler, hook, addr, func,
+ strlen(module) ? module : "[built-in]");
+ }
+ if(k->break_handler) {
+ handler = (unsigned long)k->pre_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "BREAK\t0x%lx(%s)\t0x%lx(%s)\t%s\n",
+ handler, hook, addr, func,
+ strlen(module) ? module : "[built-in]");
+ }
+}
+
+int get_kprobes_list(char *page)
+{
+
+ int i, len = 0;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct kprobe *k;
+
+ spin_lock(&kprobe_lock);
+ for(i = 0; i < KPROBE_TABLE_SIZE; i++) {
+ head = &kprobe_table[i];
+ hlist_for_each(node, head) {
+ if((k = hlist_entry(node, struct kprobe, hlist))) {
+ get_kprobes_info(k, page + len);
+ len = strlen(page);
+ }
+ }
+ }
+ spin_unlock(&kprobe_lock);
+ return len;
+}
+
static int __init init_kprobes(void)
{
int i, err = 0;
- --- ./fs/proc/proc_misc.c 2005-01-03 20:40:44.000000000 +0100
+++ ./fs/proc/proc_misc.c 2005-01-09 23:50:32.000000000 +0100
@@ -66,6 +66,7 @@
extern int get_exec_domain_list(char *);
extern int get_dma_list(char *);
extern int get_locks_status (char *, char **, off_t, int);
+extern int get_kprobes_list(char *);
static int proc_calc_metrics(char *page, char **start, off_t off,
int count, int *eof, int len)
@@ -547,6 +548,15 @@
return proc_calc_metrics(page, start, off, count, eof, len);
}
+#ifdef CONFIG_KPROBES
+static int kprobes_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_kprobes_list(page);
+ return proc_calc_metrics(page, start, off, count, eof, len);
+}
+#endif
+
#ifdef CONFIG_MAGIC_SYSRQ
/*
* writing 'C' to /proc/sysrq-trigger is like sysrq-C
@@ -601,6 +611,9 @@
{"cmdline", cmdline_read_proc},
{"locks", locks_read_proc},
{"execdomains", execdomains_read_proc},
+#ifdef CONFIG_KPROBES
+ {"kprobes", kprobes_read_proc},
+#endif
{NULL,}
};
for (p = simple_ones; p->name; p++)
Regards,
Luca
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iQEVAwUBQeKsghZrwl7j21nOAQLBsAf9GV9qIV00kCLuGRFckh5HEmRypl2WylZm kCKcpttG1qaDmeD1Rxee6nDMT3zuOlooHjUJhMFXAA1u63oEp0j9BzjuaO+IF/PQ WloKCDquY/nmHMj/C37b9xmdXAGrEpozXcRo1JLd/6SRDNybeCxZDaO5IjK0y5bH NvWvdF86RokC2QujFyrX228M2wNbIKt9yFCpaWtOT723tezDdp2DLB/h3uTiY84i pCLuG0xV8ccakSmJRAkC7qGy8pqJTAt7mY8JVdTxJN5XiDUorHEU/FaUNWLHD4xY NheUG+AWtTy1ulrKEK3T7uK0UEmgpzSokafasFLqvtbtQX1+tdRe1Q== =Tnde
-----END PGP SIGNATURE-----
Quoted 3 lines · Luca Falavigna
This simple patch adds a new file in /proc, listing every kprobe which is currently registered in the kernel. This patch is checked against kernel 2.6.10
No, please do not add extra /proc files to the kernel. This belongs in /sys, as it has _nothing_ to do with processes.
thanks,
greg k-h
Quoted 7 lines · Greg KH
Quoted 3 lines · Luca Falavigna
This simple patch adds a new file in /proc, listing every kprobe which is currently registered in the kernel. This patch is checked against kernel 2.6.10
No, please do not add extra /proc files to the kernel. This belongs in /sys, as it has _nothing_ to do with processes.
Wouldn't this sort of thing be a good candidate for debugfs? If you're messing with kprobes, then aren't you by definition doing kernel debugging? :)
Nathan
Quoted 6 lines · Nathan Lynch
Quoted 5 lines · Greg KH
Quoted 3 lines · Luca Falavigna
This simple patch adds a new file in /proc, listing every kprobe which is currently registered in the kernel. This patch is checked against kernel 2.6.10
Quoted 6 lines
Quoted 2 lines
No, please do not add extra /proc files to the kernel. This belongs in /sys, as it has _nothing_ to do with processes.
Wouldn't this sort of thing be a good candidate for debugfs? If you're messing with kprobes, then aren't you by definition doing kernel debugging? :)
That's an even better idea, I like it.
greg k-h
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Greg KH ha scritto:
Quoted 13 lines · Nathan Lynch
Quoted 12 lines · Greg KH
Quoted 9 lines · Luca Falavigna
Quoted 4 lines
This simple patch adds a new file in /proc, listing every kprobe which is currently registered in the kernel. This patch is checked against kernel 2.6.10
No, please do not add extra /proc files to the kernel. This belongs in /sys, as it has _nothing_ to do with processes.
Quoted 9 lines
Quoted 3 lines
Wouldn't this sort of thing be a good candidate for debugfs? If you're messing with kprobes, then aren't you by definition doing kernel debugging? :)
That's an even better idea, I like it.
greg k-h
Good, I'll work on it ASAP.
Thank you for your suggestions!
Luca
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iQEVAwUBQeRqzRZrwl7j21nOAQJrFQf/RnBUDTsju6LLcYRdM6RYiyrnydTBJWtw Q3MuNE9S/kiwmFpCJjshV9tazJ+dA29pxuqt+Wg2aGkqSSVgq8KuuF1uSLIlaatM n0ZSZ/tnOEJoQtlI32azik+PYVQkHHcr2HMN5ruThRO3uCJfHuYZEGEGaUkZQRa+ ORGrVgXSoLVCQmenIOaXHDW1UNOdKb1IgyU4HBpjL8zVUWOLTB7jbtxghC5rDgHP BV9AYP0GaeIb7Xy5l/bcfngU+teKE75ht+ew5xzX3Ee0Sz9G5a5YVvWJTecHSyeq id4WK0etFHp8qufX/gcGr0uTY8gpxF8GCzwcU8KCr32Y6vvLlVKzxQ== =BXBj
-----END PGP SIGNATURE-----
Hi Luca,
Applied kernel probes can also be listed using SysRq key. Below is the small patch that provides this feature. Please let me know your comments.
Thanks
Prasanna
Quoted 22 lines
Greg KH ha scritto:
Quoted 20 lines · Nathan Lynch
Quoted 9 lines · Greg KH
Quoted 7 lines · Luca Falavigna
Quoted 4 lines
This simple patch adds a new file in /proc, listing every kprobe which is currently registered in the kernel. This patch is checked against kernel 2.6.10
Quoted 6 lines
Quoted 2 lines
No, please do not add extra /proc files to the kernel. This belongs in /sys, as it has _nothing_ to do with processes.
Wouldn't this sort of thing be a good candidate for debugfs? If you're messing with kprobes, then aren't you by definition doing kernel debugging? :)
That's an even better idea, I like it.
Quoted 7 lines
Quoted 2 lines
greg k-h
Good, I'll work on it ASAP.
Thank you for your suggestions!Luca
---
Users like to list the kprobes inserted into the kernel. This patch provides Sysrq-key to list all the kernel probes. Usage Alt+SysRq+W to show the applied kprobes.
or $echo w > /proc/sysrq-trigger
---
---
linux-2.6.10-prasanna/kernel/kprobes.c | 27 +++++++++++++++++++++++++++ 1 files changed, 27 insertions(+)
kernel/kprobes.c renamed from kernel/kprobes.c~kprobes-sysrq-addn-feature +27 -0
@@ -29,6 +29,8 @@* exceptions notifier to be first on the priority list. */ #include <linux/kprobes.h> +#include <linux/sysrq.h> +#include <linux/kallsyms.h> #include <linux/spinlock.h> #include <linux/hash.h> #include <linux/init.h>
@@ -131,10 +133,35 @@ void unregister_jprobe(struct jprobe *jpunregister_kprobe (&jp->kp); } +static void show_kprobes (int key,struct pt_regs *pt_regs,struct tty_struct *tty) +{ +int i; +struct hlist_node *node; + +/* unsafe: kprobe_lock ought to be taken here */ +for (i =0 ; i <KPROBE_TABLE_SIZE ; i++) { +if (!hlist_empty (&kprobe_table[i])) { +hlist_for_each (node, &kprobe_table[i]) { + struct kprobe *p = hlist_entry(node, struct kprobe, hlist); +printk ("[<%p>] " , p->addr); +print_symbol ("%s\t" , (unsigned long )p->addr); +print_symbol ("%s\n" , (unsigned long )p->pre_handler); + } + } + } +} + +static struct sysrq_key_op sysrq_show_kprobes = { + .handler = show_kprobes, + .help_msg ="shoWkprobes" , + .action_msg ="Show kprobes\n" +}; +static int __init init_kprobes (void ) {int i, err =0 ; +register_sysrq_key ('w' , &sysrq_show_kprobes);/* FIXME allocate the probe table, currently defined statically */ /* initialize all list heads */ for (i =0 ; i <KPROBE_TABLE_SIZE ; i++)
_
Signature · 5 lines
Prasanna S Panchamukhi Linux Technology Center India Software Labs, IBM Bangalore Ph: 91-80-25044636 <[email protected]>
Hi Luca,
Below is the latest patch that provides sysrq key feature to list the applied kernel probes.
Please let me know your comments.
Thanks
Prasanna
---
Users like to list the kprobes inserted into the kernel. This patch provides Sysrq-key to list all the kernel probes. Usage Alt+SysRq+W to show the applied kprobes.
or $echo w > /proc/sysrq-trigger
---
---
linux-2.6.10-prasanna/kernel/kprobes.c | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+)
kernel/kprobes.c renamed from kernel/kprobes.c~kprobes-sysrq-addn-feature +25 -0
@@ -29,6 +29,8 @@* exceptions notifier to be first on the priority list. */ #include <linux/kprobes.h> +#include <linux/sysrq.h> +#include <linux/kallsyms.h> #include <linux/spinlock.h> #include <linux/hash.h> #include <linux/init.h>
@@ -131,10 +133,33 @@ void unregister_jprobe(struct jprobe *jpunregister_kprobe (&jp->kp); } +static void show_kprobes (int key,struct pt_regs *pt_regs,struct tty_struct *tty) +{ +int i; +struct hlist_node *node; + +/* unsafe: kprobe_lock ought to be taken here */ +for (i =0 ; i <KPROBE_TABLE_SIZE ; i++) { +struct kprobe *p; +hlist_for_each_entry (p, node, &kprobe_table[i], hlist) { +printk ("[<%p>] " , p->addr); +print_symbol ("%s\t" , (unsigned long )p->addr); +print_symbol ("%s\n" , (unsigned long )p->pre_handler); + } + } +} + +static struct sysrq_key_op sysrq_show_kprobes = { + .handler = show_kprobes, + .help_msg ="shoWkprobes" , + .action_msg ="Show kprobes\n" +}; +static int __init init_kprobes (void ) {int i, err =0 ; +register_sysrq_key ('w' , &sysrq_show_kprobes);/* FIXME allocate the probe table, currently defined statically */ /* initialize all list heads */ for (i =0 ; i <KPROBE_TABLE_SIZE ; i++)
_
Signature · 5 lines
Prasanna S Panchamukhi Linux Technology Center India Software Labs, IBM Bangalore Ph: 91-80-25044636 <[email protected]>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Voilà! Here is kprobes debug patch via debugfs.
- --- ./kernel/kprobes.c 2005-01-13 20:41:11.000000000 +0100
+++ ./kernel/kprobes.c 2005-01-13 20:39:27.000000000 +0100
@@ -33,6 +33,9 @@
#include <linux/hash.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/kallsyms.h>
#include <asm/cacheflush.h>
#include <asm/errno.h>
#include <asm/kdebug.h>
@@ -131,6 +134,96 @@
unregister_kprobe(&jp->kp);
}
+#ifdef CONFIG_DEBUG_FS
+int kprobes_open(struct inode *inode, struct file *file) +{
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+int kprobes_release(struct inode *inode, struct file *file) +{
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+void kprobes_list_info(struct kprobe *k, char *p) +{
+ ssize_t len = 0;
+ char *module, namebuf[KSYM_NAME_LEN+1];
+ const char *hook, *func;
+ unsigned long off, size, handler, addr = (unsigned long)k->addr;
+
+ if(k->pre_handler) {
+ handler = (unsigned long)k->pre_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "PRE\t0x%lx(%s+%#lx)\t",
+ addr, func, off);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "0x%lx(%s)\t%s\n", handler, hook,
+ strlen(module) ? module : "[built-in]");
+ }
+ if(k->post_handler) {
+ handler = (unsigned long)k->post_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "POST\t0x%lx(%s+%#lx)\t",
+ addr, func, off);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "0x%lx(%s)\t%s\n", handler, hook,
+ strlen(module) ? module : "[built-in]");
+ }
+ if(k->fault_handler) {
+ handler = (unsigned long)k->fault_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "FAULT\t0x%lx(%s+%#lx)\t",
+ addr, func, off);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "0x%lx(%s)\t%s\n", handler, hook,
+ strlen(module) ? module : "[built-in]");
+ }
+ if(k->break_handler) {
+ handler = (unsigned long)k->break_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "BREAK\t0x%lx(%s+%#lx)\t",
+ addr, func, off);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ len += sprintf(p + len, "0x%lx(%s)\t%s\n", handler, hook,
+ strlen(module) ? module : "[built-in]");
+ }
+}
+
+ssize_t kprobes_read(struct file *file, char __user *buf,
+ size_t size, loff_t *off)
+{
+ int i;
+ char *data = "";
+ ssize_t len = 0;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct kprobe *k;
+
+ spin_lock(&kprobe_lock);
+ for(i = 0; i < KPROBE_TABLE_SIZE; i++) {
+ head = &kprobe_table[i];
+ hlist_for_each(node, head) {
+ if((k = hlist_entry(node, struct kprobe, hlist))) {
+ kprobes_list_info(k, data + len);
+ len = strlen(data);
+ }
+ }
+ }
+ spin_unlock(&kprobe_lock);
+ return simple_read_from_buffer(buf, size, off, data, len);
+}
+
+struct dentry *kprobes_dir, *kprobes_list; +struct file_operations kprobes_fops = {
+ .open = kprobes_open,
+ .read = kprobes_read,
+ .release = kprobes_release
+ };
+#endif
+
static int __init init_kprobes(void)
{
int i, err = 0;
@@ -140,6 +233,16 @@
for (i = 0; i < KPROBE_TABLE_SIZE; i++)
INIT_HLIST_HEAD(&kprobe_table[i]);
+#ifdef CONFIG_DEBUG_FS
+ if(!(kprobes_dir = debugfs_create_dir("kprobes", NULL)))
+ return -ENODEV;
+ if(!(kprobes_list = debugfs_create_file("list", S_IRUGO, kprobes_dir,
+ NULL, &kprobes_fops))) {
+ debugfs_remove(kprobes_dir);
+ return -ENODEV;
+ }
+#endif
+
err = register_die_notifier(&kprobe_exceptions_nb); return err;
Regards,
Luca
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iQEVAwUBQecCMxZrwl7j21nOAQKEawf/csjjWfFF/UlsN5qZQ3QyYJ1lTSSvuKnh 5ttGdB0hI3Qra+CIR6A/2qhUVomNTV4fcf80R6pMqOmUY61FmYFx2Mv6cRs4fqK3 BoLlOYYAKv3x5dgePdmI3n5ENss3UUYfTG5zd5ng3Qo2IqjwI/L2CR/CM1peXRV1 EXjhTmwU78c+0PLYHPwglDxawfkDO62AyMGqcytg0wFnDDfhjbIHrt48ynl6EIwL oPvxQteQYSp15hRxAQbMRDz/1mzlhNMXZX6dKE15XrE31mk5P/iEaNadInv5r4DU 1ZFEpV0nKuJkmxSA4nVJHtLO7R+lqzkmFBmTBn9HT6Mh0U76aryixA== =zQ7Z
-----END PGP SIGNATURE-----
Quoted 2 lines · Luca Falavigna
+#ifdef
CONFIG_DEBUG_FS
This ifdef should not be needed.
Quoted 1 line
+int
kprobes_open(struct inode *inode, struct file *file)
Shouldn't these calls be static?
Review
Quoted 2 lines
(quoted diff) +2
-0+{ + try_module_get(THIS_MODULE);
Check the return value of this call?
Review line 236
Quoted 8 lines
static int
__initinit_kprobes(void)
{(quoted diff) +1
-0int i, err = 0;@@ -140,6 +233,16 @@ for (i = 0; i < KPROBE_TABLE_SIZE; i++) INIT_HLIST_HEAD(&kprobe_table[i]); +#ifdef CONFIG_DEBUG_FS
ifdef not needed.
Review line 243
Quoted 7 lines
(quoted diff) +7
-0+ if(!(kprobes_dir = debugfs_create_dir("kprobes", NULL))) + return -ENODEV; + if(!(kprobes_list = debugfs_create_file("list", S_IRUGO, kprobes_dir, + NULL, &kprobes_fops))) { + debugfs_remove(kprobes_dir); + return -ENODEV; + }
You never delete this file or directory on module unload, do you?
thanks,
greg k-h
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Here is a modified version of kprobes patch fixing some issues reported by Greg.
Greg KH ha scritto:
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+{ + try_module_get(THIS_MODULE);Check the return value of this call?
I removed try_module_get() and module_put() because of Stephen Hemminger's mail:
"The module ref counting should be done by the VFS layer not the interface." Thank you for this hint :)
Quoted 10 lines
Review
Quoted 7 lines
(quoted diff) +7
-0+ if(!(kprobes_dir = debugfs_create_dir("kprobes", NULL))) + return -ENODEV; + if(!(kprobes_list = debugfs_create_file("list", S_IRUGO, kprobes_dir, + NULL, &kprobes_fops))) { + debugfs_remove(kprobes_dir); + return -ENODEV; + }You never delete this file or directory on module unload, do you?
kprobes are a built-in feature, I think there's no way to handle this. Please, tell me if I am wrong.
- --- ./kernel/kprobes.c 2005-01-17 17:56:11.000000000 +0100
+++ ./kernel/kprobes.c 2005-01-17 17:46:04.000000000 +0100
@@ -33,6 +33,9 @@
#include <linux/hash.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/kallsyms.h>
#include <asm/cacheflush.h>
#include <asm/errno.h>
#include <asm/kdebug.h>
@@ -131,6 +134,88 @@
unregister_kprobe(&jp->kp);
}
+static int kprobes_open(struct inode *inode, struct file *file) +{
+ return 0;
+}
+
+static int kprobes_release(struct inode *inode, struct file *file) +{
+ return 0;
+}
+
+void kprobes_list_info(struct kprobe *k, char *buf)
+{
+ char *module, namebuf[KSYM_NAME_LEN+1];
+ const char *hook, *func;
+ unsigned long off, size, handler, addr = (unsigned long)k->addr;
+
+ if(k->pre_handler) {
+ handler = (unsigned long)k->pre_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ buf += sprintf(buf, "PRE\t0x%lx(%s+%#lx)\t", addr, func, off);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ buf += sprintf(buf, "0x%lx(%s)\t%s\n", handler, hook,
+ strlen(module) ? module : "[built-in]");
+ }
+ if(k->post_handler) {
+ handler = (unsigned long)k->post_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ buf += sprintf(buf, "POST\t0x%lx(%s+%#lx)\t", addr, func, off);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ buf += sprintf(buf, "0x%lx(%s)\t%s\n", handler, hook,
+ strlen(module) ? module : "[built-in]");
+ }
+ if(k->fault_handler) {
+ handler = (unsigned long)k->fault_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ buf += sprintf(buf, "FAULT\t0x%lx(%s+%#lx)\t",
+ addr, func, off);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ buf += sprintf(buf, "0x%lx(%s)\t%s\n", handler, hook,
+ strlen(module) ? module : "[built-in]");
+ }
+ if(k->break_handler) {
+ handler = (unsigned long)k->break_handler;
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ buf += sprintf(buf, "BREAK\t0x%lx(%s+%#lx)\t",
+ addr, func, off);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ buf += sprintf(buf, "0x%lx(%s)\t%s\n", handler, hook,
+ strlen(module) ? module : "[built-in]");
+ }
+}
+
+static ssize_t kprobes_read(struct file *file, char __user *buf,
+ size_t size, loff_t *off)
+{
+ int i;
+ char *data = "";
+ ssize_t len = 0;
+ struct hlist_node *node;
+ struct kprobe *k;
+
+ spin_lock(&kprobe_lock);
+ for(i = 0; i < KPROBE_TABLE_SIZE; i++) {
+ hlist_for_each_entry(k, node, &kprobe_table[i], hlist) {
+ if(k) {
+ kprobes_list_info(k, data + len);
+ len += strlen(data);
+ }
+ }
+ }
+ spin_unlock(&kprobe_lock);
+ return simple_read_from_buffer(buf, size, off, data, len);
+}
+
+struct dentry *kprobes_dir, *kprobes_list;
+struct file_operations kprobes_fops = {
+ .open = kprobes_open,
+ .read = kprobes_read,
+ .release = kprobes_release,
+ .owner = THIS_MODULE
+};
+
static int __init init_kprobes(void)
{
int i, err = 0;
@@ -140,6 +225,20 @@
for (i = 0; i < KPROBE_TABLE_SIZE; i++)
INIT_HLIST_HEAD(&kprobe_table[i]);
+ kprobes_dir = debugfs_create_dir("kprobes", NULL);
+ if(!kprobes_dir) {
+ printk("kprobes: could not create debugfs entry\n");
+ goto finish;
+ }
+ kprobes_list = debugfs_create_file("list", S_IRUGO, kprobes_dir,
+ NULL, &kprobes_fops);
+ if(!kprobes_list) {
+ printk("kprobes: could not create debugfs entry\n");
+ debugfs_remove(kprobes_dir);
+ goto finish;
+ }
+
+finish:
err = register_die_notifier(&kprobe_exceptions_nb); return err;
}
Regards,
Luca
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iQEVAwUBQevumBZrwl7j21nOAQL46Af/apeTfTYuXvDdhWFsqWI7QBqpmYkj9+iu S4A2EKsBUUlnlcZrpL08lqwMup2H8jt3zjmmCcPn2Oplr054aHIDIQveu5XMA+jJ 9w5EdDf3SZcPF+HEPmN9EV5n0BakVwGERM/8615jH804Y5IJtB8b79XMmU8wLI8x M4JGa+kwboD260IbWRuxfRUVqJMMVL5Mibin0RFN4WCbJYfxPhDiCsH2HGNgrw1Y m0uyuaUt4pynAVPpHJPAKPylwY/A9MC7/Zdfa2IIO118bNxKaFTMg0z+AN66jUwz kRUzxoUfDv3kIhzkHwvyPX9hjsoSPof/xQZwxclz8p6Yz00KICdZRw== =Ka0n
-----END PGP SIGNATURE-----
Quoted 10 lines · Luca Falavigna
(quoted diff) +10
-0+static ssize_t kprobes_read(struct file *file, char __user *buf, + size_t size, loff_t *off) +{ + int i; + char *data = ""; + ssize_t len = 0; + struct hlist_node *node; + struct kprobe *k; + + spin_lock(&kprobe_lock);
Review
Quoted 10 lines
(quoted diff) +10
-0+ for(i = 0; i < KPROBE_TABLE_SIZE; i++) { + hlist_for_each_entry(k, node, &kprobe_table[i], hlist) { + if(k) { + kprobes_list_info(k, data + len); + len += strlen(data); + } + } + } + spin_unlock(&kprobe_lock); + return simple_read_from_buffer(buf, size, off, data, len);
Am I missing where you allocate the space for the data to be put into?
Also, why not use the seqfile interface for this, to prevent overflowing the read buffer?
thanks,
greg k-h
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Greg KH ha scritto:
Quoted 2 lines
Also, why not use the seqfile interface for this, to prevent overflowing the read buffer?
Great idea!
Quoted 1 line
Am I missing where you allocate the space for the data to be put into?
seq_read does the job now. It manages to allocate PAGE_SIZE bytes. Assuming function, hook and module names occupy KSYM_NAME_LEN bytes each, maximum length will be 424 bytes for each kprobe. I don't think it would be useful to allocate more memory than PAGE_SIZE. Please, let me know your opinion.
- --- ./kernel/kprobes.c 2005-01-19 11:03:03.000000000 +0100
+++ ./kernel/kprobes.c 2005-01-20 15:02:47.000000000 +0100
@@ -33,6 +33,10 @@
#include <linux/hash.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/kallsyms.h>
+#include <linux/seq_file.h>
#include <asm/cacheflush.h>
#include <asm/errno.h>
#include <asm/kdebug.h>
@@ -45,6 +49,13 @@
unsigned int kprobe_cpu = NR_CPUS;
static DEFINE_SPINLOCK(kprobe_lock);
+static char *ktype[] = {
+ "PRE",
+ "POST",
+ "FAULT",
+ "BREAK",
+};
+
/* Locks kprobe: irqs must be disabled */
void lock_kprobes(void)
{
@@ -131,15 +142,92 @@
unregister_kprobe(&jp->kp);
}
+static void kprobes_print(struct seq_file *seq, unsigned long addr,
+ unsigned long handler, int type)
+{
+ char *module, namebuf[KSYM_NAME_LEN+1];
+ const char *hook, *func;
+ unsigned long off, size;
+
+ func = kallsyms_lookup(addr, &size, &off, &module, namebuf);
+ seq_printf(seq, "%s\t0x%lx(%s+%#lx)\t", ktype[type], addr, func, off);
+ hook = kallsyms_lookup(handler, &size, &off, &module, namebuf);
+ seq_printf(seq, "0x%lx(%s)\t%s\n", handler, hook,
+ strlen(module) ? module : "[built-in]");
+}
+
+static int kprobes_show(struct seq_file *seq, void *unused) +{
+ int i;
+ struct kprobe *k;
+ struct hlist_node *node;
+ unsigned long addr, handler;
+
+ spin_lock(&kprobe_lock);
+ for(i = 0; i < KPROBE_TABLE_SIZE; i++) {
+ hlist_for_each_entry(k, node, &kprobe_table[i], hlist) {
+ if(!k)
+ continue;
+ addr = (unsigned long)k->addr;
+ if(k->pre_handler) {
+ handler = (unsigned long)k->pre_handler;
+ kprobes_print(seq, addr, handler, PRE);
+ }
+ if(k->post_handler) {
+ handler = (unsigned long)k->post_handler;
+ kprobes_print(seq, addr, handler, POST);
+ }
+ if(k->fault_handler) {
+ handler = (unsigned long)k->fault_handler;
+ kprobes_print(seq, addr, handler, FAULT);
+ }
+ if(k->break_handler) {
+ handler = (unsigned long)k->break_handler;
+ kprobes_print(seq, addr, handler, BREAK);
+ }
+ }
+ }
+ spin_unlock(&kprobe_lock);
+ return 0;
+}
+
+static int kprobes_open(struct inode *inode, struct file *file) +{
+ return single_open(file, kprobes_show, NULL);
+}
+
+static struct file_operations kprobes_fops = {
+ .open = kprobes_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE
+};
+
static int __init init_kprobes(void)
{
int i, err = 0;
+ struct dentry *kprobes_dir, *kprobes_list;
/* FIXME allocate the probe table, currently defined statically */ /* initialize all list heads */
for (i = 0; i < KPROBE_TABLE_SIZE; i++)
INIT_HLIST_HEAD(&kprobe_table[i]);
+ kprobes_dir = debugfs_create_dir("kprobes", NULL);
+ if(!kprobes_dir) {
+ printk("kprobes: could not create debugfs entry\n");
+ goto finish;
+ }
+ kprobes_list = debugfs_create_file("list", S_IRUGO, kprobes_dir,
+ NULL, &kprobes_fops);
+ if(!kprobes_list) {
+ printk("kprobes: could not create debugfs entry\n");
+ debugfs_remove(kprobes_dir);
+ goto finish;
+ }
+
+finish:
err = register_die_notifier(&kprobe_exceptions_nb); return err;
}
- --- ./include/linux/kprobes.h 2005-01-03 20:40:51.000000000 +0100
+++ ./include/linux/kprobes.h 2005-01-20 13:59:27.000000000 +0100
@@ -82,6 +82,13 @@
kprobe_opcode_t *entry; /* probe handling code to jump to */
};
+enum kprobe_type {
+ PRE=0,
+ POST,
+ FAULT,
+ BREAK,
+};
+
#ifdef CONFIG_KPROBES
/* Locks kprobe: irq must be disabled */
void lock_kprobes(void);
Regards,
Luca
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iQEVAwUBQe+8dhZrwl7j21nOAQJDHAf+KOkiM3K7S23ALmOntaobAKykZVzKEB5o e7vBZuUhADoG+5VzeUybHiFDP22dvEZ06iVn4O70VuL1fcOsrUNyJri2Vefkc8at Krxxd3Qb0a8903ksx2IzO3d+S+lV30gJie8yHZLrFTp8eCJtSEO8wuXXx0BQtT86 QG1VAxh2hP3ytsbNRNHczeI1yE+PhzdJ2pmJRwTm9tdTWoYznk0QTi/3AUqwvLXE WCxG5ED8vUzeywBB1jL0u3Zq9z+Q+ul8BzsnPhAN8v7Zeo9R4YfbK2dgfbMpVW+N UHO9AqYYDIJN62h2j+iQmtrNPmILjUmVx4uQtYkjk0MQytdN9lbhCw== =paEq
-----END PGP SIGNATURE-----
The module ref counting should be done by the VFS layer not the interface. See below:
Quoted 13 lines
- ---
./kernel/kprobes.c2005-01-13 20:41:11.000000000 +0100
+++./kernel/kprobes.c2005-01-13 20:39:27.000000000 +0100(quoted diff) +3
-0@@ -33,6 +33,9 @@ #include <linux/hash.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/fs.h> +#include <linux/debugfs.h> +#include <linux/kallsyms.h> #include <asm/cacheflush.h> #include <asm/errno.h> #include <asm/kdebug.h>
Review line 140
Quoted 7 lines
(quoted diff) +4
-0@@ -131,6 +134,96 @@ unregister_kprobe(&jp->kp); } +#ifdef CONFIG_DEBUG_FS +int kprobes_open(struct inode *inode, struct file *file) +{ + try_module_get(THIS_MODULE);
not needed (see below).
Review line 146
Quoted 6 lines
(quoted diff) +6
-0+ return 0; +} + +int kprobes_release(struct inode *inode, struct file *file) +{ + module_put(THIS_MODULE);
ditto
Review line 155
Quoted 9 lines
(quoted diff) +8
-0+ return 0; +} + +struct dentry *kprobes_dir, *kprobes_list; +struct file_operations kprobes_fops = { + .open = kprobes_open, + .read = kprobes_read, + .release = kprobes_release
Add:
.owner = THIS_MODULE,