xref: /openbmc/qemu/trace/qmp.c (revision 4a09d0bb)
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         TraceEventIter iter;
56         TraceEvent *ev;
57         trace_event_iter_init(&iter, name);
58         while ((ev = trace_event_iter_next(&iter)) != NULL) {
59             if (!ignore_unavailable && !trace_event_get_state_static(ev)) {
60                 error_setg(errp, "event \"%s\" is disabled", trace_event_get_name(ev));
61                 return false;
62             }
63         }
64         return true;
65     }
66 }
67 
68 TraceEventInfoList *qmp_trace_event_get_state(const char *name,
69                                               bool has_vcpu, int64_t vcpu,
70                                               Error **errp)
71 {
72     Error *err = NULL;
73     TraceEventInfoList *events = NULL;
74     TraceEventIter iter;
75     TraceEvent *ev;
76     bool is_pattern = trace_event_is_pattern(name);
77     CPUState *cpu;
78 
79     /* Check provided vcpu */
80     cpu = get_cpu(has_vcpu, vcpu, &err);
81     if (err) {
82         error_propagate(errp, err);
83         return NULL;
84     }
85 
86     /* Check events */
87     if (!check_events(has_vcpu, true, is_pattern, name, errp)) {
88         return NULL;
89     }
90 
91     /* Get states (all errors checked above) */
92     trace_event_iter_init(&iter, name);
93     while ((ev = trace_event_iter_next(&iter)) != NULL) {
94         TraceEventInfoList *elem;
95         bool is_vcpu = trace_event_is_vcpu(ev);
96         if (has_vcpu && !is_vcpu) {
97             continue;
98         }
99 
100         elem = g_new(TraceEventInfoList, 1);
101         elem->value = g_new(TraceEventInfo, 1);
102         elem->value->vcpu = is_vcpu;
103         elem->value->name = g_strdup(trace_event_get_name(ev));
104 
105         if (!trace_event_get_state_static(ev)) {
106             elem->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                         elem->value->state = TRACE_EVENT_STATE_ENABLED;
112                     } else {
113                         elem->value->state = TRACE_EVENT_STATE_DISABLED;
114                     }
115                 }
116                 /* else: already skipped above */
117             } else {
118                 if (trace_event_get_state_dynamic(ev)) {
119                     elem->value->state = TRACE_EVENT_STATE_ENABLED;
120                 } else {
121                     elem->value->state = TRACE_EVENT_STATE_DISABLED;
122                 }
123             }
124         }
125         elem->next = events;
126         events = elem;
127     }
128 
129     return events;
130 }
131 
132 void qmp_trace_event_set_state(const char *name, bool enable,
133                                bool has_ignore_unavailable, bool ignore_unavailable,
134                                bool has_vcpu, int64_t vcpu,
135                                Error **errp)
136 {
137     Error *err = NULL;
138     TraceEventIter iter;
139     TraceEvent *ev;
140     bool is_pattern = trace_event_is_pattern(name);
141     CPUState *cpu;
142 
143     /* Check provided vcpu */
144     cpu = get_cpu(has_vcpu, vcpu, &err);
145     if (err) {
146         error_propagate(errp, err);
147         return;
148     }
149 
150     /* Check events */
151     if (!check_events(has_vcpu, has_ignore_unavailable && ignore_unavailable,
152                       is_pattern, name, errp)) {
153         return;
154     }
155 
156     /* Apply changes (all errors checked above) */
157     trace_event_iter_init(&iter, name);
158     while ((ev = trace_event_iter_next(&iter)) != NULL) {
159         if (!trace_event_get_state_static(ev) ||
160             (has_vcpu && !trace_event_is_vcpu(ev))) {
161             continue;
162         }
163         if (has_vcpu) {
164             trace_event_set_vcpu_state_dynamic(cpu, ev, enable);
165         } else {
166             trace_event_set_state_dynamic(ev, enable);
167         }
168     }
169 }
170