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