Re: [RFC][PATCH -tip 1/5 V2] tracing: kprobe-tracer plugin core
From: Frederic Weisbecker
Date: Fri Mar 20 2009 - 22:42:34 EST
On Fri, Mar 20, 2009 at 09:33:30PM -0400, Masami Hiramatsu wrote:
> Add kprobes based event tracer on ftrace.
>
> This tracer is similar to the events tracer which is based on Tracepoint
> infrastructure. Instead of Tracepoint, this tracer is based on kprobes(kprobe
> and kretprobe). It probes anywhere where kprobes can probe(this means, all
> functions body except for __kprobes functions).
>
> changes from v1:
> - fix a bug in offset parsing.
> - use __trace_bprintk() instead of __trace_printk().
>
> Signed-off-by: Masami Hiramatsu <mhiramat@xxxxxxxxxx>
> Cc: Steven Rostedt <rostedt@xxxxxxxxxxx>
> Cc: Ananth N Mavinakayanahalli <ananth@xxxxxxxxxx>
> Cc: Ingo Molnar <mingo@xxxxxxx>
> Cc: Frederic Weisbecker <fweisbec@xxxxxxxxx>
> ---
[ ... ]
> +/* Probes listing interfaces */
> +static void *probes_seq_start(struct seq_file *m, loff_t *pos)
> +{
> + struct trace_probe *probe;
> + loff_t n = *pos;
> +
> + mutex_lock(&probe_lock);
> + if (!list_empty(&probe_list)) {
> + list_for_each_entry(probe, &probe_list, list)
> + if (0 == n--)
> + return probe;
> + }
> + return NULL;
> +}
> +
> +static void *probes_seq_next(struct seq_file *m, void *v, loff_t *pos)
> +{
> + struct trace_probe *tp = v;
> +
> + (*pos)++;
> + if (tp->list.next == &probe_list)
> + tp = NULL;
> + else
> + tp = list_entry(tp->list.next, struct trace_probe, list);
> + return tp;
> +}
Hm, I think seq_list_start/next will be sufficient for your needs.
> +static void probes_seq_stop(struct seq_file *m, void *v)
> +{
> + mutex_unlock(&probe_lock);
> +}
> +
> +static int probes_seq_show(struct seq_file *m, void *v)
> +{
> + struct trace_probe *tp = v;
> +
> + if (tp == NULL)
> + return 0;
> +
> + if (tp->symbol)
> + seq_printf(m, "%c %s%+ld\n",
> + probe_is_return(tp) ? 'r' : 'p',
> + probe_symbol(tp), probe_offset(tp));
> + else
> + seq_printf(m, "%c 0x%p\n",
> + probe_is_return(tp) ? 'r' : 'p',
> + probe_address(tp));
> + return 0;
> +}
> +
> +static const struct seq_operations probes_seq_op = {
> + .start = probes_seq_start,
> + .next = probes_seq_next,
> + .stop = probes_seq_stop,
> + .show = probes_seq_show
> +};
> +
> +static int probes_open(struct inode *inode, struct file *file)
> +{
> + if ((file->f_mode & FMODE_WRITE) &&
> + !(file->f_flags & O_APPEND))
> + cleanup_all_probes();
> +
> + return seq_open(file, &probes_seq_op);
This seq_open is only for read case. No?
> +}
> +
> +
> +#define WRITE_BUFSIZE 128
> +
> +ssize_t probes_write(struct file *file, const char __user *buffer,
> + size_t count, loff_t *ppos)
> +{
> + char *kbuf, *tmp;
> + char **argv = NULL;
> + int argc = 0;
> + int ret;
> + size_t done;
> + size_t size;
> +
> + if (!count || count < 0)
> + return 0;
> +
> + kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL);
> + if (!kbuf)
> + return -ENOMEM;
> +
> + ret = done = 0;
> + do {
> + size = count - done;
> + if (size > WRITE_BUFSIZE)
> + size = WRITE_BUFSIZE;
> + if (copy_from_user(kbuf, buffer + done, size)) {
> + ret = -EFAULT;
> + goto out;
> + }
> + kbuf[size] = '\0';
> + tmp = strchr(kbuf, '\n');
> + if (!tmp) {
> + pr_warning("Line length is too long: "
> + "Should be less than %d.", WRITE_BUFSIZE);
> + ret = -EINVAL;
> + goto out;
> + }
> + *tmp = '\0';
> + size = tmp - kbuf + 1;
> + done += size;
> +
> + argv = argv_split(GFP_KERNEL, kbuf, &argc);
> + if (!argv) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + if (argc)
> + ret = create_trace_probe(argc, argv);
> +
> + argv_free(argv);
> + if (ret < 0)
> + goto out;
> +
> + } while (done < count);
> + ret = done;
> +out:
> + kfree(kbuf);
> + return ret;
> +}
> +
> +static const struct file_operations kprobe_points_ops = {
> + .owner = THIS_MODULE,
> + .open = probes_open,
> + .read = seq_read,
> + .llseek = seq_lseek,
> + .release = seq_release,
> + .write = probes_write,
> +};
> +
> +/* event recording functions */
> +static void kprobe_trace_record(unsigned long ip, struct trace_probe *tp,
> + struct pt_regs *regs)
> +{
> + __trace_bprintk(ip, "%s%s%+ld\n",
> + probe_is_return(tp) ? "<-" : "@",
> + probe_symbol(tp), probe_offset(tp));
> +}
> +
> +/* Make a debugfs interface for controling probe points */
> +static __init int init_kprobe_trace(void)
> +{
> + struct dentry *d_tracer;
> + struct dentry *entry;
> +
> + d_tracer = tracing_init_dentry();
> + if (!d_tracer)
> + return 0;
> +
> + entry = debugfs_create_file("kprobe_probes", 0444, d_tracer,
Shouldn't it be 0644 ?
Since its first intend, and the most important one, is to receive
commands from user?
Thanks,
Frederic.
> + NULL, &kprobe_points_ops);
> +
> + if (!entry)
> + pr_warning("Could not create debugfs "
> + "'kprobe_probess' entry\n");
> + return 0;
> +}
> +fs_initcall(init_kprobe_trace);
> +
> --
> Masami Hiramatsu
>
> Software Engineer
> Hitachi Computer Products (America) Inc.
> Software Solutions Division
>
> e-mail: mhiramat@xxxxxxxxxx
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/