]>
Commit | Line | Data |
---|---|---|
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 "trace/control.h" | |
11 | #ifdef CONFIG_TRACE_SIMPLE | |
12 | #include "trace/simple.h" | |
13 | #endif | |
14 | #ifdef CONFIG_TRACE_FTRACE | |
15 | #include "trace/ftrace.h" | |
16 | #endif | |
17 | #include "qemu/error-report.h" | |
18 | ||
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) | |
65 | { | |
66 | assert(pat != NULL); | |
67 | ||
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 | ||
88 | static void trace_init_events(const char *fname) | |
89 | { | |
90 | Location loc; | |
91 | FILE *fp; | |
92 | char line_buf[1024]; | |
93 | size_t line_idx = 0; | |
94 | ||
95 | if (fname == NULL) { | |
96 | return; | |
97 | } | |
98 | ||
99 | loc_push_none(&loc); | |
100 | loc_set_file(fname, 0); | |
101 | fp = fopen(fname, "r"); | |
102 | if (!fp) { | |
103 | error_report("%s", strerror(errno)); | |
104 | exit(1); | |
105 | } | |
106 | while (fgets(line_buf, sizeof(line_buf), fp)) { | |
107 | loc_set_file(fname, ++line_idx); | |
108 | size_t len = strlen(line_buf); | |
109 | if (len > 1) { /* skip empty lines */ | |
110 | line_buf[len - 1] = '\0'; | |
111 | if ('#' == line_buf[0]) { /* skip commented lines */ | |
112 | continue; | |
113 | } | |
114 | const bool enable = ('-' != line_buf[0]); | |
115 | char *line_ptr = enable ? line_buf : line_buf + 1; | |
116 | if (trace_event_is_pattern(line_ptr)) { | |
117 | TraceEvent *ev = NULL; | |
118 | while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) { | |
119 | if (trace_event_get_state_static(ev)) { | |
120 | trace_event_set_state_dynamic(ev, enable); | |
121 | } | |
122 | } | |
123 | } else { | |
124 | TraceEvent *ev = trace_event_name(line_ptr); | |
125 | if (ev == NULL) { | |
126 | error_report("WARNING: trace event '%s' does not exist", | |
127 | line_ptr); | |
128 | } else if (!trace_event_get_state_static(ev)) { | |
129 | error_report("WARNING: trace event '%s' is not traceable\n", | |
130 | line_ptr); | |
131 | } else { | |
132 | trace_event_set_state_dynamic(ev, enable); | |
133 | } | |
134 | } | |
135 | } | |
136 | } | |
137 | if (fclose(fp) != 0) { | |
138 | loc_set_file(fname, 0); | |
139 | error_report("%s", strerror(errno)); | |
140 | exit(1); | |
141 | } | |
142 | loc_pop(&loc); | |
143 | } | |
144 | ||
145 | bool trace_init_backends(const char *events, const char *file) | |
146 | { | |
147 | #ifdef CONFIG_TRACE_SIMPLE | |
148 | if (!st_init(file)) { | |
149 | fprintf(stderr, "failed to initialize simple tracing backend.\n"); | |
150 | return false; | |
151 | } | |
152 | #else | |
153 | if (file) { | |
154 | fprintf(stderr, "error: -trace file=...: " | |
155 | "option not supported by the selected tracing backends\n"); | |
156 | return false; | |
157 | } | |
158 | #endif | |
159 | ||
160 | #ifdef CONFIG_TRACE_FTRACE | |
161 | if (!ftrace_init()) { | |
162 | fprintf(stderr, "failed to initialize ftrace backend.\n"); | |
163 | return false; | |
164 | } | |
165 | #endif | |
166 | ||
167 | trace_init_events(events); | |
168 | return true; | |
169 | } |