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