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