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