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