blob: 1880a643809785a173fa5709169f26c3c268851d [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) \
341 #type, #name, (unsigned int)offsetof(typeof(field), name), \
342 (unsigned int)sizeof(field.name)
Steven Rostedt91729ef2009-03-02 15:03:01 -0500343
344static int trace_write_header(struct trace_seq *s)
345{
346 struct trace_entry field;
347
348 /* struct trace_entry */
349 return trace_seq_printf(s,
Steven Rostedt156b5f12009-03-06 10:50:53 -0500350 "\tfield:%s %s;\toffset:%u;\tsize:%u;\n"
351 "\tfield:%s %s;\toffset:%u;\tsize:%u;\n"
352 "\tfield:%s %s;\toffset:%u;\tsize:%u;\n"
353 "\tfield:%s %s;\toffset:%u;\tsize:%u;\n"
354 "\tfield:%s %s;\toffset:%u;\tsize:%u;\n"
Steven Rostedt91729ef2009-03-02 15:03:01 -0500355 "\n",
356 FIELD(unsigned char, type),
357 FIELD(unsigned char, flags),
358 FIELD(unsigned char, preempt_count),
359 FIELD(int, pid),
360 FIELD(int, tgid));
361}
Steven Rostedtda4d0302009-03-09 17:14:30 -0400362
Steven Rostedt981d0812009-03-02 13:53:59 -0500363static ssize_t
364event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
365 loff_t *ppos)
366{
367 struct ftrace_event_call *call = filp->private_data;
368 struct trace_seq *s;
369 char *buf;
370 int r;
371
372 s = kmalloc(sizeof(*s), GFP_KERNEL);
373 if (!s)
374 return -ENOMEM;
375
376 trace_seq_init(s);
377
378 if (*ppos)
379 return 0;
380
Steven Rostedtc5e4e192009-03-02 15:10:02 -0500381 /* If any of the first writes fail, so will the show_format. */
382
383 trace_seq_printf(s, "name: %s\n", call->name);
384 trace_seq_printf(s, "ID: %d\n", call->id);
385 trace_seq_printf(s, "format:\n");
Steven Rostedt91729ef2009-03-02 15:03:01 -0500386 trace_write_header(s);
387
Steven Rostedt981d0812009-03-02 13:53:59 -0500388 r = call->show_format(s);
389 if (!r) {
390 /*
391 * ug! The format output is bigger than a PAGE!!
392 */
393 buf = "FORMAT TOO BIG\n";
394 r = simple_read_from_buffer(ubuf, cnt, ppos,
395 buf, strlen(buf));
396 goto out;
397 }
398
399 r = simple_read_from_buffer(ubuf, cnt, ppos,
400 s->buffer, s->len);
401 out:
402 kfree(s);
403 return r;
404}
405
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500406static const struct seq_operations show_event_seq_ops = {
407 .start = t_start,
408 .next = t_next,
409 .show = t_show,
410 .stop = t_stop,
411};
412
413static const struct seq_operations show_set_event_seq_ops = {
414 .start = s_start,
415 .next = s_next,
416 .show = t_show,
417 .stop = t_stop,
418};
419
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500420static const struct file_operations ftrace_set_event_fops = {
421 .open = ftrace_event_seq_open,
422 .read = seq_read,
423 .write = ftrace_event_write,
424 .llseek = seq_lseek,
425 .release = seq_release,
426};
427
Steven Rostedt1473e442009-02-24 14:15:08 -0500428static const struct file_operations ftrace_enable_fops = {
429 .open = tracing_open_generic,
430 .read = event_enable_read,
431 .write = event_enable_write,
432};
433
Steven Rostedt981d0812009-03-02 13:53:59 -0500434static const struct file_operations ftrace_event_format_fops = {
435 .open = tracing_open_generic,
436 .read = event_format_read,
437};
438
Steven Rostedt1473e442009-02-24 14:15:08 -0500439static struct dentry *event_trace_events_dir(void)
440{
441 static struct dentry *d_tracer;
442 static struct dentry *d_events;
443
444 if (d_events)
445 return d_events;
446
447 d_tracer = tracing_init_dentry();
448 if (!d_tracer)
449 return NULL;
450
451 d_events = debugfs_create_dir("events", d_tracer);
452 if (!d_events)
453 pr_warning("Could not create debugfs "
454 "'events' directory\n");
455
456 return d_events;
457}
458
Steven Rostedt6ecc2d12009-02-27 21:33:02 -0500459struct event_subsystem {
460 struct list_head list;
461 const char *name;
462 struct dentry *entry;
463};
464
465static LIST_HEAD(event_subsystems);
466
467static struct dentry *
468event_subsystem_dir(const char *name, struct dentry *d_events)
469{
470 struct event_subsystem *system;
471
472 /* First see if we did not already create this dir */
473 list_for_each_entry(system, &event_subsystems, list) {
474 if (strcmp(system->name, name) == 0)
475 return system->entry;
476 }
477
478 /* need to create new entry */
479 system = kmalloc(sizeof(*system), GFP_KERNEL);
480 if (!system) {
481 pr_warning("No memory to create event subsystem %s\n",
482 name);
483 return d_events;
484 }
485
486 system->entry = debugfs_create_dir(name, d_events);
487 if (!system->entry) {
488 pr_warning("Could not create event subsystem %s\n",
489 name);
490 kfree(system);
491 return d_events;
492 }
493
494 system->name = name;
495 list_add(&system->list, &event_subsystems);
496
497 return system->entry;
498}
499
Steven Rostedt1473e442009-02-24 14:15:08 -0500500static int
501event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
502{
503 struct dentry *entry;
Steven Rostedtfd994982009-02-28 02:41:25 -0500504 int ret;
Steven Rostedt1473e442009-02-24 14:15:08 -0500505
Steven Rostedt6ecc2d12009-02-27 21:33:02 -0500506 /*
507 * If the trace point header did not define TRACE_SYSTEM
508 * then the system would be called "TRACE_SYSTEM".
509 */
510 if (strcmp(call->system, "TRACE_SYSTEM") != 0)
511 d_events = event_subsystem_dir(call->system, d_events);
512
Steven Rostedtfd994982009-02-28 02:41:25 -0500513 if (call->raw_init) {
514 ret = call->raw_init();
515 if (ret < 0) {
516 pr_warning("Could not initialize trace point"
517 " events/%s\n", call->name);
518 return ret;
519 }
520 }
521
Steven Rostedt1473e442009-02-24 14:15:08 -0500522 call->dir = debugfs_create_dir(call->name, d_events);
523 if (!call->dir) {
524 pr_warning("Could not create debugfs "
525 "'%s' directory\n", call->name);
526 return -1;
527 }
528
Steven Rostedt770cb242009-03-05 21:35:29 -0500529 if (call->regfunc) {
530 entry = debugfs_create_file("enable", 0644, call->dir, call,
531 &ftrace_enable_fops);
532 if (!entry)
533 pr_warning("Could not create debugfs "
534 "'%s/enable' entry\n", call->name);
535 }
Steven Rostedt1473e442009-02-24 14:15:08 -0500536
Steven Rostedt981d0812009-03-02 13:53:59 -0500537 /* A trace may not want to export its format */
538 if (!call->show_format)
539 return 0;
540
541 entry = debugfs_create_file("format", 0444, call->dir, call,
542 &ftrace_event_format_fops);
543 if (!entry)
544 pr_warning("Could not create debugfs "
545 "'%s/format' entry\n", call->name);
Steven Rostedtfd994982009-02-28 02:41:25 -0500546
Steven Rostedt1473e442009-02-24 14:15:08 -0500547 return 0;
548}
549
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500550static __init int event_trace_init(void)
551{
Steven Rostedt1473e442009-02-24 14:15:08 -0500552 struct ftrace_event_call *call = __start_ftrace_events;
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500553 struct dentry *d_tracer;
554 struct dentry *entry;
Steven Rostedt1473e442009-02-24 14:15:08 -0500555 struct dentry *d_events;
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500556
557 d_tracer = tracing_init_dentry();
558 if (!d_tracer)
559 return 0;
560
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500561 entry = debugfs_create_file("set_event", 0644, d_tracer,
562 (void *)&show_set_event_seq_ops,
563 &ftrace_set_event_fops);
564 if (!entry)
565 pr_warning("Could not create debugfs "
566 "'set_event' entry\n");
567
Steven Rostedt1473e442009-02-24 14:15:08 -0500568 d_events = event_trace_events_dir();
569 if (!d_events)
570 return 0;
571
572 events_for_each(call) {
573 /* The linker may leave blanks */
574 if (!call->name)
575 continue;
576 event_create_dir(call, d_events);
577 }
578
Steven Rostedtb77e38a2009-02-24 10:21:36 -0500579 return 0;
580}
581fs_initcall(event_trace_init);