Skip to contentSkip to conversation

Kprobes /proc entry

PATCH In review Luca Falavigna 5 participants 13 messages Jan 10, 2005 – Jan 20, 2005 kprobes

lore
Share & tools
lore
#0 lore raw

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-----

#1 lore raw
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

#2 lore raw
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

#3 lore raw
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

#4 lore raw

-----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-----

#5 lore raw

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
diff -puN kernel/kprobes.c~kprobes-sysrq-addn-feature kernel/kprobes.c
@@ -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 *jp
 	unregister_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]>
#6 lore raw

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
diff -puN kernel/kprobes.c~kprobes-sysrq-addn-feature kernel/kprobes.c
@@ -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 *jp
 	unregister_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]>
#7 lore raw
In reply to Greg KH

-----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-----

#8 lore raw
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 __init init_kprobes(void)
{

(quoted diff) +1 -0
 	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

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

#9 lore raw

-----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-----

#10 lore raw
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

#11 lore raw

-----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-----

#12 lore raw
In reply to Luca Falavigna

The module ref counting should be done by the VFS layer not the interface. See below:

Quoted 13 lines

- --- ./kernel/kprobes.c 2005-01-13 20:41:11.000000000 +0100
+++ ./kernel/kprobes.c 2005-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,