xref: /openbmc/qemu/trace/qmp.c (revision 6016b7b4)
1 /*
2  * QMP commands for tracing events.
3  *
4  * Copyright (C) 2014-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 "qapi/error.h"
12 #include "qapi/qapi-commands-trace.h"
13 #include "control-vcpu.h"
14 
15 
16 static CPUState *get_cpu(bool has_vcpu, int vcpu, Error **errp)
17 {
18     if (has_vcpu) {
19         CPUState *cpu = qemu_get_cpu(vcpu);
20         if (cpu == NULL) {
21             error_setg(errp, "invalid vCPU index %u", vcpu);
22         }
23         return cpu;
24     } else {
25         return NULL;
26     }
27 }
28 
29 static bool check_events(bool has_vcpu, bool ignore_unavailable, bool is_pattern,
30                          const char *name, Error **errp)
31 {
32     if (!is_pattern) {
33         TraceEvent *ev = trace_event_name(name);
34 
35         /* error for non-existing event */
36         if (ev == NULL) {
37             error_setg(errp, "unknown event \"%s\"", name);
38             return false;
39         }
40 
41         /* error for non-vcpu event */
42         if (has_vcpu && !trace_event_is_vcpu(ev)) {
43             error_setg(errp, "event \"%s\" is not vCPU-specific", name);
44             return false;
45         }
46 
47         /* error for unavailable event */
48         if (!ignore_unavailable && !trace_event_get_state_static(ev)) {
49             error_setg(errp, "event \"%s\" is disabled", name);
50             return false;
51         }
52 
53         return true;
54     } else {
55         /* error for unavailable events */
56         TraceEventIter iter;
57         TraceEvent *ev;
58         trace_event_iter_init_pattern(&iter, name);
59         while ((ev = trace_event_iter_next(&iter)) != NULL) {
60             if (!ignore_unavailable && !trace_event_get_state_static(ev)) {
61                 error_setg(errp, "event \"%s\" is disabled", trace_event_get_name(ev));
62                 return false;
63             }
64         }
65         return true;
66     }
67 }
68 
69 TraceEventInfoList *qmp_trace_event_get_state(const char *name,
70                                               bool has_vcpu, int64_t vcpu,
71                                               Error **errp)
72 {
73     Error *err = NULL;
74     TraceEventInfoList *events = NULL;
75     TraceEventIter iter;
76     TraceEvent *ev;
77     bool is_pattern = trace_event_is_pattern(name);
78     CPUState *cpu;
79 
80     /* Check provided vcpu */
81     cpu = get_cpu(has_vcpu, vcpu, &err);
82     if (err) {
83         error_propagate(errp, err);
84         return NULL;
85     }
86 
87     /* Check events */
88     if (!check_events(has_vcpu, true, is_pattern, name, errp)) {
89         return NULL;
90     }
91 
92     /* Get states (all errors checked above) */
93     trace_event_iter_init_pattern(&iter, name);
94     while ((ev = trace_event_iter_next(&iter)) != NULL) {
95         TraceEventInfo *value;
96         bool is_vcpu = trace_event_is_vcpu(ev);
97         if (has_vcpu && !is_vcpu) {
98             continue;
99         }
100 
101         value = g_new(TraceEventInfo, 1);
102         value->vcpu = is_vcpu;
103         value->name = g_strdup(trace_event_get_name(ev));
104 
105         if (!trace_event_get_state_static(ev)) {
106             value->state = TRACE_EVENT_STATE_UNAVAILABLE;
107         } else {
108             if (has_vcpu) {
109                 if (is_vcpu) {
110                     if (trace_event_get_vcpu_state_dynamic(cpu, ev)) {
111                         value->state = TRACE_EVENT_STATE_ENABLED;
112                     } else {
113                         value->state = TRACE_EVENT_STATE_DISABLED;
114                     }
115                 }
116                 /* else: already skipped above */
117             } else {
118                 if (trace_event_get_state_dynamic(ev)) {
119                     value->state = TRACE_EVENT_STATE_ENABLED;
120                 } else {
121                     value->state = TRACE_EVENT_STATE_DISABLED;
122                 }
123             }
124         }
125         QAPI_LIST_PREPEND(events, value);
126     }
127 
128     return events;
129 }
130 
131 void qmp_trace_event_set_state(const char *name, bool enable,
132                                bool has_ignore_unavailable, bool ignore_unavailable,
133                                bool has_vcpu, int64_t vcpu,
134                                Error **errp)
135 {
136     Error *err = NULL;
137     TraceEventIter iter;
138     TraceEvent *ev;
139     bool is_pattern = trace_event_is_pattern(name);
140     CPUState *cpu;
141 
142     /* Check provided vcpu */
143     cpu = get_cpu(has_vcpu, vcpu, &err);
144     if (err) {
145         error_propagate(errp, err);
146         return;
147     }
148 
149     /* Check events */
150     if (!check_events(has_vcpu, has_ignore_unavailable && ignore_unavailable,
151                       is_pattern, name, errp)) {
152         return;
153     }
154 
155     /* Apply changes (all errors checked above) */
156     trace_event_iter_init_pattern(&iter, name);
157     while ((ev = trace_event_iter_next(&iter)) != NULL) {
158         if (!trace_event_get_state_static(ev) ||
159             (has_vcpu && !trace_event_is_vcpu(ev))) {
160             continue;
161         }
162         if (has_vcpu) {
163             trace_event_set_vcpu_state_dynamic(cpu, ev, enable);
164         } else {
165             trace_event_set_state_dynamic(ev, enable);
166         }
167     }
168 }
169