2005-01-10 18:01:19

by Luca Falavigna

[permalink] [raw]
Subject: [PATCH] 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++)

Signed-off-by: Luca Falavigna <[email protected]>



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


2005-01-10 18:18:46

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

On Mon, Jan 10, 2005 at 05:25:38PM +0100, Luca Falavigna wrote:
> 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

2005-01-11 21:33:32

by Nathan Lynch

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

On Mon, 2005-01-10 at 12:14, Greg KH wrote:
> On Mon, Jan 10, 2005 at 05:25:38PM +0100, Luca Falavigna wrote:
> > 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


2005-01-11 21:41:02

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

On Tue, Jan 11, 2005 at 03:31:17PM -0600, Nathan Lynch wrote:
> On Mon, 2005-01-10 at 12:14, Greg KH wrote:
> > On Mon, Jan 10, 2005 at 05:25:38PM +0100, Luca Falavigna wrote:
> > > 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? :)

That's an even better idea, I like it.

greg k-h

2005-01-12 00:33:30

by Luca Falavigna

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Greg KH ha scritto:
> On Tue, Jan 11, 2005 at 03:31:17PM -0600, Nathan Lynch wrote:
>
>>On Mon, 2005-01-10 at 12:14, Greg KH wrote:
>>
>>>On Mon, Jan 10, 2005 at 05:25:38PM +0100, Luca Falavigna wrote:
>>>
>>>>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? :)
>
>
> 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-----

2005-01-12 06:32:36

by S. P. Prasanna

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

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
>
> Greg KH ha scritto:
> > On Tue, Jan 11, 2005 at 03:31:17PM -0600, Nathan Lynch wrote:
> >
> >>On Mon, 2005-01-10 at 12:14, Greg KH wrote:
> >>
> >>>On Mon, Jan 10, 2005 at 05:25:38PM +0100, Luca Falavigna wrote:
> >>>
> >>>>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? :)
> >
> >
> > 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


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

Signed-of-by: Prasanna S Panchamukhi <[email protected]>
---



---

linux-2.6.10-prasanna/kernel/kprobes.c | 27 +++++++++++++++++++++++++++
1 files changed, 27 insertions(+)

diff -puN kernel/kprobes.c~kprobes-sysrq-addn-feature kernel/kprobes.c
--- linux-2.6.10/kernel/kprobes.c~kprobes-sysrq-addn-feature 2005-01-12 11:54:08.000000000 +0530
+++ linux-2.6.10-prasanna/kernel/kprobes.c 2005-01-12 11:54:08.000000000 +0530
@@ -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++)

_
--

Prasanna S Panchamukhi
Linux Technology Center
India Software Labs, IBM Bangalore
Ph: 91-80-25044636
<[email protected]>

2005-01-12 09:46:53

by S. P. Prasanna

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

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

Signed-of-by: Prasanna S Panchamukhi <[email protected]>
---



---

linux-2.6.10-prasanna/kernel/kprobes.c | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+)

diff -puN kernel/kprobes.c~kprobes-sysrq-addn-feature kernel/kprobes.c
--- linux-2.6.10/kernel/kprobes.c~kprobes-sysrq-addn-feature 2005-01-12 12:29:49.000000000 +0530
+++ linux-2.6.10-prasanna/kernel/kprobes.c 2005-01-12 14:52:49.000000000 +0530
@@ -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++)

_
--

Prasanna S Panchamukhi
Linux Technology Center
India Software Labs, IBM Bangalore
Ph: 91-80-25044636
<[email protected]>

2005-01-13 23:29:38

by Luca Falavigna

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

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

Signed-off-by: Luca Falavigna <[email protected]>



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

2005-01-13 23:43:06

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

On Fri, Jan 14, 2005 at 12:20:20AM +0100, Luca Falavigna wrote:
>
> +#ifdef CONFIG_DEBUG_FS

This ifdef should not be needed.

> +int kprobes_open(struct inode *inode, struct file *file)

Shouldn't these calls be static?

> +{
> + try_module_get(THIS_MODULE);

Check the return value of this call?

> 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

ifdef not needed.

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

2005-01-14 00:32:23

by Stephen Hemminger

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

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

> - --- ./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);
not needed (see below).
> + return 0;
> +}
> +
> +int kprobes_release(struct inode *inode, struct file *file)
> +{
> + module_put(THIS_MODULE);
ditto

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

2005-01-17 18:10:23

by Luca Falavigna

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Here is a modified version of kprobes patch fixing some issues reported by Greg.

Greg KH ha scritto:
>>+{
>>+ 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 :)

>>+ 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;
}

Signed-off-by: Luca Falavigna <[email protected]>



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

2005-01-18 06:44:27

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

On Mon, Jan 17, 2005 at 05:58:00PM +0100, Luca Falavigna wrote:
> +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);

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

2005-01-20 17:39:03

by Luca Falavigna

[permalink] [raw]
Subject: Re: [PATCH] Kprobes /proc entry

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Greg KH ha scritto:
> Also, why not use the seqfile interface for this, to prevent overflowing
> the read buffer?
Great idea!

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

Signed-off-by: Luca Falavigna <[email protected]>



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