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