aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-03-02 13:53:59 -0500
committerSteven Rostedt <srostedt@redhat.com>2009-03-02 14:27:27 -0500
commit981d081ec8b958b7d962ee40d433581a55d40fc5 (patch)
tree366aa5da7dc98cc2354002946e6f19ec60c02301 /kernel/trace
parentf9520750c4c9924c14325cd951efae5fae58104c (diff)
tracing: add format file to describe event struct fields
This patch adds the "format" file to the trace point event directory. This is based off of work by Tom Zanussi, in which a file is exported to be tread from user land such that a user space app may read the binary record stored in the ring buffer. # cat /debug/tracing/events/sched/sched_switch/format field:pid_t prev_pid; offset:12; size:4; field:int prev_prio; offset:16; size:4; field special:char next_comm[TASK_COMM_LEN]; offset:20; size:16; field:pid_t next_pid; offset:36; size:4; field:int next_prio; offset:40; size:4; Idea-from: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace.h1
-rw-r--r--kernel/trace/trace_events.c56
-rw-r--r--kernel/trace/trace_events_stage_2.h52
-rw-r--r--kernel/trace/trace_events_stage_3.h2
4 files changed, 110 insertions, 1 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index cf6ba4181b14..e606633fb498 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -754,6 +754,7 @@ struct ftrace_event_call {
754 int (*raw_init)(void); 754 int (*raw_init)(void);
755 int (*raw_reg)(void); 755 int (*raw_reg)(void);
756 void (*raw_unreg)(void); 756 void (*raw_unreg)(void);
757 int (*show_format)(struct trace_seq *s);
757}; 758};
758 759
759void event_trace_printk(unsigned long ip, const char *fmt, ...); 760void event_trace_printk(unsigned long ip, const char *fmt, ...);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 26069fa6b3b0..d57a772981c1 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -3,6 +3,9 @@
3 * 3 *
4 * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 4 * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
5 * 5 *
6 * - Added format output of fields of the trace point.
7 * This was based off of work by Tom Zanussi <tzanussi@gmail.com>.
8 *
6 */ 9 */
7 10
8#include <linux/debugfs.h> 11#include <linux/debugfs.h>
@@ -444,6 +447,42 @@ event_available_types_read(struct file *filp, char __user *ubuf, size_t cnt,
444 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); 447 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
445} 448}
446 449
450static ssize_t
451event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
452 loff_t *ppos)
453{
454 struct ftrace_event_call *call = filp->private_data;
455 struct trace_seq *s;
456 char *buf;
457 int r;
458
459 s = kmalloc(sizeof(*s), GFP_KERNEL);
460 if (!s)
461 return -ENOMEM;
462
463 trace_seq_init(s);
464
465 if (*ppos)
466 return 0;
467
468 r = call->show_format(s);
469 if (!r) {
470 /*
471 * ug! The format output is bigger than a PAGE!!
472 */
473 buf = "FORMAT TOO BIG\n";
474 r = simple_read_from_buffer(ubuf, cnt, ppos,
475 buf, strlen(buf));
476 goto out;
477 }
478
479 r = simple_read_from_buffer(ubuf, cnt, ppos,
480 s->buffer, s->len);
481 out:
482 kfree(s);
483 return r;
484}
485
447static const struct seq_operations show_event_seq_ops = { 486static const struct seq_operations show_event_seq_ops = {
448 .start = t_start, 487 .start = t_start,
449 .next = t_next, 488 .next = t_next,
@@ -490,6 +529,11 @@ static const struct file_operations ftrace_available_types_fops = {
490 .read = event_available_types_read, 529 .read = event_available_types_read,
491}; 530};
492 531
532static const struct file_operations ftrace_event_format_fops = {
533 .open = tracing_open_generic,
534 .read = event_format_read,
535};
536
493static struct dentry *event_trace_events_dir(void) 537static struct dentry *event_trace_events_dir(void)
494{ 538{
495 static struct dentry *d_tracer; 539 static struct dentry *d_tracer;
@@ -602,7 +646,17 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
602 &ftrace_available_types_fops); 646 &ftrace_available_types_fops);
603 if (!entry) 647 if (!entry)
604 pr_warning("Could not create debugfs " 648 pr_warning("Could not create debugfs "
605 "'%s/type' available_types\n", call->name); 649 "'%s/available_types' entry\n", call->name);
650
651 /* A trace may not want to export its format */
652 if (!call->show_format)
653 return 0;
654
655 entry = debugfs_create_file("format", 0444, call->dir, call,
656 &ftrace_event_format_fops);
657 if (!entry)
658 pr_warning("Could not create debugfs "
659 "'%s/format' entry\n", call->name);
606 660
607 return 0; 661 return 0;
608} 662}
diff --git a/kernel/trace/trace_events_stage_2.h b/kernel/trace/trace_events_stage_2.h
index dc79fe3a2ecb..3a80ea4e92cb 100644
--- a/kernel/trace/trace_events_stage_2.h
+++ b/kernel/trace/trace_events_stage_2.h
@@ -74,3 +74,55 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \
74} 74}
75 75
76#include <trace/trace_event_types.h> 76#include <trace/trace_event_types.h>
77
78/*
79 * Setup the showing format of trace point.
80 *
81 * int
82 * ftrace_format_##call(struct trace_seq *s)
83 * {
84 * struct ftrace_raw_##call field;
85 * int ret;
86 *
87 * ret = trace_seq_printf(s, #type " " #item ";"
88 * " size:%d; offset:%d;\n",
89 * sizeof(field.type),
90 * offsetof(struct ftrace_raw_##call,
91 * item));
92 *
93 * }
94 */
95
96#undef TRACE_FIELD
97#define TRACE_FIELD(type, item, assign) \
98 ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
99 "offset:%lu;\tsize:%lu;\n", \
100 offsetof(typeof(field), item), \
101 sizeof(field.item)); \
102 if (!ret) \
103 return 0;
104
105
106#undef TRACE_FIELD_SPECIAL
107#define TRACE_FIELD_SPECIAL(type_item, item, cmd) \
108 ret = trace_seq_printf(s, "\tfield special:" #type_item ";\t" \
109 "offset:%lu;\tsize:%lu;\n", \
110 offsetof(typeof(field), item), \
111 sizeof(field.item)); \
112 if (!ret) \
113 return 0;
114
115#undef TRACE_EVENT_FORMAT
116#define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \
117int \
118ftrace_format_##call(struct trace_seq *s) \
119{ \
120 struct ftrace_raw_##call field; \
121 int ret; \
122 \
123 tstruct; \
124 \
125 return ret; \
126}
127
128#include <trace/trace_event_types.h>
diff --git a/kernel/trace/trace_events_stage_3.h b/kernel/trace/trace_events_stage_3.h
index 2ab65e958223..c62a4d2a5283 100644
--- a/kernel/trace/trace_events_stage_3.h
+++ b/kernel/trace/trace_events_stage_3.h
@@ -101,6 +101,7 @@
101 * .raw_init = ftrace_raw_init_event_<call>, 101 * .raw_init = ftrace_raw_init_event_<call>,
102 * .raw_reg = ftrace_raw_reg_event_<call>, 102 * .raw_reg = ftrace_raw_reg_event_<call>,
103 * .raw_unreg = ftrace_raw_unreg_event_<call>, 103 * .raw_unreg = ftrace_raw_unreg_event_<call>,
104 * .show_format = ftrace_format_<call>,
104 * } 105 * }
105 * 106 *
106 */ 107 */
@@ -230,4 +231,5 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
230 .raw_init = ftrace_raw_init_event_##call, \ 231 .raw_init = ftrace_raw_init_event_##call, \
231 .raw_reg = ftrace_raw_reg_event_##call, \ 232 .raw_reg = ftrace_raw_reg_event_##call, \
232 .raw_unreg = ftrace_raw_unreg_event_##call, \ 233 .raw_unreg = ftrace_raw_unreg_event_##call, \
234 .show_format = ftrace_format_##call, \
233} 235}