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" 29*0ab8ed18SDaniel P. Berrange #include "trace-root.h" 3023d15e86SLluís 3143b48cfcSPaolo Bonzini int trace_events_enabled_count; 3243b48cfcSPaolo Bonzini 33fe4db84dSDaniel P. Berrange typedef struct TraceEventGroup { 34fe4db84dSDaniel P. Berrange TraceEvent **events; 35fe4db84dSDaniel P. Berrange } TraceEventGroup; 36fe4db84dSDaniel P. Berrange 37fe4db84dSDaniel P. Berrange static TraceEventGroup *event_groups; 38fe4db84dSDaniel P. Berrange static size_t nevent_groups; 39ca3fa0e8SDaniel P. Berrange static uint32_t next_id; 40ca3fa0e8SDaniel P. Berrange static uint32_t next_vcpu_id; 41fe4db84dSDaniel P. Berrange 42e9e0bb2aSDenis V. Lunev QemuOptsList qemu_trace_opts = { 43e9e0bb2aSDenis V. Lunev .name = "trace", 44e9e0bb2aSDenis V. Lunev .implied_opt_name = "enable", 45e9e0bb2aSDenis V. Lunev .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head), 46e9e0bb2aSDenis V. Lunev .desc = { 47e9e0bb2aSDenis V. Lunev { 48e9e0bb2aSDenis V. Lunev .name = "enable", 49e9e0bb2aSDenis V. Lunev .type = QEMU_OPT_STRING, 50e9e0bb2aSDenis V. Lunev }, 51e9e0bb2aSDenis V. Lunev { 52e9e0bb2aSDenis V. Lunev .name = "events", 53e9e0bb2aSDenis V. Lunev .type = QEMU_OPT_STRING, 54e9e0bb2aSDenis V. Lunev },{ 55e9e0bb2aSDenis V. Lunev .name = "file", 56e9e0bb2aSDenis V. Lunev .type = QEMU_OPT_STRING, 57e9e0bb2aSDenis V. Lunev }, 58e9e0bb2aSDenis V. Lunev { /* end of list */ } 59e9e0bb2aSDenis V. Lunev }, 60e9e0bb2aSDenis V. Lunev }; 61e9e0bb2aSDenis V. Lunev 62e9e0bb2aSDenis V. Lunev 63fe4db84dSDaniel P. Berrange void trace_event_register_group(TraceEvent **events) 64fe4db84dSDaniel P. Berrange { 65ca3fa0e8SDaniel P. Berrange size_t i; 66ca3fa0e8SDaniel P. Berrange for (i = 0; events[i] != NULL; i++) { 67ca3fa0e8SDaniel P. Berrange events[i]->id = next_id++; 68ca3fa0e8SDaniel P. Berrange if (events[i]->vcpu_id != TRACE_VCPU_EVENT_NONE) { 69ca3fa0e8SDaniel P. Berrange events[i]->vcpu_id = next_vcpu_id++; 70ca3fa0e8SDaniel P. Berrange } 71ca3fa0e8SDaniel P. Berrange } 72fe4db84dSDaniel P. Berrange event_groups = g_renew(TraceEventGroup, event_groups, nevent_groups + 1); 73fe4db84dSDaniel P. Berrange event_groups[nevent_groups].events = events; 74fe4db84dSDaniel P. Berrange nevent_groups++; 75fe4db84dSDaniel P. Berrange } 76fe4db84dSDaniel P. Berrange 77fe4db84dSDaniel P. Berrange 78b1bae816SLluís Vilanova TraceEvent *trace_event_name(const char *name) 79b1bae816SLluís Vilanova { 80b1bae816SLluís Vilanova assert(name != NULL); 81b1bae816SLluís Vilanova 820d4e995cSDaniel P. Berrange TraceEventIter iter; 830d4e995cSDaniel P. Berrange TraceEvent *ev; 840d4e995cSDaniel P. Berrange trace_event_iter_init(&iter, NULL); 850d4e995cSDaniel P. Berrange while ((ev = trace_event_iter_next(&iter)) != NULL) { 86b1bae816SLluís Vilanova if (strcmp(trace_event_get_name(ev), name) == 0) { 87b1bae816SLluís Vilanova return ev; 88b1bae816SLluís Vilanova } 89b1bae816SLluís Vilanova } 90b1bae816SLluís Vilanova return NULL; 91b1bae816SLluís Vilanova } 92b1bae816SLluís Vilanova 93b1bae816SLluís Vilanova static bool pattern_glob(const char *pat, const char *ev) 94b1bae816SLluís Vilanova { 95b1bae816SLluís Vilanova while (*pat != '\0' && *ev != '\0') { 96b1bae816SLluís Vilanova if (*pat == *ev) { 97b1bae816SLluís Vilanova pat++; 98b1bae816SLluís Vilanova ev++; 99b1bae816SLluís Vilanova } 100b1bae816SLluís Vilanova else if (*pat == '*') { 101b1bae816SLluís Vilanova if (pattern_glob(pat, ev+1)) { 102b1bae816SLluís Vilanova return true; 103b1bae816SLluís Vilanova } else if (pattern_glob(pat+1, ev)) { 104b1bae816SLluís Vilanova return true; 105b1bae816SLluís Vilanova } else { 106b1bae816SLluís Vilanova return false; 107b1bae816SLluís Vilanova } 108b1bae816SLluís Vilanova } else { 109b1bae816SLluís Vilanova return false; 110b1bae816SLluís Vilanova } 111b1bae816SLluís Vilanova } 112b1bae816SLluís Vilanova 113b1bae816SLluís Vilanova while (*pat == '*') { 114b1bae816SLluís Vilanova pat++; 115b1bae816SLluís Vilanova } 116b1bae816SLluís Vilanova 117b1bae816SLluís Vilanova if (*pat == '\0' && *ev == '\0') { 118b1bae816SLluís Vilanova return true; 119b1bae816SLluís Vilanova } else { 120b1bae816SLluís Vilanova return false; 121b1bae816SLluís Vilanova } 122b1bae816SLluís Vilanova } 123b1bae816SLluís Vilanova 124b1bae816SLluís Vilanova 1256a1b0f3aSDaniel P. Berrange void trace_event_iter_init(TraceEventIter *iter, const char *pattern) 1266a1b0f3aSDaniel P. Berrange { 1276a1b0f3aSDaniel P. Berrange iter->event = 0; 128fe4db84dSDaniel P. Berrange iter->group = 0; 1296a1b0f3aSDaniel P. Berrange iter->pattern = pattern; 1306a1b0f3aSDaniel P. Berrange } 1316a1b0f3aSDaniel P. Berrange 1326a1b0f3aSDaniel P. Berrange TraceEvent *trace_event_iter_next(TraceEventIter *iter) 1336a1b0f3aSDaniel P. Berrange { 134fe4db84dSDaniel P. Berrange while (iter->group < nevent_groups && 135fe4db84dSDaniel P. Berrange event_groups[iter->group].events[iter->event] != NULL) { 136fe4db84dSDaniel P. Berrange TraceEvent *ev = event_groups[iter->group].events[iter->event]; 1376a1b0f3aSDaniel P. Berrange iter->event++; 138fe4db84dSDaniel P. Berrange if (event_groups[iter->group].events[iter->event] == NULL) { 139fe4db84dSDaniel P. Berrange iter->event = 0; 140fe4db84dSDaniel P. Berrange iter->group++; 141fe4db84dSDaniel P. Berrange } 1426a1b0f3aSDaniel P. Berrange if (!iter->pattern || 1436a1b0f3aSDaniel P. Berrange pattern_glob(iter->pattern, 1446a1b0f3aSDaniel P. Berrange trace_event_get_name(ev))) { 1456a1b0f3aSDaniel P. Berrange return ev; 1466a1b0f3aSDaniel P. Berrange } 1476a1b0f3aSDaniel P. Berrange } 1486a1b0f3aSDaniel P. Berrange 1496a1b0f3aSDaniel P. Berrange return NULL; 1506a1b0f3aSDaniel P. Berrange } 1516a1b0f3aSDaniel P. Berrange 152e9527dd3SPaolo Bonzini void trace_list_events(void) 153e9527dd3SPaolo Bonzini { 1540d4e995cSDaniel P. Berrange TraceEventIter iter; 1550d4e995cSDaniel P. Berrange TraceEvent *ev; 1560d4e995cSDaniel P. Berrange trace_event_iter_init(&iter, NULL); 1570d4e995cSDaniel P. Berrange while ((ev = trace_event_iter_next(&iter)) != NULL) { 1580d4e995cSDaniel P. Berrange fprintf(stderr, "%s\n", trace_event_get_name(ev)); 159e9527dd3SPaolo Bonzini } 160e9527dd3SPaolo Bonzini } 161e9527dd3SPaolo Bonzini 162e9527dd3SPaolo Bonzini static void do_trace_enable_events(const char *line_buf) 16310578a25SPaolo Bonzini { 16410578a25SPaolo Bonzini const bool enable = ('-' != line_buf[0]); 16510578a25SPaolo Bonzini const char *line_ptr = enable ? line_buf : line_buf + 1; 1660d4e995cSDaniel P. Berrange TraceEventIter iter; 1670d4e995cSDaniel P. Berrange TraceEvent *ev; 1680d4e995cSDaniel P. Berrange bool is_pattern = trace_event_is_pattern(line_ptr); 16910578a25SPaolo Bonzini 1700d4e995cSDaniel P. Berrange trace_event_iter_init(&iter, line_ptr); 1710d4e995cSDaniel P. Berrange while ((ev = trace_event_iter_next(&iter)) != NULL) { 1720d4e995cSDaniel P. Berrange if (!trace_event_get_state_static(ev)) { 1730d4e995cSDaniel P. Berrange if (!is_pattern) { 17410578a25SPaolo Bonzini error_report("WARNING: trace event '%s' is not traceable", 17510578a25SPaolo Bonzini line_ptr); 1760d4e995cSDaniel P. Berrange return; 17710578a25SPaolo Bonzini } 1780d4e995cSDaniel P. Berrange continue; 1790d4e995cSDaniel P. Berrange } 1800d4e995cSDaniel P. Berrange 1810d4e995cSDaniel P. Berrange /* start tracing */ 1820d4e995cSDaniel P. Berrange trace_event_set_state_dynamic(ev, enable); 1830d4e995cSDaniel P. Berrange if (!is_pattern) { 1840d4e995cSDaniel P. Berrange return; 1850d4e995cSDaniel P. Berrange } 1860d4e995cSDaniel P. Berrange } 1870d4e995cSDaniel P. Berrange 1880d4e995cSDaniel P. Berrange if (!is_pattern) { 1890d4e995cSDaniel P. Berrange error_report("WARNING: trace event '%s' does not exist", 1900d4e995cSDaniel P. Berrange line_ptr); 19110578a25SPaolo Bonzini } 19210578a25SPaolo Bonzini } 19310578a25SPaolo Bonzini 194e9527dd3SPaolo Bonzini void trace_enable_events(const char *line_buf) 195e9527dd3SPaolo Bonzini { 196e9527dd3SPaolo Bonzini if (is_help_option(line_buf)) { 197e9527dd3SPaolo Bonzini trace_list_events(); 198acc6809dSDenis V. Lunev if (cur_mon == NULL) { 199e9527dd3SPaolo Bonzini exit(0); 200acc6809dSDenis V. Lunev } 201e9527dd3SPaolo Bonzini } else { 202e9527dd3SPaolo Bonzini do_trace_enable_events(line_buf); 203e9527dd3SPaolo Bonzini } 204e9527dd3SPaolo Bonzini } 205e9527dd3SPaolo Bonzini 206e9e0bb2aSDenis V. Lunev static void trace_init_events(const char *fname) 20723d15e86SLluís { 208a35d9be6SAlexey Kardashevskiy Location loc; 209a35d9be6SAlexey Kardashevskiy FILE *fp; 210a35d9be6SAlexey Kardashevskiy char line_buf[1024]; 211a35d9be6SAlexey Kardashevskiy size_t line_idx = 0; 212a35d9be6SAlexey Kardashevskiy 21323d15e86SLluís if (fname == NULL) { 21423d15e86SLluís return; 21523d15e86SLluís } 21623d15e86SLluís 217a35d9be6SAlexey Kardashevskiy loc_push_none(&loc); 218a35d9be6SAlexey Kardashevskiy loc_set_file(fname, 0); 219a35d9be6SAlexey Kardashevskiy fp = fopen(fname, "r"); 22023d15e86SLluís if (!fp) { 221a35d9be6SAlexey Kardashevskiy error_report("%s", strerror(errno)); 22223d15e86SLluís exit(1); 22323d15e86SLluís } 22423d15e86SLluís while (fgets(line_buf, sizeof(line_buf), fp)) { 225a35d9be6SAlexey Kardashevskiy loc_set_file(fname, ++line_idx); 22623d15e86SLluís size_t len = strlen(line_buf); 22723d15e86SLluís if (len > 1) { /* skip empty lines */ 22823d15e86SLluís line_buf[len - 1] = '\0'; 229794b1f96SAlexey Kardashevskiy if ('#' == line_buf[0]) { /* skip commented lines */ 230794b1f96SAlexey Kardashevskiy continue; 231794b1f96SAlexey Kardashevskiy } 23210578a25SPaolo Bonzini trace_enable_events(line_buf); 23323d15e86SLluís } 23482432638SAlexey Kardashevskiy } 23523d15e86SLluís if (fclose(fp) != 0) { 236a35d9be6SAlexey Kardashevskiy loc_set_file(fname, 0); 237a35d9be6SAlexey Kardashevskiy error_report("%s", strerror(errno)); 23823d15e86SLluís exit(1); 23923d15e86SLluís } 240a35d9be6SAlexey Kardashevskiy loc_pop(&loc); 24123d15e86SLluís } 2425b808275SLluís Vilanova 24341fc57e4SPaolo Bonzini void trace_init_file(const char *file) 2445b808275SLluís Vilanova { 2455b808275SLluís Vilanova #ifdef CONFIG_TRACE_SIMPLE 24641fc57e4SPaolo Bonzini st_set_trace_file(file); 247ed7f5f1dSPaolo Bonzini #elif defined CONFIG_TRACE_LOG 248ed7f5f1dSPaolo Bonzini /* If both the simple and the log backends are enabled, "-trace file" 249ed7f5f1dSPaolo Bonzini * only applies to the simple backend; use "-D" for the log backend. 250ed7f5f1dSPaolo Bonzini */ 251ed7f5f1dSPaolo Bonzini if (file) { 252daa76aa4SMarkus Armbruster qemu_set_log_filename(file, &error_fatal); 253ed7f5f1dSPaolo Bonzini } 2545b808275SLluís Vilanova #else 2555b808275SLluís Vilanova if (file) { 2565b808275SLluís Vilanova fprintf(stderr, "error: -trace file=...: " 2575b808275SLluís Vilanova "option not supported by the selected tracing backends\n"); 25841fc57e4SPaolo Bonzini exit(1); 25941fc57e4SPaolo Bonzini } 26041fc57e4SPaolo Bonzini #endif 26141fc57e4SPaolo Bonzini } 26241fc57e4SPaolo Bonzini 26382e95ec8SLluís Vilanova void trace_fini_vcpu(CPUState *vcpu) 26482e95ec8SLluís Vilanova { 26582e95ec8SLluís Vilanova TraceEventIter iter; 26682e95ec8SLluís Vilanova TraceEvent *ev; 26782e95ec8SLluís Vilanova 268a47e8715SLluís Vilanova trace_guest_cpu_exit(vcpu); 269a47e8715SLluís Vilanova 27082e95ec8SLluís Vilanova trace_event_iter_init(&iter, NULL); 27182e95ec8SLluís Vilanova while ((ev = trace_event_iter_next(&iter)) != NULL) { 27282e95ec8SLluís Vilanova if (trace_event_is_vcpu(ev) && 27382e95ec8SLluís Vilanova trace_event_get_state_static(ev) && 27482e95ec8SLluís Vilanova trace_event_get_vcpu_state_dynamic(vcpu, ev)) { 27582e95ec8SLluís Vilanova /* must disable to affect the global counter */ 27682e95ec8SLluís Vilanova trace_event_set_vcpu_state_dynamic(vcpu, ev, false); 27782e95ec8SLluís Vilanova } 27882e95ec8SLluís Vilanova } 27982e95ec8SLluís Vilanova } 28082e95ec8SLluís Vilanova 28141fc57e4SPaolo Bonzini bool trace_init_backends(void) 28241fc57e4SPaolo Bonzini { 28341fc57e4SPaolo Bonzini #ifdef CONFIG_TRACE_SIMPLE 28441fc57e4SPaolo Bonzini if (!st_init()) { 28541fc57e4SPaolo Bonzini fprintf(stderr, "failed to initialize simple tracing backend.\n"); 2865b808275SLluís Vilanova return false; 2875b808275SLluís Vilanova } 2885b808275SLluís Vilanova #endif 2895b808275SLluís Vilanova 2905b808275SLluís Vilanova #ifdef CONFIG_TRACE_FTRACE 2915b808275SLluís Vilanova if (!ftrace_init()) { 2925b808275SLluís Vilanova fprintf(stderr, "failed to initialize ftrace backend.\n"); 2935b808275SLluís Vilanova return false; 2945b808275SLluís Vilanova } 2955b808275SLluís Vilanova #endif 2965b808275SLluís Vilanova 2970a852417SPaul Durrant #ifdef CONFIG_TRACE_SYSLOG 2980a852417SPaul Durrant openlog(NULL, LOG_PID, LOG_DAEMON); 2990a852417SPaul Durrant #endif 3000a852417SPaul Durrant 3015b808275SLluís Vilanova return true; 3025b808275SLluís Vilanova } 303e9e0bb2aSDenis V. Lunev 304e9e0bb2aSDenis V. Lunev char *trace_opt_parse(const char *optarg) 305e9e0bb2aSDenis V. Lunev { 306e9e0bb2aSDenis V. Lunev char *trace_file; 307e9e0bb2aSDenis V. Lunev QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("trace"), 308e9e0bb2aSDenis V. Lunev optarg, true); 309e9e0bb2aSDenis V. Lunev if (!opts) { 310e9e0bb2aSDenis V. Lunev exit(1); 311e9e0bb2aSDenis V. Lunev } 312e9e0bb2aSDenis V. Lunev if (qemu_opt_get(opts, "enable")) { 313e9e0bb2aSDenis V. Lunev trace_enable_events(qemu_opt_get(opts, "enable")); 314e9e0bb2aSDenis V. Lunev } 315e9e0bb2aSDenis V. Lunev trace_init_events(qemu_opt_get(opts, "events")); 316e9e0bb2aSDenis V. Lunev trace_file = g_strdup(qemu_opt_get(opts, "file")); 317e9e0bb2aSDenis V. Lunev qemu_opts_del(opts); 318e9e0bb2aSDenis V. Lunev 319e9e0bb2aSDenis V. Lunev return trace_file; 320e9e0bb2aSDenis V. Lunev } 321b7d48952SDaniel P. Berrange 322b7d48952SDaniel P. Berrange uint32_t trace_get_vcpu_event_count(void) 323b7d48952SDaniel P. Berrange { 324ca3fa0e8SDaniel P. Berrange return next_vcpu_id; 325b7d48952SDaniel P. Berrange } 326