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