blob: a0b41cc26f267223587aaf434222f159193979d8 [file] [log] [blame]
Steven Rostedtb77e38a2009-02-24 10:21:36 -05001/*
2 * event tracer
3 *
4 * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
5 *
Steven Rostedt981d0812009-03-02 13:53:59 -05006 * - Added format output of fields of the trace point.
7 * This was based off of work by Tom Zanussi <tzanussi@gmail.com>.
8 *
Steven Rostedtb77e38a2009-02-24 10:21:36 -05009 */
10
11#include <linux/debugfs.h>
12#include <linux/uaccess.h>
13#include <linux/module.h>
14#include <linux/ctype.h>
15
Steven Rostedt91729ef2009-03-02 15:03:01 -050016#include "trace_output.h"
Steven Rostedtb77e38a2009-02-24 10:21:36 -050017
Steven Rostedtb628b3e2009-02-27 23:32:58 -050018#define TRACE_SYSTEM "TRACE_SYSTEM"
19
Steven Rostedt11a241a2009-03-02 11:49:04 -050020static DEFINE_MUTEX(event_mutex);
21
Steven Rostedt1473e442009-02-24 14:15:08 -050022#define events_for_each(event) \
23 for (event = __start_ftrace_events; \
24 (unsigned long)event < (unsigned long)__stop_ftrace_events; \
25 event++)
26
Steven Rostedtb77e38a2009-02-24 10:21:36 -050027void event_trace_printk(unsigned long ip, const char *fmt, ...)
28{
29 va_list ap;
30
31 va_start(ap, fmt);
32 tracing_record_cmdline(current);
33 trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap);
34 va_end(ap);
35}
36
37static void ftrace_clear_events(void)
38{
39 struct ftrace_event_call *call = (void *)__start_ftrace_events;
40
41
42 while ((unsigned long)call < (unsigned long)__stop_ftrace_events) {
43
44 if (call->enabled) {
45 call->enabled = 0;
46 call->unregfunc();
47 }
48 call++;
49 }
50}
51
Steven Rostedtfd994982009-02-28 02:41:25 -050052static void ftrace_event_enable_disable(struct ftrace_event_call *call,
53 int enable)
54{
55
56 switch (enable) {
57 case 0:
58 if (call->enabled) {
59 call->enabled = 0;
60 call->unregfunc();
61 }
Steven Rostedtfd994982009-02-28 02:41:25 -050062 break;
63 case 1:
Steven Rostedtda4d0302009-03-09 17:14:30 -040064 if (!call->enabled) {
Steven Rostedtfd994982009-02-28 02:41:25 -050065 call->enabled = 1;
66 call->regfunc();
67 }
Steven Rostedtfd994982009-02-28 02:41:25 -050068 break;
69 }
70}
71
Steven Rostedtb77e38a2009-02-24 10:21:36 -050072static int ftrace_set_clr_event(char *buf, int set)
73{
Steven Rostedt1473e442009-02-24 14:15:08 -050074 struct ftrace_event_call *call = __start_ftrace_events;
Steven Rostedtb628b3e2009-02-27 23:32:58 -050075 char *event = NULL, *sub = NULL, *match;
76 int ret = -EINVAL;
Steven Rostedtb77e38a2009-02-24 10:21:36 -050077
Steven Rostedtb628b3e2009-02-27 23:32:58 -050078 /*
79 * The buf format can be <subsystem>:<event-name>
80 * *:<event-name> means any event by that name.
81 * :<event-name> is the same.
82 *
83 * <subsystem>:* means all events in that subsystem
84 * <subsystem>: means the same.
85 *
86 * <name> (no ':') means all events in a subsystem with
87 * the name <name> or any event that matches <name>
88 */
89
90 match = strsep(&buf, ":");
91 if (buf) {
92 sub = match;
93 event = buf;
94 match = NULL;
95
96 if (!strlen(sub) || strcmp(sub, "*") == 0)
97 sub = NULL;
98 if (!strlen(event) || strcmp(event, "*") == 0)
99 event = NULL;
100 }
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500101
Steven Rostedt11a241a2009-03-02 11:49:04 -0500102 mutex_lock(&event_mutex);
Steven Rostedt1473e442009-02-24 14:15:08 -0500103 events_for_each(call) {
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500104
Steven Rostedt1473e442009-02-24 14:15:08 -0500105 if (!call->name)
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500106 continue;
Steven Rostedt1473e442009-02-24 14:15:08 -0500107
Steven Rostedtb628b3e2009-02-27 23:32:58 -0500108 if (match &&
109 strcmp(match, call->name) != 0 &&
110 strcmp(match, call->system) != 0)
111 continue;
112
113 if (sub && strcmp(sub, call->system) != 0)
114 continue;
115
116 if (event && strcmp(event, call->name) != 0)
Steven Rostedt1473e442009-02-24 14:15:08 -0500117 continue;
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500118
Steven Rostedtfd994982009-02-28 02:41:25 -0500119 ftrace_event_enable_disable(call, set);
120
Steven Rostedtb628b3e2009-02-27 23:32:58 -0500121 ret = 0;
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500122 }
Steven Rostedt11a241a2009-03-02 11:49:04 -0500123 mutex_unlock(&event_mutex);
124
Steven Rostedtb628b3e2009-02-27 23:32:58 -0500125 return ret;
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500126}
127
128/* 128 should be much more than enough */
129#define EVENT_BUF_SIZE 127
130
131static ssize_t
132ftrace_event_write(struct file *file, const char __user *ubuf,
133 size_t cnt, loff_t *ppos)
134{
135 size_t read = 0;
136 int i, set = 1;
137 ssize_t ret;
138 char *buf;
139 char ch;
140
141 if (!cnt || cnt < 0)
142 return 0;
143
144 ret = get_user(ch, ubuf++);
145 if (ret)
146 return ret;
147 read++;
148 cnt--;
149
150 /* skip white space */
151 while (cnt && isspace(ch)) {
152 ret = get_user(ch, ubuf++);
153 if (ret)
154 return ret;
155 read++;
156 cnt--;
157 }
158
159 /* Only white space found? */
160 if (isspace(ch)) {
161 file->f_pos += read;
162 ret = read;
163 return ret;
164 }
165
166 buf = kmalloc(EVENT_BUF_SIZE+1, GFP_KERNEL);
167 if (!buf)
168 return -ENOMEM;
169
170 if (cnt > EVENT_BUF_SIZE)
171 cnt = EVENT_BUF_SIZE;
172
173 i = 0;
174 while (cnt && !isspace(ch)) {
175 if (!i && ch == '!')
176 set = 0;
177 else
178 buf[i++] = ch;
179
180 ret = get_user(ch, ubuf++);
181 if (ret)
182 goto out_free;
183 read++;
184 cnt--;
185 }
186 buf[i] = 0;
187
188 file->f_pos += read;
189
190 ret = ftrace_set_clr_event(buf, set);
191 if (ret)
192 goto out_free;
193
194 ret = read;
195
196 out_free:
197 kfree(buf);
198
199 return ret;
200}
201
202static void *
203t_next(struct seq_file *m, void *v, loff_t *pos)
204{
205 struct ftrace_event_call *call = m->private;
206 struct ftrace_event_call *next = call;
207
208 (*pos)++;
209
210 if ((unsigned long)call >= (unsigned long)__stop_ftrace_events)
211 return NULL;
212
213 m->private = ++next;
214
215 return call;
216}
217
218static void *t_start(struct seq_file *m, loff_t *pos)
219{
220 return t_next(m, NULL, pos);
221}
222
223static void *
224s_next(struct seq_file *m, void *v, loff_t *pos)
225{
226 struct ftrace_event_call *call = m->private;
227 struct ftrace_event_call *next;
228
229 (*pos)++;
230
231 retry:
232 if ((unsigned long)call >= (unsigned long)__stop_ftrace_events)
233 return NULL;
234
235 if (!call->enabled) {
236 call++;
237 goto retry;
238 }
239
240 next = call;
241 m->private = ++next;
242
243 return call;
244}
245
246static void *s_start(struct seq_file *m, loff_t *pos)
247{
248 return s_next(m, NULL, pos);
249}
250
251static int t_show(struct seq_file *m, void *v)
252{
253 struct ftrace_event_call *call = v;
254
Steven Rostedtb628b3e2009-02-27 23:32:58 -0500255 if (strcmp(call->system, TRACE_SYSTEM) != 0)
256 seq_printf(m, "%s:", call->system);
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500257 seq_printf(m, "%s\n", call->name);
258
259 return 0;
260}
261
262static void t_stop(struct seq_file *m, void *p)
263{
264}
265
266static int
267ftrace_event_seq_open(struct inode *inode, struct file *file)
268{
269 int ret;
270 const struct seq_operations *seq_ops;
271
272 if ((file->f_mode & FMODE_WRITE) &&
273 !(file->f_flags & O_APPEND))
274 ftrace_clear_events();
275
276 seq_ops = inode->i_private;
277 ret = seq_open(file, seq_ops);
278 if (!ret) {
279 struct seq_file *m = file->private_data;
280
281 m->private = __start_ftrace_events;
282 }
283 return ret;
284}
285
Steven Rostedt1473e442009-02-24 14:15:08 -0500286static ssize_t
287event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
288 loff_t *ppos)
289{
290 struct ftrace_event_call *call = filp->private_data;
291 char *buf;
292
Steven Rostedtda4d0302009-03-09 17:14:30 -0400293 if (call->enabled)
Steven Rostedt1473e442009-02-24 14:15:08 -0500294 buf = "1\n";
295 else
296 buf = "0\n";
297
298 return simple_read_from_buffer(ubuf, cnt, ppos, buf, 2);
299}
300
301static ssize_t
302event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
303 loff_t *ppos)
304{
305 struct ftrace_event_call *call = filp->private_data;
306 char buf[64];
307 unsigned long val;
308 int ret;
309
310 if (cnt >= sizeof(buf))
311 return -EINVAL;
312
313 if (copy_from_user(&buf, ubuf, cnt))
314 return -EFAULT;
315
316 buf[cnt] = 0;
317
318 ret = strict_strtoul(buf, 10, &val);
319 if (ret < 0)
320 return ret;
321
322 switch (val) {
323 case 0:
Steven Rostedt1473e442009-02-24 14:15:08 -0500324 case 1:
Steven Rostedt11a241a2009-03-02 11:49:04 -0500325 mutex_lock(&event_mutex);
Steven Rostedtfd994982009-02-28 02:41:25 -0500326 ftrace_event_enable_disable(call, val);
Steven Rostedt11a241a2009-03-02 11:49:04 -0500327 mutex_unlock(&event_mutex);
Steven Rostedt1473e442009-02-24 14:15:08 -0500328 break;
329
330 default:
331 return -EINVAL;
332 }
333
334 *ppos += cnt;
335
336 return cnt;
337}
338
Steven Rostedt91729ef2009-03-02 15:03:01 -0500339#undef FIELD
Steven Rostedt156b5f12009-03-06 10:50:53 -0500340#define FIELD(type, name) \
Steven Rostedtce8eb2b2009-03-10 10:14:35 -0400341 #type, #name, offsetof(typeof(field), name), sizeof(field.name)
Steven Rostedt91729ef2009-03-02 15:03:01 -0500342
343static int trace_write_header(struct trace_seq *s)
344{
345 struct trace_entry field;
346
347 /* struct trace_entry */
348 return trace_seq_printf(s,
Steven Rostedtce8eb2b2009-03-10 10:14:35 -0400349 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
350 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
351 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
352 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
353 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
Steven Rostedt91729ef2009-03-02 15:03:01 -0500354 "\n",
355 FIELD(unsigned char, type),
356 FIELD(unsigned char, flags),
357 FIELD(unsigned char, preempt_count),
358 FIELD(int, pid),
359 FIELD(int, tgid));
360}
Steven Rostedtda4d0302009-03-09 17:14:30 -0400361
Steven Rostedt981d0812009-03-02 13:53:59 -0500362static ssize_t
363event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
364 loff_t *ppos)
365{
366 struct ftrace_event_call *call = filp->private_data;
367 struct trace_seq *s;
368 char *buf;
369 int r;
370
371 s = kmalloc(sizeof(*s), GFP_KERNEL);
372 if (!s)
373 return -ENOMEM;
374
375 trace_seq_init(s);
376
377 if (*ppos)
378 return 0;
379
Steven Rostedtc5e4e192009-03-02 15:10:02 -0500380 /* If any of the first writes fail, so will the show_format. */
381
382 trace_seq_printf(s, "name: %s\n", call->name);
383 trace_seq_printf(s, "ID: %d\n", call->id);
384 trace_seq_printf(s, "format:\n");
Steven Rostedt91729ef2009-03-02 15:03:01 -0500385 trace_write_header(s);
386
Steven Rostedt981d0812009-03-02 13:53:59 -0500387 r = call->show_format(s);
388 if (!r) {
389 /*
390 * ug! The format output is bigger than a PAGE!!
391 */
392 buf = "FORMAT TOO BIG\n";
393 r = simple_read_from_buffer(ubuf, cnt, ppos,
394 buf, strlen(buf));
395 goto out;
396 }
397
398 r = simple_read_from_buffer(ubuf, cnt, ppos,
399 s->buffer, s->len);
400 out:
401 kfree(s);
402 return r;
403}
404
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500405static const struct seq_operations show_event_seq_ops = {
406 .start = t_start,
407 .next = t_next,
408 .show = t_show,
409 .stop = t_stop,
410};
411
412static const struct seq_operations show_set_event_seq_ops = {
413 .start = s_start,
414 .next = s_next,
415 .show = t_show,
416 .stop = t_stop,
417};
418
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500419static const struct file_operations ftrace_set_event_fops = {
420 .open = ftrace_event_seq_open,
421 .read = seq_read,
422 .write = ftrace_event_write,
423 .llseek = seq_lseek,
424 .release = seq_release,
425};
426
Steven Rostedt1473e442009-02-24 14:15:08 -0500427static const struct file_operations ftrace_enable_fops = {
428 .open = tracing_open_generic,
429 .read = event_enable_read,
430 .write = event_enable_write,
431};
432
Steven Rostedt981d0812009-03-02 13:53:59 -0500433static const struct file_operations ftrace_event_format_fops = {
434 .open = tracing_open_generic,
435 .read = event_format_read,
436};
437
Steven Rostedt1473e442009-02-24 14:15:08 -0500438static struct dentry *event_trace_events_dir(void)
439{
440 static struct dentry *d_tracer;
441 static struct dentry *d_events;
442
443 if (d_events)
444 return d_events;
445
446 d_tracer = tracing_init_dentry();
447 if (!d_tracer)
448 return NULL;
449
450 d_events = debugfs_create_dir("events", d_tracer);
451 if (!d_events)
452 pr_warning("Could not create debugfs "
453 "'events' directory\n");
454
455 return d_events;
456}
457
Steven Rostedt6ecc2d12009-02-27 21:33:02 -0500458struct event_subsystem {
459 struct list_head list;
460 const char *name;
461 struct dentry *entry;
462};
463
464static LIST_HEAD(event_subsystems);
465
466static struct dentry *
467event_subsystem_dir(const char *name, struct dentry *d_events)
468{
469 struct event_subsystem *system;
470
471 /* First see if we did not already create this dir */
472 list_for_each_entry(system, &event_subsystems, list) {
473 if (strcmp(system->name, name) == 0)
474 return system->entry;
475 }
476
477 /* need to create new entry */
478 system = kmalloc(sizeof(*system), GFP_KERNEL);
479 if (!system) {
480 pr_warning("No memory to create event subsystem %s\n",
481 name);
482 return d_events;
483 }
484
485 system->entry = debugfs_create_dir(name, d_events);
486 if (!system->entry) {
487 pr_warning("Could not create event subsystem %s\n",
488 name);
489 kfree(system);
490 return d_events;
491 }
492
493 system->name = name;
494 list_add(&system->list, &event_subsystems);
495
496 return system->entry;
497}
498
Steven Rostedt1473e442009-02-24 14:15:08 -0500499static int
500event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
501{
502 struct dentry *entry;
Steven Rostedtfd994982009-02-28 02:41:25 -0500503 int ret;
Steven Rostedt1473e442009-02-24 14:15:08 -0500504
Steven Rostedt6ecc2d12009-02-27 21:33:02 -0500505 /*
506 * If the trace point header did not define TRACE_SYSTEM
507 * then the system would be called "TRACE_SYSTEM".
508 */
509 if (strcmp(call->system, "TRACE_SYSTEM") != 0)
510 d_events = event_subsystem_dir(call->system, d_events);
511
Steven Rostedtfd994982009-02-28 02:41:25 -0500512 if (call->raw_init) {
513 ret = call->raw_init();
514 if (ret < 0) {
515 pr_warning("Could not initialize trace point"
516 " events/%s\n", call->name);
517 return ret;
518 }
519 }
520
Steven Rostedt1473e442009-02-24 14:15:08 -0500521 call->dir = debugfs_create_dir(call->name, d_events);
522 if (!call->dir) {
523 pr_warning("Could not create debugfs "
524 "'%s' directory\n", call->name);
525 return -1;
526 }
527
Steven Rostedt770cb242009-03-05 21:35:29 -0500528 if (call->regfunc) {
529 entry = debugfs_create_file("enable", 0644, call->dir, call,
530 &ftrace_enable_fops);
531 if (!entry)
532 pr_warning("Could not create debugfs "
533 "'%s/enable' entry\n", call->name);
534 }
Steven Rostedt1473e442009-02-24 14:15:08 -0500535
Steven Rostedt981d0812009-03-02 13:53:59 -0500536 /* A trace may not want to export its format */
537 if (!call->show_format)
538 return 0;
539
540 entry = debugfs_create_file("format", 0444, call->dir, call,
541 &ftrace_event_format_fops);
542 if (!entry)
543 pr_warning("Could not create debugfs "
544 "'%s/format' entry\n", call->name);
Steven Rostedtfd994982009-02-28 02:41:25 -0500545
Steven Rostedt1473e442009-02-24 14:15:08 -0500546 return 0;
547}
548
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500549static __init int event_trace_init(void)
550{
Steven Rostedt1473e442009-02-24 14:15:08 -0500551 struct ftrace_event_call *call = __start_ftrace_events;
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500552 struct dentry *d_tracer;
553 struct dentry *entry;
Steven Rostedt1473e442009-02-24 14:15:08 -0500554 struct dentry *d_events;
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500555
556 d_tracer = tracing_init_dentry();
557 if (!d_tracer)
558 return 0;
559
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500560 entry = debugfs_create_file("set_event", 0644, d_tracer,
561 (void *)&show_set_event_seq_ops,
562 &ftrace_set_event_fops);
563 if (!entry)
564 pr_warning("Could not create debugfs "
565 "'set_event' entry\n");
566
Steven Rostedt1473e442009-02-24 14:15:08 -0500567 d_events = event_trace_events_dir();
568 if (!d_events)
569 return 0;
570
571 events_for_each(call) {
572 /* The linker may leave blanks */
573 if (!call->name)
574 continue;
575 event_create_dir(call, d_events);
576 }
577
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500578 return 0;
579}
580fs_initcall(event_trace_init);