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" 13922a01a0SMarkus Armbruster #include "qemu/option.h" 145b808275SLluís Vilanova #ifdef CONFIG_TRACE_SIMPLE 155b808275SLluís Vilanova #include "trace/simple.h" 165b808275SLluís Vilanova #endif 175b808275SLluís Vilanova #ifdef CONFIG_TRACE_FTRACE 185b808275SLluís Vilanova #include "trace/ftrace.h" 195b808275SLluís Vilanova #endif 20ed7f5f1dSPaolo Bonzini #ifdef CONFIG_TRACE_LOG 21ed7f5f1dSPaolo Bonzini #include "qemu/log.h" 22ed7f5f1dSPaolo Bonzini #endif 230a852417SPaul Durrant #ifdef CONFIG_TRACE_SYSLOG 240a852417SPaul Durrant #include <syslog.h> 250a852417SPaul Durrant #endif 26daa76aa4SMarkus Armbruster #include "qapi/error.h" 27a35d9be6SAlexey Kardashevskiy #include "qemu/error-report.h" 28e9e0bb2aSDenis V. Lunev #include "qemu/config-file.h" 29acc6809dSDenis V. Lunev #include "monitor/monitor.h" 30243af022SPaolo Bonzini #include "trace/trace-root.h" 3123d15e86SLluís 3243b48cfcSPaolo Bonzini int trace_events_enabled_count; 3343b48cfcSPaolo Bonzini 34fe4db84dSDaniel P. Berrange typedef struct TraceEventGroup { 35fe4db84dSDaniel P. Berrange TraceEvent **events; 36fe4db84dSDaniel P. Berrange } TraceEventGroup; 37fe4db84dSDaniel P. Berrange 38fe4db84dSDaniel P. Berrange static TraceEventGroup *event_groups; 39fe4db84dSDaniel P. Berrange static size_t nevent_groups; 40ca3fa0e8SDaniel P. Berrange static uint32_t next_id; 41ca3fa0e8SDaniel P. Berrange static uint32_t next_vcpu_id; 42648b4823SJosh DuBois static bool init_trace_on_startup; 439f45a641SPaolo Bonzini static char *trace_opts_file; 44fe4db84dSDaniel P. Berrange 45e9e0bb2aSDenis V. Lunev QemuOptsList qemu_trace_opts = { 46e9e0bb2aSDenis V. Lunev .name = "trace", 47e9e0bb2aSDenis V. Lunev .implied_opt_name = "enable", 48e9e0bb2aSDenis V. Lunev .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head), 49e9e0bb2aSDenis V. Lunev .desc = { 50e9e0bb2aSDenis V. Lunev { 51e9e0bb2aSDenis V. Lunev .name = "enable", 52e9e0bb2aSDenis V. Lunev .type = QEMU_OPT_STRING, 53e9e0bb2aSDenis V. Lunev }, 54e9e0bb2aSDenis V. Lunev { 55e9e0bb2aSDenis V. Lunev .name = "events", 56e9e0bb2aSDenis V. Lunev .type = QEMU_OPT_STRING, 57e9e0bb2aSDenis V. Lunev },{ 58e9e0bb2aSDenis V. Lunev .name = "file", 59e9e0bb2aSDenis V. Lunev .type = QEMU_OPT_STRING, 60e9e0bb2aSDenis V. Lunev }, 61e9e0bb2aSDenis V. Lunev { /* end of list */ } 62e9e0bb2aSDenis V. Lunev }, 63e9e0bb2aSDenis V. Lunev }; 64e9e0bb2aSDenis V. Lunev 65e9e0bb2aSDenis V. Lunev 66fe4db84dSDaniel P. Berrange void trace_event_register_group(TraceEvent **events) 67fe4db84dSDaniel P. Berrange { 68ca3fa0e8SDaniel P. Berrange size_t i; 69ca3fa0e8SDaniel P. Berrange for (i = 0; events[i] != NULL; i++) { 70ca3fa0e8SDaniel P. Berrange events[i]->id = next_id++; 71d01c05c9SLluís Vilanova if (events[i]->vcpu_id == TRACE_VCPU_EVENT_NONE) { 72d01c05c9SLluís Vilanova continue; 73d01c05c9SLluís Vilanova } 74d01c05c9SLluís Vilanova 75d01c05c9SLluís Vilanova if (likely(next_vcpu_id < CPU_TRACE_DSTATE_MAX_EVENTS)) { 76ca3fa0e8SDaniel P. Berrange events[i]->vcpu_id = next_vcpu_id++; 77d01c05c9SLluís Vilanova } else { 7855d527a9SAlistair Francis warn_report("too many vcpu trace events; dropping '%s'", 79d01c05c9SLluís Vilanova events[i]->name); 80ca3fa0e8SDaniel P. Berrange } 81ca3fa0e8SDaniel P. Berrange } 82fe4db84dSDaniel P. Berrange event_groups = g_renew(TraceEventGroup, event_groups, nevent_groups + 1); 83fe4db84dSDaniel P. Berrange event_groups[nevent_groups].events = events; 84fe4db84dSDaniel P. Berrange nevent_groups++; 85fe4db84dSDaniel P. Berrange } 86fe4db84dSDaniel P. Berrange 87fe4db84dSDaniel P. Berrange 88b1bae816SLluís Vilanova TraceEvent *trace_event_name(const char *name) 89b1bae816SLluís Vilanova { 90b1bae816SLluís Vilanova assert(name != NULL); 91b1bae816SLluís Vilanova 920d4e995cSDaniel P. Berrange TraceEventIter iter; 930d4e995cSDaniel P. Berrange TraceEvent *ev; 94*117856c3SGerd Hoffmann trace_event_iter_init_all(&iter); 950d4e995cSDaniel P. Berrange while ((ev = trace_event_iter_next(&iter)) != NULL) { 96b1bae816SLluís Vilanova if (strcmp(trace_event_get_name(ev), name) == 0) { 97b1bae816SLluís Vilanova return ev; 98b1bae816SLluís Vilanova } 99b1bae816SLluís Vilanova } 100b1bae816SLluís Vilanova return NULL; 101b1bae816SLluís Vilanova } 102b1bae816SLluís Vilanova 103*117856c3SGerd Hoffmann void trace_event_iter_init_all(TraceEventIter *iter) 1046a1b0f3aSDaniel P. Berrange { 1056a1b0f3aSDaniel P. Berrange iter->event = 0; 106fe4db84dSDaniel P. Berrange iter->group = 0; 107*117856c3SGerd Hoffmann iter->pattern = NULL; 108*117856c3SGerd Hoffmann } 109*117856c3SGerd Hoffmann 110*117856c3SGerd Hoffmann void trace_event_iter_init_pattern(TraceEventIter *iter, const char *pattern) 111*117856c3SGerd Hoffmann { 112*117856c3SGerd Hoffmann trace_event_iter_init_all(iter); 1136a1b0f3aSDaniel P. Berrange iter->pattern = pattern; 1146a1b0f3aSDaniel P. Berrange } 1156a1b0f3aSDaniel P. Berrange 1166a1b0f3aSDaniel P. Berrange TraceEvent *trace_event_iter_next(TraceEventIter *iter) 1176a1b0f3aSDaniel P. Berrange { 118fe4db84dSDaniel P. Berrange while (iter->group < nevent_groups && 119fe4db84dSDaniel P. Berrange event_groups[iter->group].events[iter->event] != NULL) { 120fe4db84dSDaniel P. Berrange TraceEvent *ev = event_groups[iter->group].events[iter->event]; 1216a1b0f3aSDaniel P. Berrange iter->event++; 122fe4db84dSDaniel P. Berrange if (event_groups[iter->group].events[iter->event] == NULL) { 123fe4db84dSDaniel P. Berrange iter->event = 0; 124fe4db84dSDaniel P. Berrange iter->group++; 125fe4db84dSDaniel P. Berrange } 1266a1b0f3aSDaniel P. Berrange if (!iter->pattern || 127e66eae7aSAlex Bennée g_pattern_match_simple(iter->pattern, trace_event_get_name(ev))) { 1286a1b0f3aSDaniel P. Berrange return ev; 1296a1b0f3aSDaniel P. Berrange } 1306a1b0f3aSDaniel P. Berrange } 1316a1b0f3aSDaniel P. Berrange 1326a1b0f3aSDaniel P. Berrange return NULL; 1336a1b0f3aSDaniel P. Berrange } 1346a1b0f3aSDaniel P. Berrange 1356745c8a0SDoug Evans void trace_list_events(FILE *f) 136e9527dd3SPaolo Bonzini { 1370d4e995cSDaniel P. Berrange TraceEventIter iter; 1380d4e995cSDaniel P. Berrange TraceEvent *ev; 139*117856c3SGerd Hoffmann trace_event_iter_init_all(&iter); 1400d4e995cSDaniel P. Berrange while ((ev = trace_event_iter_next(&iter)) != NULL) { 1416745c8a0SDoug Evans fprintf(f, "%s\n", trace_event_get_name(ev)); 142e9527dd3SPaolo Bonzini } 1439f591a5dSPhilippe Mathieu-Daudé #ifdef CONFIG_TRACE_DTRACE 1446745c8a0SDoug Evans fprintf(f, "This list of names of trace points may be incomplete " 1459f591a5dSPhilippe Mathieu-Daudé "when using the DTrace/SystemTap backends.\n" 1469f591a5dSPhilippe Mathieu-Daudé "Run 'qemu-trace-stap list %s' to print the full list.\n", 1479f591a5dSPhilippe Mathieu-Daudé error_get_progname()); 1489f591a5dSPhilippe Mathieu-Daudé #endif 149e9527dd3SPaolo Bonzini } 150e9527dd3SPaolo Bonzini 151e9527dd3SPaolo Bonzini static void do_trace_enable_events(const char *line_buf) 15210578a25SPaolo Bonzini { 15310578a25SPaolo Bonzini const bool enable = ('-' != line_buf[0]); 15410578a25SPaolo Bonzini const char *line_ptr = enable ? line_buf : line_buf + 1; 1550d4e995cSDaniel P. Berrange TraceEventIter iter; 1560d4e995cSDaniel P. Berrange TraceEvent *ev; 1570d4e995cSDaniel P. Berrange bool is_pattern = trace_event_is_pattern(line_ptr); 15810578a25SPaolo Bonzini 159*117856c3SGerd Hoffmann trace_event_iter_init_pattern(&iter, line_ptr); 1600d4e995cSDaniel P. Berrange while ((ev = trace_event_iter_next(&iter)) != NULL) { 1610d4e995cSDaniel P. Berrange if (!trace_event_get_state_static(ev)) { 1620d4e995cSDaniel P. Berrange if (!is_pattern) { 1633dc6f869SAlistair Francis warn_report("trace event '%s' is not traceable", 16410578a25SPaolo Bonzini line_ptr); 1650d4e995cSDaniel P. Berrange return; 16610578a25SPaolo Bonzini } 1670d4e995cSDaniel P. Berrange continue; 1680d4e995cSDaniel P. Berrange } 1690d4e995cSDaniel P. Berrange 1700d4e995cSDaniel P. Berrange /* start tracing */ 1710d4e995cSDaniel P. Berrange trace_event_set_state_dynamic(ev, enable); 1720d4e995cSDaniel P. Berrange if (!is_pattern) { 1730d4e995cSDaniel P. Berrange return; 1740d4e995cSDaniel P. Berrange } 1750d4e995cSDaniel P. Berrange } 1760d4e995cSDaniel P. Berrange 1770d4e995cSDaniel P. Berrange if (!is_pattern) { 1783dc6f869SAlistair Francis warn_report("trace event '%s' does not exist", 1790d4e995cSDaniel P. Berrange line_ptr); 18010578a25SPaolo Bonzini } 18110578a25SPaolo Bonzini } 18210578a25SPaolo Bonzini 183e9527dd3SPaolo Bonzini void trace_enable_events(const char *line_buf) 184e9527dd3SPaolo Bonzini { 185e9527dd3SPaolo Bonzini if (is_help_option(line_buf)) { 1866745c8a0SDoug Evans trace_list_events(stdout); 187947e4744SKevin Wolf if (monitor_cur() == NULL) { 188e9527dd3SPaolo Bonzini exit(0); 189acc6809dSDenis V. Lunev } 190e9527dd3SPaolo Bonzini } else { 191e9527dd3SPaolo Bonzini do_trace_enable_events(line_buf); 192e9527dd3SPaolo Bonzini } 193e9527dd3SPaolo Bonzini } 194e9527dd3SPaolo Bonzini 195e9e0bb2aSDenis V. Lunev static void trace_init_events(const char *fname) 19623d15e86SLluís { 197a35d9be6SAlexey Kardashevskiy Location loc; 198a35d9be6SAlexey Kardashevskiy FILE *fp; 199a35d9be6SAlexey Kardashevskiy char line_buf[1024]; 200a35d9be6SAlexey Kardashevskiy size_t line_idx = 0; 201a35d9be6SAlexey Kardashevskiy 20223d15e86SLluís if (fname == NULL) { 20323d15e86SLluís return; 20423d15e86SLluís } 20523d15e86SLluís 206a35d9be6SAlexey Kardashevskiy loc_push_none(&loc); 207a35d9be6SAlexey Kardashevskiy loc_set_file(fname, 0); 208a35d9be6SAlexey Kardashevskiy fp = fopen(fname, "r"); 20923d15e86SLluís if (!fp) { 210a35d9be6SAlexey Kardashevskiy error_report("%s", strerror(errno)); 21123d15e86SLluís exit(1); 21223d15e86SLluís } 21323d15e86SLluís while (fgets(line_buf, sizeof(line_buf), fp)) { 214a35d9be6SAlexey Kardashevskiy loc_set_file(fname, ++line_idx); 21523d15e86SLluís size_t len = strlen(line_buf); 21623d15e86SLluís if (len > 1) { /* skip empty lines */ 21723d15e86SLluís line_buf[len - 1] = '\0'; 218794b1f96SAlexey Kardashevskiy if ('#' == line_buf[0]) { /* skip commented lines */ 219794b1f96SAlexey Kardashevskiy continue; 220794b1f96SAlexey Kardashevskiy } 22110578a25SPaolo Bonzini trace_enable_events(line_buf); 22223d15e86SLluís } 22382432638SAlexey Kardashevskiy } 22423d15e86SLluís if (fclose(fp) != 0) { 225a35d9be6SAlexey Kardashevskiy loc_set_file(fname, 0); 226a35d9be6SAlexey Kardashevskiy error_report("%s", strerror(errno)); 22723d15e86SLluís exit(1); 22823d15e86SLluís } 229a35d9be6SAlexey Kardashevskiy loc_pop(&loc); 23023d15e86SLluís } 2315b808275SLluís Vilanova 23292eecfffSPaolo Bonzini void trace_init_file(void) 2335b808275SLluís Vilanova { 2345b808275SLluís Vilanova #ifdef CONFIG_TRACE_SIMPLE 2359f45a641SPaolo Bonzini st_set_trace_file(trace_opts_file); 236648b4823SJosh DuBois if (init_trace_on_startup) { 2371b7157beSJosh DuBois st_set_trace_file_enabled(true); 238648b4823SJosh DuBois } 239ed7f5f1dSPaolo Bonzini #elif defined CONFIG_TRACE_LOG 2403d88754eSAlex Bennée /* 2413d88754eSAlex Bennée * If both the simple and the log backends are enabled, "--trace file" 2423d88754eSAlex Bennée * only applies to the simple backend; use "-D" for the log 2433d88754eSAlex Bennée * backend. However we should only override -D if we actually have 2443d88754eSAlex Bennée * something to override it with. 245ed7f5f1dSPaolo Bonzini */ 2469f45a641SPaolo Bonzini if (trace_opts_file) { 2479f45a641SPaolo Bonzini qemu_set_log_filename(trace_opts_file, &error_fatal); 2483d88754eSAlex Bennée } 2495b808275SLluís Vilanova #else 2509f45a641SPaolo Bonzini if (trace_opts_file) { 251db817b8cSYaowei Bai fprintf(stderr, "error: --trace file=...: " 2525b808275SLluís Vilanova "option not supported by the selected tracing backends\n"); 25341fc57e4SPaolo Bonzini exit(1); 25441fc57e4SPaolo Bonzini } 25541fc57e4SPaolo Bonzini #endif 25641fc57e4SPaolo Bonzini } 25741fc57e4SPaolo Bonzini 25882e95ec8SLluís Vilanova void trace_fini_vcpu(CPUState *vcpu) 25982e95ec8SLluís Vilanova { 26082e95ec8SLluís Vilanova TraceEventIter iter; 26182e95ec8SLluís Vilanova TraceEvent *ev; 26282e95ec8SLluís Vilanova 263a47e8715SLluís Vilanova trace_guest_cpu_exit(vcpu); 264a47e8715SLluís Vilanova 265*117856c3SGerd Hoffmann trace_event_iter_init_all(&iter); 26682e95ec8SLluís Vilanova while ((ev = trace_event_iter_next(&iter)) != NULL) { 26782e95ec8SLluís Vilanova if (trace_event_is_vcpu(ev) && 26882e95ec8SLluís Vilanova trace_event_get_state_static(ev) && 26982e95ec8SLluís Vilanova trace_event_get_vcpu_state_dynamic(vcpu, ev)) { 27082e95ec8SLluís Vilanova /* must disable to affect the global counter */ 27182e95ec8SLluís Vilanova trace_event_set_vcpu_state_dynamic(vcpu, ev, false); 27282e95ec8SLluís Vilanova } 27382e95ec8SLluís Vilanova } 27482e95ec8SLluís Vilanova } 27582e95ec8SLluís Vilanova 27641fc57e4SPaolo Bonzini bool trace_init_backends(void) 27741fc57e4SPaolo Bonzini { 27841fc57e4SPaolo Bonzini #ifdef CONFIG_TRACE_SIMPLE 27941fc57e4SPaolo Bonzini if (!st_init()) { 28041fc57e4SPaolo Bonzini fprintf(stderr, "failed to initialize simple tracing backend.\n"); 2815b808275SLluís Vilanova return false; 2825b808275SLluís Vilanova } 2835b808275SLluís Vilanova #endif 2845b808275SLluís Vilanova 2855b808275SLluís Vilanova #ifdef CONFIG_TRACE_FTRACE 2865b808275SLluís Vilanova if (!ftrace_init()) { 2875b808275SLluís Vilanova fprintf(stderr, "failed to initialize ftrace backend.\n"); 2885b808275SLluís Vilanova return false; 2895b808275SLluís Vilanova } 2905b808275SLluís Vilanova #endif 2915b808275SLluís Vilanova 2920a852417SPaul Durrant #ifdef CONFIG_TRACE_SYSLOG 2930a852417SPaul Durrant openlog(NULL, LOG_PID, LOG_DAEMON); 2940a852417SPaul Durrant #endif 2950a852417SPaul Durrant 2965b808275SLluís Vilanova return true; 2975b808275SLluís Vilanova } 298e9e0bb2aSDenis V. Lunev 29992eecfffSPaolo Bonzini void trace_opt_parse(const char *optarg) 300e9e0bb2aSDenis V. Lunev { 301e9e0bb2aSDenis V. Lunev QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("trace"), 302e9e0bb2aSDenis V. Lunev optarg, true); 303e9e0bb2aSDenis V. Lunev if (!opts) { 304e9e0bb2aSDenis V. Lunev exit(1); 305e9e0bb2aSDenis V. Lunev } 306e9e0bb2aSDenis V. Lunev if (qemu_opt_get(opts, "enable")) { 307e9e0bb2aSDenis V. Lunev trace_enable_events(qemu_opt_get(opts, "enable")); 308e9e0bb2aSDenis V. Lunev } 309e9e0bb2aSDenis V. Lunev trace_init_events(qemu_opt_get(opts, "events")); 310648b4823SJosh DuBois init_trace_on_startup = true; 3119f45a641SPaolo Bonzini g_free(trace_opts_file); 3129f45a641SPaolo Bonzini trace_opts_file = g_strdup(qemu_opt_get(opts, "file")); 313e9e0bb2aSDenis V. Lunev qemu_opts_del(opts); 314e9e0bb2aSDenis V. Lunev } 315b7d48952SDaniel P. Berrange 316b7d48952SDaniel P. Berrange uint32_t trace_get_vcpu_event_count(void) 317b7d48952SDaniel P. Berrange { 318ca3fa0e8SDaniel P. Berrange return next_vcpu_id; 319b7d48952SDaniel P. Berrange } 320