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