From: Frederic Weisbecker <fweisbec@gmail.com>
To: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>,
Ingo Molnar <mingo@elte.hu>, Jim Keniston <jkenisto@us.ibm.com>,
LKML <linux-kernel@vger.kernel.org>,
systemtap-ml <systemtap@sources.redhat.com>
Subject: Re: [RFC][PATCH -tip 8/9] kprobes: support respawn probes for module probing
Date: Sat, 21 Mar 2009 01:32:00 -0000 [thread overview]
Message-ID: <20090321000844.GD6044@nowhere> (raw)
In-Reply-To: <49C31206.3060806@redhat.com>
On Thu, Mar 19, 2009 at 11:48:22PM -0400, Masami Hiramatsu wrote:
> Frederic Weisbecker wrote:
> >> diff --git a/kernel/kprobes.c b/kernel/kprobes.c
> >> index 5016bfb..f16a54e 100644
> >> --- a/kernel/kprobes.c
> >> +++ b/kernel/kprobes.c
> >> @@ -1416,6 +1416,256 @@ static int __kprobes debugfs_kprobe_init(void)
> >> late_initcall(debugfs_kprobe_init);
> >> #endif /* CONFIG_DEBUG_FS */
> >>
> >> +/* Kprobes module respawn support */
> >> +enum probe_type {
> >> + PROBE_TYPE_KPROBE,
> >> + PROBE_TYPE_KRETPROBE,
> >> + PROBE_TYPE_JPROBE,
> >> +};
> >> +
> >> +struct module_probe_client {
> >> + struct list_head list;
> >> + const char *module; /* including symbol name */
> >> + int active;
> >> + void *data;
> >> + probe_activate_handler_t handler;
> >> + enum probe_type type;
> >> + union {
> >> + struct kprobe *kp;
> >> + struct kretprobe *rp;
> >> + struct jprobe *jp;
> >> + };
> >> +};
> >> +
> >> +static DEFINE_MUTEX(module_probe_mutex);
> >> +static LIST_HEAD(module_probe_list);
> >> +
> >> +static int activate_module_probe(struct module_probe_client *pc)
> >> +{
> >> + int ret = 0;
> >> + if (pc->active)
> >> + return 0;
> >> + switch (pc->type) {
> >> + case PROBE_TYPE_KPROBE:
> >> + ret = register_kprobe(pc->kp);
> >> + break;
> >> + case PROBE_TYPE_KRETPROBE:
> >> + ret = register_kretprobe(pc->rp);
> >> + break;
> >> + case PROBE_TYPE_JPROBE:
> >> + ret = register_jprobe(pc->jp);
> >> + break;
> >> + default:
> >> + WARN_ON(1);
> >> + break;
> >> + }
> >> + if (!ret)
> >> + pc->active = 1;
> >> + return ret;
> >> +}
> >> +
> >> +static void deactivate_module_probe(struct module_probe_client *pc)
> >> +{
> >> + if (!pc->active)
> >> + return;
> >> + switch (pc->type) {
> >> + case PROBE_TYPE_KPROBE:
> >> + unregister_kprobe(pc->kp);
> >> + break;
> >> + case PROBE_TYPE_KRETPROBE:
> >> + unregister_kretprobe(pc->rp);
> >> + break;
> >> + case PROBE_TYPE_JPROBE:
> >> + unregister_jprobe(pc->jp);
> >> + break;
> >> + default:
> >> + WARN_ON(1);
> >> + break;
> >> + }
> >> + pc->active = 0;
> >> +}
> >> +
> >> +static const char *probed_module_name(struct kprobe *kp)
> >> +{
> >> + if ((kp->symbol_name) && strchr(kp->symbol_name, ':'))
> >> + return kp->symbol_name;
> >> + return NULL;
> >> +}
> >> +
> >> +static int module_is_exist(const char *module)
> >> +{
> >> + char buf[MODULE_NAME_LEN + 8];
> >> + snprintf(buf, MODULE_NAME_LEN + 8, "%s:__stext", module);
> >> + return module_kallsyms_lookup_name(buf) ? 1 : 0;
> >> +}
> >> +
> >> +static int add_module_probe(const char *module, void *p, enum probe_type type,
> >> + probe_activate_handler_t handler, void *data)
> >> +{
> >> + struct module_probe_client *pc;
> >> + int ret = 0;
> >> +
> >> + if (!handler)
> >> + return -EINVAL;
> >> +
> >> + pc = kzalloc(sizeof(struct module_probe_client), GFP_KERNEL);
> >> + pc->kp = p;
> >> + pc->type = type;
> >> + pc->module = module;
> >> + pc->handler = handler;
> >> + pc->data = data;
> >> + INIT_LIST_HEAD(&pc->list);
> >> +
> >> + mutex_lock(&module_probe_mutex);
> >> + if (module_is_exist(module))
> >> + ret = activate_module_probe(pc);
> >> + if (ret)
> >> + kfree(pc);
> >> + else
> >> + list_add_tail(&pc->list, &module_probe_list);
> >> + mutex_unlock(&module_probe_mutex);
> >> + return ret;
> >> +}
> >> +
> >> +static void __del_module_probe(struct module_probe_client *pc)
> >> +{
> >> + list_del(&pc->list);
> >> + deactivate_module_probe(pc);
> >> + kfree(pc);
> >> +}
> >> +
> >> +static int del_module_probe(void *p)
> >> +{
> >> + struct module_probe_client *pc;
> >> + int ret;
> >> +
> >> + mutex_lock(&module_probe_mutex);
> >> + list_for_each_entry(pc, &module_probe_list, list)
> >> + if (pc->kp == p) {
> >> + /* don't need safe loop, we exit soon */
> >> + __del_module_probe(pc);
> >> + goto found;
> >> + }
> >> + ret = -ENOENT;
> >> +found:
> >> + mutex_unlock(&module_probe_mutex);
> >> + return ret;
> >> +}
> >> +
> >> +int __kprobes
> >> +register_module_kprobe(struct kprobe *kp,
> >> + probe_activate_handler_t handler, void *data)
> >> +{
> >> + const char *module;
> >> + module = probed_module_name(kp);
> >> + if (!module)
> >> + return register_kprobe(kp);
> >> + return add_module_probe(module, kp, PROBE_TYPE_KPROBE,
> >> + handler, data);
> >> +}
> >> +EXPORT_SYMBOL_GPL(register_module_kprobe);
> >> +
> >> +int __kprobes
> >> +register_module_kretprobe(struct kretprobe *rp,
> >> + probe_activate_handler_t handler, void *data)
> >> +{
> >> + const char *module;
> >> + module = probed_module_name(&rp->kp);
> >> + if (!module)
> >> + return register_kretprobe(rp);
> >> + return add_module_probe(module, rp, PROBE_TYPE_KRETPROBE,
> >> + handler, data);
> >> +}
> >> +EXPORT_SYMBOL_GPL(register_module_kretprobe);
> >> +
> >> +int __kprobes
> >> +register_module_jprobe(struct jprobe *jp,
> >> + probe_activate_handler_t handler, void *data)
> >> +{
> >> + const char *module;
> >> + module = probed_module_name(&jp->kp);
> >> + if (!module)
> >> + return register_jprobe(jp);
> >> + return add_module_probe(module, jp, PROBE_TYPE_JPROBE,
> >> + handler, data);
> >> +}
> >> +EXPORT_SYMBOL_GPL(register_module_jprobe);
> >> +
> >> +void __kprobes unregister_module_kprobe(struct kprobe *kp)
> >> +{
> >> + const char *module;
> >> + module = probed_module_name(kp);
> >> + if (!module)
> >> + unregister_kprobe(kp);
> >> + else
> >> + del_module_probe(kp);
> >> +}
> >> +EXPORT_SYMBOL_GPL(unregister_module_kprobe);
> >> +
> >> +void __kprobes unregister_module_kretprobe(struct kretprobe *rp)
> >> +{
> >> + const char *module;
> >> + module = probed_module_name(&rp->kp);
> >> + if (!module)
> >> + unregister_kretprobe(rp);
> >> + else
> >> + del_module_probe(rp);
> >> +}
> >> +EXPORT_SYMBOL_GPL(unregister_module_kretprobe);
> >> +
> >> +void __kprobes unregister_module_jprobe(struct jprobe *jp)
> >> +{
> >> + const char *module;
> >> + module = probed_module_name(&jp->kp);
> >> + if (!module)
> >> + unregister_jprobe(jp);
> >> + else
> >> + del_module_probe(jp);
> >> +}
> >> +EXPORT_SYMBOL_GPL(unregister_module_jprobe);
> >> +
> >> +static int module_is_probed(const char *mod, const char *sym)
> >> +{
> >> + int len = strlen(mod);
> >> + return strncmp(mod, sym, len) == 0 && sym[len] == ':';
> >> +}
> >> +
> >> +static int module_probe_callback(struct notifier_block *nb,
> >> + unsigned long state, void *module)
> >> +{
> >> + struct module_probe_client *pc;
> >> + struct module *mod = module;
> >> + if (state == MODULE_STATE_LIVE)
> >> + return NOTIFY_DONE;
> >> +
> >> + mutex_lock(&module_probe_mutex);
> >> + list_for_each_entry(pc, &module_probe_list, list) {
> >> + if (!module_is_probed(mod->name, pc->module))
> >> + continue;
> >> + if (state == MODULE_STATE_COMING &&
> >> + pc->handler(pc->data, module)) {
> >
> >
> > I don't see a place where you check if pc->handler != NULL
> > May be you could attach a stub in such cases.
>
> Please see add_module_probe(), handler == NULL case returns -EINVAL,
> and module_probe_list is internal list. So, pc->handler never be NULL.
Ah ok, I missed it.
And indeed if the users don't care about giving a handler, they just
have to use the usual kprobe functions.
> Thank you,
>
> --
> Masami Hiramatsu
>
> Software Engineer
> Hitachi Computer Products (America) Inc.
> Software Solutions Division
>
> e-mail: mhiramat@redhat.com
>
prev parent reply other threads:[~2009-03-21 0:08 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-20 0:08 Masami Hiramatsu
2009-03-20 1:55 ` Frederic Weisbecker
2009-03-20 5:43 ` Masami Hiramatsu
2009-03-20 3:03 ` Frederic Weisbecker
2009-03-20 4:41 ` Masami Hiramatsu
2009-03-21 1:32 ` Frederic Weisbecker [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090321000844.GD6044@nowhere \
--to=fweisbec@gmail.com \
--cc=ananth@in.ibm.com \
--cc=jkenisto@us.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mhiramat@redhat.com \
--cc=mingo@elte.hu \
--cc=systemtap@sources.redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).