qemu/trace/control.c
<<
>>
Prefs
   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 "qemu/osdep.h"
  11#include "trace/control.h"
  12#include "qemu/help_option.h"
  13#ifdef CONFIG_TRACE_SIMPLE
  14#include "trace/simple.h"
  15#endif
  16#ifdef CONFIG_TRACE_FTRACE
  17#include "trace/ftrace.h"
  18#endif
  19#ifdef CONFIG_TRACE_LOG
  20#include "qemu/log.h"
  21#endif
  22#include "qemu/error-report.h"
  23#include "monitor/monitor.h"
  24
  25int trace_events_enabled_count;
  26bool trace_events_dstate[TRACE_EVENT_COUNT];
  27
  28TraceEvent *trace_event_name(const char *name)
  29{
  30    assert(name != NULL);
  31
  32    TraceEventID i;
  33    for (i = 0; i < trace_event_count(); i++) {
  34        TraceEvent *ev = trace_event_id(i);
  35        if (strcmp(trace_event_get_name(ev), name) == 0) {
  36            return ev;
  37        }
  38    }
  39    return NULL;
  40}
  41
  42static bool pattern_glob(const char *pat, const char *ev)
  43{
  44    while (*pat != '\0' && *ev != '\0') {
  45        if (*pat == *ev) {
  46            pat++;
  47            ev++;
  48        }
  49        else if (*pat == '*') {
  50            if (pattern_glob(pat, ev+1)) {
  51                return true;
  52            } else if (pattern_glob(pat+1, ev)) {
  53                return true;
  54            } else {
  55                return false;
  56            }
  57        } else {
  58            return false;
  59        }
  60    }
  61
  62    while (*pat == '*') {
  63        pat++;
  64    }
  65
  66    if (*pat == '\0' && *ev == '\0') {
  67        return true;
  68    } else {
  69        return false;
  70    }
  71}
  72
  73TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev)
  74{
  75    assert(pat != NULL);
  76
  77    TraceEventID i;
  78
  79    if (ev == NULL) {
  80        i = -1;
  81    } else {
  82        i = trace_event_get_id(ev);
  83    }
  84    i++;
  85
  86    while (i < trace_event_count()) {
  87        TraceEvent *res = trace_event_id(i);
  88        if (pattern_glob(pat, trace_event_get_name(res))) {
  89            return res;
  90        }
  91        i++;
  92    }
  93
  94    return NULL;
  95}
  96
  97void trace_list_events(void)
  98{
  99    int i;
 100    for (i = 0; i < trace_event_count(); i++) {
 101        TraceEvent *res = trace_event_id(i);
 102        fprintf(stderr, "%s\n", trace_event_get_name(res));
 103    }
 104}
 105
 106static void do_trace_enable_events(const char *line_buf)
 107{
 108    const bool enable = ('-' != line_buf[0]);
 109    const char *line_ptr = enable ? line_buf : line_buf + 1;
 110
 111    if (trace_event_is_pattern(line_ptr)) {
 112        TraceEvent *ev = NULL;
 113        while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) {
 114            if (trace_event_get_state_static(ev)) {
 115                trace_event_set_state_dynamic(ev, enable);
 116            }
 117        }
 118    } else {
 119        TraceEvent *ev = trace_event_name(line_ptr);
 120        if (ev == NULL) {
 121            error_report("WARNING: trace event '%s' does not exist",
 122                         line_ptr);
 123        } else if (!trace_event_get_state_static(ev)) {
 124            error_report("WARNING: trace event '%s' is not traceable",
 125                         line_ptr);
 126        } else {
 127            trace_event_set_state_dynamic(ev, enable);
 128        }
 129    }
 130}
 131
 132void trace_enable_events(const char *line_buf)
 133{
 134    if (is_help_option(line_buf)) {
 135        trace_list_events();
 136        if (cur_mon == NULL) {
 137            exit(0);
 138        }
 139    } else {
 140        do_trace_enable_events(line_buf);
 141    }
 142}
 143
 144void trace_init_events(const char *fname)
 145{
 146    Location loc;
 147    FILE *fp;
 148    char line_buf[1024];
 149    size_t line_idx = 0;
 150
 151    if (fname == NULL) {
 152        return;
 153    }
 154
 155    loc_push_none(&loc);
 156    loc_set_file(fname, 0);
 157    fp = fopen(fname, "r");
 158    if (!fp) {
 159        error_report("%s", strerror(errno));
 160        exit(1);
 161    }
 162    while (fgets(line_buf, sizeof(line_buf), fp)) {
 163        loc_set_file(fname, ++line_idx);
 164        size_t len = strlen(line_buf);
 165        if (len > 1) {              /* skip empty lines */
 166            line_buf[len - 1] = '\0';
 167            if ('#' == line_buf[0]) { /* skip commented lines */
 168                continue;
 169            }
 170            trace_enable_events(line_buf);
 171        }
 172    }
 173    if (fclose(fp) != 0) {
 174        loc_set_file(fname, 0);
 175        error_report("%s", strerror(errno));
 176        exit(1);
 177    }
 178    loc_pop(&loc);
 179}
 180
 181void trace_init_file(const char *file)
 182{
 183#ifdef CONFIG_TRACE_SIMPLE
 184    st_set_trace_file(file);
 185#elif defined CONFIG_TRACE_LOG
 186    /* If both the simple and the log backends are enabled, "-trace file"
 187     * only applies to the simple backend; use "-D" for the log backend.
 188     */
 189    if (file) {
 190        qemu_set_log_filename(file);
 191    }
 192#else
 193    if (file) {
 194        fprintf(stderr, "error: -trace file=...: "
 195                "option not supported by the selected tracing backends\n");
 196        exit(1);
 197    }
 198#endif
 199}
 200
 201bool trace_init_backends(void)
 202{
 203#ifdef CONFIG_TRACE_SIMPLE
 204    if (!st_init()) {
 205        fprintf(stderr, "failed to initialize simple tracing backend.\n");
 206        return false;
 207    }
 208#endif
 209
 210#ifdef CONFIG_TRACE_FTRACE
 211    if (!ftrace_init()) {
 212        fprintf(stderr, "failed to initialize ftrace backend.\n");
 213        return false;
 214    }
 215#endif
 216
 217    return true;
 218}
 219