qemu

Форк
0
/
control.c 
308 строк · 7.6 Кб
1
/*
2
 * Interface for configuring and controlling the state of tracing events.
3
 *
4
 * Copyright (C) 2011-2016 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
#include "qemu/option.h"
14
#ifdef CONFIG_TRACE_SIMPLE
15
#include "trace/simple.h"
16
#endif
17
#ifdef CONFIG_TRACE_FTRACE
18
#include "trace/ftrace.h"
19
#endif
20
#ifdef CONFIG_TRACE_LOG
21
#include "qemu/log.h"
22
#endif
23
#ifdef CONFIG_TRACE_SYSLOG
24
#include <syslog.h>
25
#endif
26
#include "qapi/error.h"
27
#include "qemu/error-report.h"
28
#include "qemu/config-file.h"
29
#include "monitor/monitor.h"
30
#include "trace/trace-root.h"
31

32
int trace_events_enabled_count;
33

34
typedef struct TraceEventGroup {
35
    TraceEvent **events;
36
} TraceEventGroup;
37

38
static TraceEventGroup *event_groups;
39
static size_t nevent_groups;
40
static uint32_t next_id;
41
static uint32_t next_vcpu_id;
42
static bool init_trace_on_startup;
43
static char *trace_opts_file;
44

45
QemuOptsList qemu_trace_opts = {
46
    .name = "trace",
47
    .implied_opt_name = "enable",
48
    .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
49
    .desc = {
50
        {
51
            .name = "enable",
52
            .type = QEMU_OPT_STRING,
53
        },
54
        {
55
            .name = "events",
56
            .type = QEMU_OPT_STRING,
57
        },{
58
            .name = "file",
59
            .type = QEMU_OPT_STRING,
60
        },
61
        { /* end of list */ }
62
    },
63
};
64

65

66
void trace_event_register_group(TraceEvent **events)
67
{
68
    size_t i;
69
    for (i = 0; events[i] != NULL; i++) {
70
        events[i]->id = next_id++;
71
    }
72
    event_groups = g_renew(TraceEventGroup, event_groups, nevent_groups + 1);
73
    event_groups[nevent_groups].events = events;
74
    nevent_groups++;
75

76
#ifdef CONFIG_TRACE_SIMPLE
77
    st_init_group(nevent_groups - 1);
78
#endif
79
}
80

81

82
TraceEvent *trace_event_name(const char *name)
83
{
84
    assert(name != NULL);
85

86
    TraceEventIter iter;
87
    TraceEvent *ev;
88
    trace_event_iter_init_all(&iter);
89
    while ((ev = trace_event_iter_next(&iter)) != NULL) {
90
        if (strcmp(trace_event_get_name(ev), name) == 0) {
91
            return ev;
92
        }
93
    }
94
    return NULL;
95
}
96

97
void trace_event_iter_init_all(TraceEventIter *iter)
98
{
99
    iter->event = 0;
100
    iter->group = 0;
101
    iter->group_id = -1;
102
    iter->pattern = NULL;
103
}
104

105
void trace_event_iter_init_pattern(TraceEventIter *iter, const char *pattern)
106
{
107
    trace_event_iter_init_all(iter);
108
    iter->pattern = pattern;
109
}
110

111
void trace_event_iter_init_group(TraceEventIter *iter, size_t group_id)
112
{
113
    trace_event_iter_init_all(iter);
114
    iter->group_id = group_id;
115
}
116

117
TraceEvent *trace_event_iter_next(TraceEventIter *iter)
118
{
119
    while (iter->group < nevent_groups &&
120
           event_groups[iter->group].events[iter->event] != NULL) {
121
        TraceEvent *ev = event_groups[iter->group].events[iter->event];
122
        size_t group = iter->group;
123
        iter->event++;
124
        if (event_groups[iter->group].events[iter->event] == NULL) {
125
            iter->event = 0;
126
            iter->group++;
127
        }
128
        if (iter->pattern &&
129
            !g_pattern_match_simple(iter->pattern, trace_event_get_name(ev))) {
130
            continue;
131
        }
132
        if (iter->group_id != -1 &&
133
            iter->group_id != group) {
134
            continue;
135
        }
136
        return ev;
137
    }
138

139
    return NULL;
140
}
141

142
void trace_list_events(FILE *f)
143
{
144
    TraceEventIter iter;
145
    TraceEvent *ev;
146
    trace_event_iter_init_all(&iter);
147
    while ((ev = trace_event_iter_next(&iter)) != NULL) {
148
        fprintf(f, "%s\n", trace_event_get_name(ev));
149
    }
150
#ifdef CONFIG_TRACE_DTRACE
151
    fprintf(f, "This list of names of trace points may be incomplete "
152
               "when using the DTrace/SystemTap backends.\n"
153
               "Run 'qemu-trace-stap list %s' to print the full list.\n",
154
            g_get_prgname());
155
#endif
156
}
157

