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