xref: /openbmc/qemu/trace/control.c (revision b917da4c)
1 /*
2  * Interface for configuring and controlling the state of tracing events.
3  *
4  * Copyright (C) 2011-2014 Lluís Vilanova <vilanova@ac.upc.edu>
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  * See the COPYING file in the top-level directory.
8  */
9 
10 #include "qemu/osdep.h"
11 #include "trace/control.h"
12 #ifdef CONFIG_TRACE_SIMPLE
13 #include "trace/simple.h"
14 #endif
15 #ifdef CONFIG_TRACE_FTRACE
16 #include "trace/ftrace.h"
17 #endif
18 #ifdef CONFIG_TRACE_LOG
19 #include "qemu/log.h"
20 #endif
21 #include "qemu/error-report.h"
22 
23 int trace_events_enabled_count;
24 bool trace_events_dstate[TRACE_EVENT_COUNT];
25 
26 TraceEvent *trace_event_name(const char *name)
27 {
28     assert(name != NULL);
29 
30     TraceEventID i;
31     for (i = 0; i < trace_event_count(); i++) {
32         TraceEvent *ev = trace_event_id(i);
33         if (strcmp(trace_event_get_name(ev), name) == 0) {
34             return ev;
35         }
36     }
37     return NULL;
38 }
39 
40 static bool pattern_glob(const char *pat, const char *ev)
41 {
42     while (*pat != '\0' && *ev != '\0') {
43         if (*pat == *ev) {
44             pat++;
45             ev++;
46         }
47         else if (*pat == '*') {
48             if (pattern_glob(pat, ev+1)) {
49                 return true;
50             } else if (pattern_glob(pat+1, ev)) {
51                 return true;
52             } else {
53                 return false;
54             }
55         } else {
56             return false;
57         }
58     }
59 
60     while (*pat == '*') {
61         pat++;
62     }
63 
64     if (*pat == '\0' && *ev == '\0') {
65         return true;
66     } else {
67         return false;
68     }
69 }
70 
71 TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev)
72 {
73     assert(pat != NULL);
74 
75     TraceEventID i;
76 
77     if (ev == NULL) {
78         i = -1;
79     } else {
80         i = trace_event_get_id(ev);
81     }
82     i++;
83 
84     while (i < trace_event_count()) {
85         TraceEvent *res = trace_event_id(i);
86         if (pattern_glob(pat, trace_event_get_name(res))) {
87             return res;
88         }
89         i++;
90     }
91 
92     return NULL;
93 }
94 
95 void trace_list_events(void)
96 {
97     int i;
98     for (i = 0; i < trace_event_count(); i++) {
99         TraceEvent *res = trace_event_id(i);
100         fprintf(stderr, "%s\n", trace_event_get_name(res));
101     }
102 }
103 
104 static void do_trace_enable_events(const char *line_buf)
105 {
106     const bool enable = ('-' != line_buf[0]);
107     const char *line_ptr = enable ? line_buf : line_buf + 1;
108 
109     if (trace_event_is_pattern(line_ptr)) {
110         TraceEvent *ev = NULL;
111         while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) {
112             if (trace_event_get_state_static(ev)) {
113                 trace_event_set_state_dynamic(ev, enable);
114             }
115         }
116     } else {
117         TraceEvent *ev = trace_event_name(line_ptr);
118         if (ev == NULL) {
119             error_report("WARNING: trace event '%s' does not exist",
120                          line_ptr);
121         } else if (!trace_event_get_state_static(ev)) {
122             error_report("WARNING: trace event '%s' is not traceable",
123                          line_ptr);
124         } else {
125             trace_event_set_state_dynamic(ev, enable);
126         }
127     }
128 }
129 
130 void trace_enable_events(const char *line_buf)
131 {
132     if (is_help_option(line_buf)) {
133         trace_list_events();
134         exit(0);
135     } else {
136         do_trace_enable_events(line_buf);
137     }
138 }
139 
140 void trace_init_events(const char *fname)
141 {
142     Location loc;
143     FILE *fp;
144     char line_buf[1024];
145     size_t line_idx = 0;
146 
147     if (fname == NULL) {
148         return;
149     }
150 
151     loc_push_none(&loc);
152     loc_set_file(fname, 0);
153     fp = fopen(fname, "r");
154     if (!fp) {
155         error_report("%s", strerror(errno));
156         exit(1);
157     }
158     while (fgets(line_buf, sizeof(line_buf), fp)) {
159         loc_set_file(fname, ++line_idx);
160         size_t len = strlen(line_buf);
161         if (len > 1) {              /* skip empty lines */
162             line_buf[len - 1] = '\0';
163             if ('#' == line_buf[0]) { /* skip commented lines */
164                 continue;
165             }
166             trace_enable_events(line_buf);
167         }
168     }
169     if (fclose(fp) != 0) {
170         loc_set_file(fname, 0);
171         error_report("%s", strerror(errno));
172         exit(1);
173     }
174     loc_pop(&loc);
175 }
176 
177 void trace_init_file(const char *file)
178 {
179 #ifdef CONFIG_TRACE_SIMPLE
180     st_set_trace_file(file);
181 #elif defined CONFIG_TRACE_LOG
182     /* If both the simple and the log backends are enabled, "-trace file"
183      * only applies to the simple backend; use "-D" for the log backend.
184      */
185     if (file) {
186         qemu_set_log_filename(file);
187     }
188 #else
189     if (file) {
190         fprintf(stderr, "error: -trace file=...: "
191                 "option not supported by the selected tracing backends\n");
192         exit(1);
193     }
194 #endif
195 }
196 
197 bool trace_init_backends(void)
198 {
199 #ifdef CONFIG_TRACE_SIMPLE
200     if (!st_init()) {
201         fprintf(stderr, "failed to initialize simple tracing backend.\n");
202         return false;
203     }
204 #endif
205 
206 #ifdef CONFIG_TRACE_FTRACE
207     if (!ftrace_init()) {
208         fprintf(stderr, "failed to initialize ftrace backend.\n");
209         return false;
210     }
211 #endif
212 
213     return true;
214 }
215