158
static void do_trace_enable_events(const char *line_buf)
159
{
160
    const bool enable = ('-' != line_buf[0]);
161
    const char *line_ptr = enable ? line_buf : line_buf + 1;
162
    TraceEventIter iter;
163
    TraceEvent *ev;
164
    bool is_pattern = trace_event_is_pattern(line_ptr);
165

166
    trace_event_iter_init_pattern(&iter, line_ptr);
167
    while ((ev = trace_event_iter_next(&iter)) != NULL) {
168
        if (!trace_event_get_state_static(ev)) {
169
            if (!is_pattern) {
170
                warn_report("trace event '%s' is not traceable",
171
                            line_ptr);
172
                return;
173
            }
174
            continue;
175
        }
176

177
        /* start tracing */
178
        trace_event_set_state_dynamic(ev, enable);
179
        if (!is_pattern) {
180
            return;
181
        }
182
    }
183

184
    if (!is_pattern) {
185
        warn_report("trace event '%s' does not exist",
186
                    line_ptr);
187
    }
188
}
189

190
void trace_enable_events(const char *line_buf)
191
{
192
    if (is_help_option(line_buf)) {
193
        trace_list_events(stdout);
194
        if (monitor_cur() == NULL) {
195
            exit(0);
196
        }
197
    } else {
198
        do_trace_enable_events(line_buf);
199
    }
200
}
201

202
static void trace_init_events(const char *fname)
203
{
204
    Location loc;
205
    FILE *fp;
206
    char line_buf[1024];
207
    size_t line_idx = 0;
208

209
    if (fname == NULL) {
210
        return;
211
    }
212

213
    loc_push_none(&loc);
214
    loc_set_file(fname, 0);
215
    fp = fopen(fname, "r");
216
    if (!fp) {
217
        error_report("%s", strerror(errno));
218
        exit(1);
219
    }
220
    while (fgets(line_buf, sizeof(line_buf), fp)) {
221
        loc_set_file(fname, ++line_idx);
222
        size_t len = strlen(line_buf);
223
        if (len > 1) {              /* skip empty lines */
224
            line_buf[len - 1] = '\0';
225
            if ('#' == line_buf[0]) { /* skip commented lines */
226
                continue;
227
            }
228
            trace_enable_events(line_buf);
229
        }
230
    }
231
    if (fclose(fp) != 0) {
232
        loc_set_file(fname, 0);
233
        error_report("%s", strerror(errno));
234
        exit(1);
235
    }
236
    loc_pop(&loc);
237
}
238

239
void trace_init_file(void)
240
{
241
#ifdef CONFIG_TRACE_SIMPLE
242
    st_set_trace_file(trace_opts_file);
243
    if (init_trace_on_startup) {
244
        st_set_trace_file_enabled(true);
245
    }
246
#elif defined CONFIG_TRACE_LOG
247
    /*
248
     * If both the simple and the log backends are enabled, "--trace file"
249
     * only applies to the simple backend; use "-D" for the log
250
     * backend. However we should only override -D if we actually have
251
     * something to override it with.
252
     */
253
    if (trace_opts_file) {
254
        qemu_set_log_filename(trace_opts_file, &error_fatal);
255
    }
256
#else
257
    if (trace_opts_file) {
258
        fprintf(stderr, "error: --trace file=...: "
259
                "option not supported by the selected tracing backends\n");
260
        exit(1);
261
    }
262
#endif
263
}
264

265
bool trace_init_backends(void)
266
{
267
#ifdef CONFIG_TRACE_SIMPLE
268
    if (!st_init()) {
269
        fprintf(stderr, "failed to initialize simple tracing backend.\n");
270
        return false;
271
    }
272
#endif
273

274
#ifdef CONFIG_TRACE_FTRACE
275
    if (!ftrace_init()) {
276
        fprintf(stderr, "failed to initialize ftrace backend.\n");
277
        return false;
278
    }
279
#endif
280

281
#ifdef CONFIG_TRACE_SYSLOG
282
    openlog(NULL, LOG_PID, LOG_DAEMON);
283
#endif
284

285
    return true;
286
}
287

288
void trace_opt_parse(const char *optstr)
289
{
290
    QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("trace"),
291
                                             optstr, true);
292
    if (!opts) {
293
        exit(1);
294
    }
295
    if (qemu_opt_get(opts, "enable")) {
296
        trace_enable_events(qemu_opt_get(opts, "enable"));
297
    }
298
    trace_init_events(qemu_opt_get(opts, "events"));
299
    init_trace_on_startup = true;
300
    g_free(trace_opts_file);
301
    trace_opts_file = g_strdup(qemu_opt_get(opts, "file"));
302
    qemu_opts_del(opts);
303
}
304

305
uint32_t trace_get_vcpu_event_count(void)
306
{
307
    return next_vcpu_id;
308
}
309

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.