123d15e86SLluís /* 223d15e86SLluís * Interface for configuring and controlling the state of tracing events. 323d15e86SLluís * 448151859SLluís Vilanova * Copyright (C) 2011-2016 Lluís Vilanova <vilanova@ac.upc.edu> 523d15e86SLluís * 6b1bae816SLluís Vilanova * This work is licensed under the terms of the GNU GPL, version 2 or later. 7b1bae816SLluís Vilanova * See the COPYING file in the top-level directory. 823d15e86SLluís */ 923d15e86SLluís 10d38ea87aSPeter Maydell #include "qemu/osdep.h" 1123d15e86SLluís #include "trace/control.h" 12f348b6d1SVeronia Bahaa #include "qemu/help_option.h" 135b808275SLluís Vilanova #ifdef CONFIG_TRACE_SIMPLE 145b808275SLluís Vilanova #include "trace/simple.h" 155b808275SLluís Vilanova #endif 165b808275SLluís Vilanova #ifdef CONFIG_TRACE_FTRACE 175b808275SLluís Vilanova #include "trace/ftrace.h" 185b808275SLluís Vilanova #endif 19ed7f5f1dSPaolo Bonzini #ifdef CONFIG_TRACE_LOG 20ed7f5f1dSPaolo Bonzini #include "qemu/log.h" 21ed7f5f1dSPaolo Bonzini #endif 220a852417SPaul Durrant #ifdef CONFIG_TRACE_SYSLOG 230a852417SPaul Durrant #include <syslog.h> 240a852417SPaul Durrant #endif 25daa76aa4SMarkus Armbruster #include "qapi/error.h" 26a35d9be6SAlexey Kardashevskiy #include "qemu/error-report.h" 27e9e0bb2aSDenis V. Lunev #include "qemu/config-file.h" 28acc6809dSDenis V. Lunev #include "monitor/monitor.h" 2923d15e86SLluís 3043b48cfcSPaolo Bonzini int trace_events_enabled_count; 3148151859SLluís Vilanova /* 3248151859SLluís Vilanova * Interpretation depends on wether the event has the 'vcpu' property: 3348151859SLluís Vilanova * - false: Boolean value indicating whether the event is active. 3448151859SLluís Vilanova * - true : Integral counting the number of vCPUs that have this event enabled. 3548151859SLluís Vilanova */ 3648151859SLluís Vilanova uint16_t trace_events_dstate[TRACE_EVENT_COUNT]; 3743b48cfcSPaolo Bonzini 38e9e0bb2aSDenis V. Lunev QemuOptsList qemu_trace_opts = { 39e9e0bb2aSDenis V. Lunev .name = "trace", 40e9e0bb2aSDenis V. Lunev .implied_opt_name = "enable", 41e9e0bb2aSDenis V. Lunev .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head), 42e9e0bb2aSDenis V. Lunev .desc = { 43e9e0bb2aSDenis V. Lunev { 44e9e0bb2aSDenis V. Lunev .name = "enable", 45e9e0bb2aSDenis V. Lunev .type = QEMU_OPT_STRING, 46e9e0bb2aSDenis V. Lunev }, 47e9e0bb2aSDenis V. Lunev { 48e9e0bb2aSDenis V. Lunev .name = "events", 49e9e0bb2aSDenis V. Lunev .type = QEMU_OPT_STRING, 50e9e0bb2aSDenis V. Lunev },{ 51e9e0bb2aSDenis V. Lunev .name = "file", 52e9e0bb2aSDenis V. Lunev .type = QEMU_OPT_STRING, 53e9e0bb2aSDenis V. Lunev }, 54e9e0bb2aSDenis V. Lunev { /* end of list */ } 55e9e0bb2aSDenis V. Lunev }, 56e9e0bb2aSDenis V. Lunev }; 57e9e0bb2aSDenis V. Lunev 58e9e0bb2aSDenis V. Lunev 59b1bae816SLluís Vilanova TraceEvent *trace_event_name(const char *name) 60b1bae816SLluís Vilanova { 61b1bae816SLluís Vilanova assert(name != NULL); 62b1bae816SLluís Vilanova 63b1bae816SLluís Vilanova TraceEventID i; 64b1bae816SLluís Vilanova for (i = 0; i < trace_event_count(); i++) { 65b1bae816SLluís Vilanova TraceEvent *ev = trace_event_id(i); 66b1bae816SLluís Vilanova if (strcmp(trace_event_get_name(ev), name) == 0) { 67b1bae816SLluís Vilanova return ev; 68b1bae816SLluís Vilanova } 69b1bae816SLluís Vilanova } 70b1bae816SLluís Vilanova return NULL; 71b1bae816SLluís Vilanova } 72b1bae816SLluís Vilanova 73b1bae816SLluís Vilanova static bool pattern_glob(const char *pat, const char *ev) 74b1bae816SLluís Vilanova { 75b1bae816SLluís Vilanova while (*pat != '\0' && *ev != '\0') { 76b1bae816SLluís Vilanova if (*pat == *ev) { 77b1bae816SLluís Vilanova pat++; 78b1bae816SLluís Vilanova ev++; 79b1bae816SLluís Vilanova } 80b1bae816SLluís Vilanova else if (*pat == '*') { 81b1bae816SLluís Vilanova if (pattern_glob(pat, ev+1)) { 82b1bae816SLluís Vilanova return true; 83b1bae816SLluís Vilanova } else if (pattern_glob(pat+1, ev)) { 84b1bae816SLluís Vilanova return true; 85b1bae816SLluís Vilanova } else { 86b1bae816SLluís Vilanova return false; 87b1bae816SLluís Vilanova } 88b1bae816SLluís Vilanova } else { 89b1bae816SLluís Vilanova return false; 90b1bae816SLluís Vilanova } 91b1bae816SLluís Vilanova } 92b1bae816SLluís Vilanova 93b1bae816SLluís Vilanova while (*pat == '*') { 94b1bae816SLluís Vilanova pat++; 95b1bae816SLluís Vilanova } 96b1bae816SLluís Vilanova 97b1bae816SLluís Vilanova if (*pat == '\0' && *ev == '\0') { 98b1bae816SLluís Vilanova return true; 99b1bae816SLluís Vilanova } else { 100b1bae816SLluís Vilanova return false; 101b1bae816SLluís Vilanova } 102b1bae816SLluís Vilanova } 103b1bae816SLluís Vilanova 104b1bae816SLluís Vilanova TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev) 105b1bae816SLluís Vilanova { 106b1bae816SLluís Vilanova assert(pat != NULL); 107b1bae816SLluís Vilanova 108b1bae816SLluís Vilanova TraceEventID i; 109b1bae816SLluís Vilanova 110b1bae816SLluís Vilanova if (ev == NULL) { 111b1bae816SLluís Vilanova i = -1; 112b1bae816SLluís Vilanova } else { 113b1bae816SLluís Vilanova i = trace_event_get_id(ev); 114b1bae816SLluís Vilanova } 115b1bae816SLluís Vilanova i++; 116b1bae816SLluís Vilanova 117b1bae816SLluís Vilanova while (i < trace_event_count()) { 118b1bae816SLluís Vilanova TraceEvent *res = trace_event_id(i); 119b1bae816SLluís Vilanova if (pattern_glob(pat, trace_event_get_name(res))) { 120b1bae816SLluís Vilanova return res; 121b1bae816SLluís Vilanova } 122b1bae816SLluís Vilanova i++; 123b1bae816SLluís Vilanova } 124b1bae816SLluís Vilanova 125b1bae816SLluís Vilanova return NULL; 126b1bae816SLluís Vilanova } 127b1bae816SLluís Vilanova 128*6a1b0f3aSDaniel P. Berrange void trace_event_iter_init(TraceEventIter *iter, const char *pattern) 129*6a1b0f3aSDaniel P. Berrange { 130*6a1b0f3aSDaniel P. Berrange iter->event = 0; 131*6a1b0f3aSDaniel P. Berrange iter->pattern = pattern; 132*6a1b0f3aSDaniel P. Berrange } 133*6a1b0f3aSDaniel P. Berrange 134*6a1b0f3aSDaniel P. Berrange TraceEvent *trace_event_iter_next(TraceEventIter *iter) 135*6a1b0f3aSDaniel P. Berrange { 136*6a1b0f3aSDaniel P. Berrange while (iter->event < TRACE_EVENT_COUNT) { 137*6a1b0f3aSDaniel P. Berrange TraceEvent *ev = &(trace_events[iter->event]); 138*6a1b0f3aSDaniel P. Berrange iter->event++; 139*6a1b0f3aSDaniel P. Berrange if (!iter->pattern || 140*6a1b0f3aSDaniel P. Berrange pattern_glob(iter->pattern, 141*6a1b0f3aSDaniel P. Berrange trace_event_get_name(ev))) { 142*6a1b0f3aSDaniel P. Berrange return ev; 143*6a1b0f3aSDaniel P. Berrange } 144*6a1b0f3aSDaniel P. Berrange } 145*6a1b0f3aSDaniel P. Berrange 146*6a1b0f3aSDaniel P. Berrange return NULL; 147*6a1b0f3aSDaniel P. Berrange } 148*6a1b0f3aSDaniel P. Berrange 149e9527dd3SPaolo Bonzini void trace_list_events(void) 150e9527dd3SPaolo Bonzini { 151e9527dd3SPaolo Bonzini int i; 152e9527dd3SPaolo Bonzini for (i = 0; i < trace_event_count(); i++) { 153e9527dd3SPaolo Bonzini TraceEvent *res = trace_event_id(i); 154e9527dd3SPaolo Bonzini fprintf(stderr, "%s\n", trace_event_get_name(res)); 155e9527dd3SPaolo Bonzini } 156e9527dd3SPaolo Bonzini } 157e9527dd3SPaolo Bonzini 158e9527dd3SPaolo Bonzini static void do_trace_enable_events(const char *line_buf) 15910578a25SPaolo Bonzini { 16010578a25SPaolo Bonzini const bool enable = ('-' != line_buf[0]); 16110578a25SPaolo Bonzini const char *line_ptr = enable ? line_buf : line_buf + 1; 16210578a25SPaolo Bonzini 16310578a25SPaolo Bonzini if (trace_event_is_pattern(line_ptr)) { 16410578a25SPaolo Bonzini TraceEvent *ev = NULL; 16510578a25SPaolo Bonzini while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) { 16610578a25SPaolo Bonzini if (trace_event_get_state_static(ev)) { 167a4d50b1dSLluís Vilanova trace_event_set_state_dynamic_init(ev, enable); 16810578a25SPaolo Bonzini } 16910578a25SPaolo Bonzini } 17010578a25SPaolo Bonzini } else { 17110578a25SPaolo Bonzini TraceEvent *ev = trace_event_name(line_ptr); 17210578a25SPaolo Bonzini if (ev == NULL) { 17310578a25SPaolo Bonzini error_report("WARNING: trace event '%s' does not exist", 17410578a25SPaolo Bonzini line_ptr); 17510578a25SPaolo Bonzini } else if (!trace_event_get_state_static(ev)) { 17610578a25SPaolo Bonzini error_report("WARNING: trace event '%s' is not traceable", 17710578a25SPaolo Bonzini line_ptr); 17810578a25SPaolo Bonzini } else { 179a4d50b1dSLluís Vilanova trace_event_set_state_dynamic_init(ev, enable); 18010578a25SPaolo Bonzini } 18110578a25SPaolo Bonzini } 18210578a25SPaolo Bonzini } 18310578a25SPaolo Bonzini 184e9527dd3SPaolo Bonzini void trace_enable_events(const char *line_buf) 185e9527dd3SPaolo Bonzini { 186e9527dd3SPaolo Bonzini if (is_help_option(line_buf)) { 187e9527dd3SPaolo Bonzini trace_list_events(); 188acc6809dSDenis V. Lunev if (cur_mon == NULL) { 189e9527dd3SPaolo Bonzini exit(0); 190acc6809dSDenis V. Lunev } 191e9527dd3SPaolo Bonzini } else { 192e9527dd3SPaolo Bonzini do_trace_enable_events(line_buf); 193e9527dd3SPaolo Bonzini } 194e9527dd3SPaolo Bonzini } 195e9527dd3SPaolo Bonzini 196e9e0bb2aSDenis V. Lunev static void trace_init_events(const char *fname) 19723d15e86SLluís { 198a35d9be6SAlexey Kardashevskiy Location loc; 199a35d9be6SAlexey Kardashevskiy FILE *fp; 200a35d9be6SAlexey Kardashevskiy char line_buf[1024]; 201a35d9be6SAlexey Kardashevskiy size_t line_idx = 0; 202a35d9be6SAlexey Kardashevskiy 20323d15e86SLluís if (fname == NULL) { 20423d15e86SLluís return; 20523d15e86SLluís } 20623d15e86SLluís 207a35d9be6SAlexey Kardashevskiy loc_push_none(&loc); 208a35d9be6SAlexey Kardashevskiy loc_set_file(fname, 0); 209a35d9be6SAlexey Kardashevskiy fp = fopen(fname, "r"); 21023d15e86SLluís if (!fp) { 211a35d9be6SAlexey Kardashevskiy error_report("%s", strerror(errno)); 21223d15e86SLluís exit(1); 21323d15e86SLluís } 21423d15e86SLluís while (fgets(line_buf, sizeof(line_buf), fp)) { 215a35d9be6SAlexey Kardashevskiy loc_set_file(fname, ++line_idx); 21623d15e86SLluís size_t len = strlen(line_buf); 21723d15e86SLluís if (len > 1) { /* skip empty lines */ 21823d15e86SLluís line_buf[len - 1] = '\0'; 219794b1f96SAlexey Kardashevskiy if ('#' == line_buf[0]) { /* skip commented lines */ 220794b1f96SAlexey Kardashevskiy continue; 221794b1f96SAlexey Kardashevskiy } 22210578a25SPaolo Bonzini trace_enable_events(line_buf); 22323d15e86SLluís } 22482432638SAlexey Kardashevskiy } 22523d15e86SLluís if (fclose(fp) != 0) { 226a35d9be6SAlexey Kardashevskiy loc_set_file(fname, 0); 227a35d9be6SAlexey Kardashevskiy error_report("%s", strerror(errno)); 22823d15e86SLluís exit(1); 22923d15e86SLluís } 230a35d9be6SAlexey Kardashevskiy loc_pop(&loc); 23123d15e86SLluís } 2325b808275SLluís Vilanova 23341fc57e4SPaolo Bonzini void trace_init_file(const char *file) 2345b808275SLluís Vilanova { 2355b808275SLluís Vilanova #ifdef CONFIG_TRACE_SIMPLE 23641fc57e4SPaolo Bonzini st_set_trace_file(file); 237ed7f5f1dSPaolo Bonzini #elif defined CONFIG_TRACE_LOG 238ed7f5f1dSPaolo Bonzini /* If both the simple and the log backends are enabled, "-trace file" 239ed7f5f1dSPaolo Bonzini * only applies to the simple backend; use "-D" for the log backend. 240ed7f5f1dSPaolo Bonzini */ 241ed7f5f1dSPaolo Bonzini if (file) { 242daa76aa4SMarkus Armbruster qemu_set_log_filename(file, &error_fatal); 243ed7f5f1dSPaolo Bonzini } 2445b808275SLluís Vilanova #else 2455b808275SLluís Vilanova if (file) { 2465b808275SLluís Vilanova fprintf(stderr, "error: -trace file=...: " 2475b808275SLluís Vilanova "option not supported by the selected tracing backends\n"); 24841fc57e4SPaolo Bonzini exit(1); 24941fc57e4SPaolo Bonzini } 25041fc57e4SPaolo Bonzini #endif 25141fc57e4SPaolo Bonzini } 25241fc57e4SPaolo Bonzini 25341fc57e4SPaolo Bonzini bool trace_init_backends(void) 25441fc57e4SPaolo Bonzini { 25541fc57e4SPaolo Bonzini #ifdef CONFIG_TRACE_SIMPLE 25641fc57e4SPaolo Bonzini if (!st_init()) { 25741fc57e4SPaolo Bonzini fprintf(stderr, "failed to initialize simple tracing backend.\n"); 2585b808275SLluís Vilanova return false; 2595b808275SLluís Vilanova } 2605b808275SLluís Vilanova #endif 2615b808275SLluís Vilanova 2625b808275SLluís Vilanova #ifdef CONFIG_TRACE_FTRACE 2635b808275SLluís Vilanova if (!ftrace_init()) { 2645b808275SLluís Vilanova fprintf(stderr, "failed to initialize ftrace backend.\n"); 2655b808275SLluís Vilanova return false; 2665b808275SLluís Vilanova } 2675b808275SLluís Vilanova #endif 2685b808275SLluís Vilanova 2690a852417SPaul Durrant #ifdef CONFIG_TRACE_SYSLOG 2700a852417SPaul Durrant openlog(NULL, LOG_PID, LOG_DAEMON); 2710a852417SPaul Durrant #endif 2720a852417SPaul Durrant 2735b808275SLluís Vilanova return true; 2745b808275SLluís Vilanova } 275e9e0bb2aSDenis V. Lunev 276e9e0bb2aSDenis V. Lunev char *trace_opt_parse(const char *optarg) 277e9e0bb2aSDenis V. Lunev { 278e9e0bb2aSDenis V. Lunev char *trace_file; 279e9e0bb2aSDenis V. Lunev QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("trace"), 280e9e0bb2aSDenis V. Lunev optarg, true); 281e9e0bb2aSDenis V. Lunev if (!opts) { 282e9e0bb2aSDenis V. Lunev exit(1); 283e9e0bb2aSDenis V. Lunev } 284e9e0bb2aSDenis V. Lunev if (qemu_opt_get(opts, "enable")) { 285e9e0bb2aSDenis V. Lunev trace_enable_events(qemu_opt_get(opts, "enable")); 286e9e0bb2aSDenis V. Lunev } 287e9e0bb2aSDenis V. Lunev trace_init_events(qemu_opt_get(opts, "events")); 288e9e0bb2aSDenis V. Lunev trace_file = g_strdup(qemu_opt_get(opts, "file")); 289e9e0bb2aSDenis V. Lunev qemu_opts_del(opts); 290e9e0bb2aSDenis V. Lunev 291e9e0bb2aSDenis V. Lunev return trace_file; 292e9e0bb2aSDenis V. Lunev } 293