]>
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 <[email protected]> |
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 | ||
10 | #include "trace/control.h" | |
5b808275 LV |
11 | #ifdef CONFIG_TRACE_SIMPLE |
12 | #include "trace/simple.h" | |
13 | #endif | |
14 | #ifdef CONFIG_TRACE_FTRACE | |
15 | #include "trace/ftrace.h" | |
16 | #endif | |
a35d9be6 | 17 | #include "qemu/error-report.h" |
23d15e86 | 18 | |
b1bae816 LV |
19 | TraceEvent *trace_event_name(const char *name) |
20 | { | |
21 | assert(name != NULL); | |
22 | ||
23 | TraceEventID i; | |
24 | for (i = 0; i < trace_event_count(); i++) { | |
25 | TraceEvent *ev = trace_event_id(i); | |
26 | if (strcmp(trace_event_get_name(ev), name) == 0) { | |
27 | return ev; | |
28 | } | |
29 | } | |
30 | return NULL; | |
31 | } | |
32 | ||
33 | static bool pattern_glob(const char *pat, const char *ev) | |
34 | { | |
35 | while (*pat != '\0' && *ev != '\0') { | |
36 | if (*pat == *ev) { | |
37 | pat++; | |
38 | ev++; | |
39 | } | |
40 | else if (*pat == '*') { | |
41 | if (pattern_glob(pat, ev+1)) { | |
42 | return true; | |
43 | } else if (pattern_glob(pat+1, ev)) { | |
44 | return true; | |
45 | } else { | |
46 | return false; | |
47 | } | |
48 | } else { | |
49 | return false; | |
50 | } | |
51 | } | |
52 | ||
53 | while (*pat == '*') { | |
54 | pat++; | |
55 | } | |
56 | ||
57 | if (*pat == '\0' && *ev == '\0') { | |
58 | return true; | |
59 | } else { | |
60 | return false; | |
61 | } | |
62 | } | |
63 | ||
64 | TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev) | |
23d15e86 | 65 | { |
b1bae816 | 66 | assert(pat != NULL); |
ddde8acc | 67 | |
b1bae816 LV |
68 | TraceEventID i; |
69 | ||
70 | if (ev == NULL) { | |
71 | i = -1; | |
72 | } else { | |
73 | i = trace_event_get_id(ev); | |
74 | } | |
75 | i++; | |
76 | ||
77 | while (i < trace_event_count()) { | |
78 | TraceEvent *res = trace_event_id(i); | |
79 | if (pattern_glob(pat, trace_event_get_name(res))) { | |
80 | return res; | |
81 | } | |
82 | i++; | |
83 | } | |
84 | ||
85 | return NULL; | |
86 | } | |
87 | ||
5b808275 LV |
88 | void trace_print_events(FILE *stream, fprintf_function stream_printf) |
89 | { | |
90 | TraceEventID i; | |
91 | ||
92 | for (i = 0; i < trace_event_count(); i++) { | |
93 | TraceEvent *ev = trace_event_id(i); | |
94 | stream_printf(stream, "%s [Event ID %u] : state %u\n", | |
95 | trace_event_get_name(ev), i, | |
96 | trace_event_get_state_static(ev) && | |
97 | trace_event_get_state_dynamic(ev)); | |
98 | } | |
99 | } | |
100 | ||
101 | static void trace_init_events(const char *fname) | |
b1bae816 | 102 | { |
a35d9be6 AK |
103 | Location loc; |
104 | FILE *fp; | |
105 | char line_buf[1024]; | |
106 | size_t line_idx = 0; | |
107 | ||
23d15e86 LV |
108 | if (fname == NULL) { |
109 | return; | |
110 | } | |
111 | ||
a35d9be6 AK |
112 | loc_push_none(&loc); |
113 | loc_set_file(fname, 0); | |
114 | fp = fopen(fname, "r"); | |
23d15e86 | 115 | if (!fp) { |
a35d9be6 | 116 | error_report("%s", strerror(errno)); |
23d15e86 LV |
117 | exit(1); |
118 | } | |
23d15e86 | 119 | while (fgets(line_buf, sizeof(line_buf), fp)) { |
a35d9be6 | 120 | loc_set_file(fname, ++line_idx); |
23d15e86 LV |
121 | size_t len = strlen(line_buf); |
122 | if (len > 1) { /* skip empty lines */ | |
123 | line_buf[len - 1] = '\0'; | |
794b1f96 AK |
124 | if ('#' == line_buf[0]) { /* skip commented lines */ |
125 | continue; | |
126 | } | |
b1bae816 LV |
127 | const bool enable = ('-' != line_buf[0]); |
128 | char *line_ptr = enable ? line_buf : line_buf + 1; | |
129 | if (trace_event_is_pattern(line_ptr)) { | |
130 | TraceEvent *ev = NULL; | |
131 | while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) { | |
132 | if (trace_event_get_state_static(ev)) { | |
133 | trace_event_set_state_dynamic(ev, enable); | |
134 | } | |
135 | } | |
ddde8acc | 136 | } else { |
b1bae816 LV |
137 | TraceEvent *ev = trace_event_name(line_ptr); |
138 | if (ev == NULL) { | |
a35d9be6 AK |
139 | error_report("WARNING: trace event '%s' does not exist", |
140 | line_ptr); | |
82432638 | 141 | } else if (!trace_event_get_state_static(ev)) { |
a35d9be6 AK |
142 | error_report("WARNING: trace event '%s' is not traceable\n", |
143 | line_ptr); | |
82432638 AK |
144 | } else { |
145 | trace_event_set_state_dynamic(ev, enable); | |
b1bae816 | 146 | } |
23d15e86 LV |
147 | } |
148 | } | |
149 | } | |
150 | if (fclose(fp) != 0) { | |
a35d9be6 AK |
151 | loc_set_file(fname, 0); |
152 | error_report("%s", strerror(errno)); | |
23d15e86 LV |
153 | exit(1); |
154 | } | |
a35d9be6 | 155 | loc_pop(&loc); |
23d15e86 | 156 | } |
5b808275 LV |
157 | |
158 | bool trace_init_backends(const char *events, const char *file) | |
159 | { | |
160 | #ifdef CONFIG_TRACE_SIMPLE | |
161 | if (!st_init(file)) { | |
162 | fprintf(stderr, "failed to initialize simple tracing backend.\n"); | |
163 | return false; | |
164 | } | |
165 | #else | |
166 | if (file) { | |
167 | fprintf(stderr, "error: -trace file=...: " | |
168 | "option not supported by the selected tracing backends\n"); | |
169 | return false; | |
170 | } | |
171 | #endif | |
172 | ||
173 | #ifdef CONFIG_TRACE_FTRACE | |
174 | if (!ftrace_init()) { | |
175 | fprintf(stderr, "failed to initialize ftrace backend.\n"); | |
176 | return false; | |
177 | } | |
178 | #endif | |
179 | ||
180 | trace_init_events(events); | |
181 | return true; | |
182 | } |