This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC][PATCH -tip 8/9] kprobes: support respawn probes for module probing


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
> 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]