projects/linux·blob master · refs

407 lines · 9.7 KiB

1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * trace-event-scripting. Scripting engine common and initialization code.
4 *
5 * Copyright (C) 2009-2010 Tom Zanussi <[email protected]>
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <errno.h>
12#ifdef HAVE_LIBTRACEEVENT
13#include <event-parse.h>
14#endif
15
16#include "debug.h"
17#include "event.h"
18#include "trace-event.h"
19#include "evsel.h"
20#include <linux/perf_event.h>
21#include <linux/zalloc.h>
22#include "util/sample.h"
23
24unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
25
26struct scripting_context *scripting_context;
27
28struct script_spec {
29 struct list_head node;
30 struct scripting_ops *ops;
31 char spec[];
32};
33
34static LIST_HEAD(script_specs);
35
36static struct script_spec *script_spec__new(const char *spec,
37 struct scripting_ops *ops)
38{
39 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
40
41 if (s != NULL) {
42 strcpy(s->spec, spec);
43 s->ops = ops;
44 }
45
46 return s;
47}
48
49static void script_spec__add(struct script_spec *s)
50{
51 list_add_tail(&s->node, &script_specs);
52}
53
54static struct script_spec *script_spec__find(const char *spec)
55{
56 struct script_spec *s;
57
58 list_for_each_entry(s, &script_specs, node)
59 if (strcasecmp(s->spec, spec) == 0)
60 return s;
61 return NULL;
62}
63
64static int script_spec_register(const char *spec, struct scripting_ops *ops)
65{
66 struct script_spec *s;
67
68 s = script_spec__find(spec);
69 if (s)
70 return -1;
71
72 s = script_spec__new(spec, ops);
73 if (!s)
74 return -1;
75
76 script_spec__add(s);
77 return 0;
78}
79
80struct scripting_ops *script_spec__lookup(const char *spec)
81{
82 struct script_spec *s = script_spec__find(spec);
83
84 if (!s)
85 return NULL;
86
87 return s->ops;
88}
89
90int script_spec__for_each(int (*cb)(struct scripting_ops *ops, const char *spec))
91{
92 struct script_spec *s;
93 int ret = 0;
94
95 list_for_each_entry(s, &script_specs, node) {
96 ret = cb(s->ops, s->spec);
97 if (ret)
98 break;
99 }
100 return ret;
101}
102
103void scripting_context__update(struct scripting_context *c,
104 union perf_event *event,
105 struct perf_sample *sample,
106 struct addr_location *al,
107 struct addr_location *addr_al)
108{
109#ifdef HAVE_LIBTRACEEVENT
110 const struct tep_event *tp_format = evsel__tp_format(sample->evsel);
111
112 c->pevent = tp_format ? tp_format->tep : NULL;
113#else
114 c->pevent = NULL;
115#endif
116 c->event_data = sample->raw_data;
117 c->event = event;
118 c->sample = sample;
119 c->al = al;
120 c->addr_al = addr_al;
121}
122
123static int flush_script_unsupported(void)
124{
125 return 0;
126}
127
128static int stop_script_unsupported(void)
129{
130 return 0;
131}
132
133static void process_event_unsupported(union perf_event *event __maybe_unused,
134 struct perf_sample *sample __maybe_unused,
135 struct addr_location *al __maybe_unused,
136 struct addr_location *addr_al __maybe_unused)
137{
138}
139
140static void print_python_unsupported_msg(void)
141{
142 fprintf(stderr, "Python scripting not supported."
143 " Install libpython and rebuild perf to enable it.\n"
144 "For example:\n # apt-get install python-dev (ubuntu)"
145 "\n # yum install python-devel (Fedora)"
146 "\n etc.\n");
147}
148
149static int python_start_script_unsupported(const char *script __maybe_unused,
150 int argc __maybe_unused,
151 const char **argv __maybe_unused,
152 struct perf_session *session __maybe_unused)
153{
154 print_python_unsupported_msg();
155
156 return -1;
157}
158
159static int python_generate_script_unsupported(struct tep_handle *pevent
160 __maybe_unused,
161 const char *outfile
162 __maybe_unused)
163{
164 print_python_unsupported_msg();
165
166 return -1;
167}
168
169struct scripting_ops python_scripting_unsupported_ops = {
170 .name = "Python",
171 .dirname = "python",
172 .start_script = python_start_script_unsupported,
173 .flush_script = flush_script_unsupported,
174 .stop_script = stop_script_unsupported,
175 .process_event = process_event_unsupported,
176 .generate_script = python_generate_script_unsupported,
177};
178
179static void register_python_scripting(struct scripting_ops *scripting_ops)
180{
181 if (scripting_context == NULL)
182 scripting_context = malloc(sizeof(*scripting_context));
183
184 if (scripting_context == NULL ||
185 script_spec_register("Python", scripting_ops) ||
186 script_spec_register("py", scripting_ops)) {
187 pr_err("Error registering Python script extension: disabling it\n");
188 zfree(&scripting_context);
189 }
190}
191
192#ifndef HAVE_LIBPYTHON_SUPPORT
193void setup_python_scripting(void)
194{
195 register_python_scripting(&python_scripting_unsupported_ops);
196}
197#else
198extern struct scripting_ops python_scripting_ops;
199
200void setup_python_scripting(void)
201{
202 register_python_scripting(&python_scripting_ops);
203}
204#endif
205
206#ifdef HAVE_LIBTRACEEVENT
207static void print_perl_unsupported_msg(void)
208{
209 fprintf(stderr, "Perl scripting not supported."
210 " Install libperl and rebuild perf to enable it.\n"
211 "For example:\n # apt-get install libperl-dev (ubuntu)"
212 "\n # yum install 'perl(ExtUtils::Embed)' (Fedora)"
213 "\n etc.\n");
214}
215
216static int perl_start_script_unsupported(const char *script __maybe_unused,
217 int argc __maybe_unused,
218 const char **argv __maybe_unused,
219 struct perf_session *session __maybe_unused)
220{
221 print_perl_unsupported_msg();
222
223 return -1;
224}
225
226static int perl_generate_script_unsupported(struct tep_handle *pevent
227 __maybe_unused,
228 const char *outfile __maybe_unused)
229{
230 print_perl_unsupported_msg();
231
232 return -1;
233}
234
235struct scripting_ops perl_scripting_unsupported_ops = {
236 .name = "Perl",
237 .dirname = "perl",
238 .start_script = perl_start_script_unsupported,
239 .flush_script = flush_script_unsupported,
240 .stop_script = stop_script_unsupported,
241 .process_event = process_event_unsupported,
242 .generate_script = perl_generate_script_unsupported,
243};
244
245static void register_perl_scripting(struct scripting_ops *scripting_ops)
246{
247 if (scripting_context == NULL)
248 scripting_context = malloc(sizeof(*scripting_context));
249
250 if (scripting_context == NULL ||
251 script_spec_register("Perl", scripting_ops) ||
252 script_spec_register("pl", scripting_ops)) {
253 pr_err("Error registering Perl script extension: disabling it\n");
254 zfree(&scripting_context);
255 }
256}
257
258#ifndef HAVE_LIBPERL_SUPPORT
259void setup_perl_scripting(void)
260{
261 register_perl_scripting(&perl_scripting_unsupported_ops);
262}
263#else
264extern struct scripting_ops perl_scripting_ops;
265
266void setup_perl_scripting(void)
267{
268 register_perl_scripting(&perl_scripting_ops);
269}
270#endif
271#endif
272
273static const struct {
274 u32 flags;
275 const char *name;
276} sample_flags[] = {
277 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
278 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
279 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "jcc"},
280 {PERF_IP_FLAG_BRANCH, "jmp"},
281 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, "int"},
282 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, "iret"},
283 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, "syscall"},
284 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, "sysret"},
285 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "async"},
286 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | PERF_IP_FLAG_INTERRUPT,
287 "hw int"},
288 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "tx abrt"},
289 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "tr strt"},
290 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "tr end"},
291 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMENTRY, "vmentry"},
292 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMEXIT, "vmexit"},
293 {0, NULL}
294};
295
296static const struct {
297 u32 flags;
298 const char *name;
299} branch_events[] = {
300 {PERF_IP_FLAG_BRANCH_MISS, "miss"},
301 {PERF_IP_FLAG_NOT_TAKEN, "not_taken"},
302 {0, NULL}
303};
304
305static int sample_flags_to_name(u32 flags, char *str, size_t size)
306{
307 int i;
308 const char *prefix;
309 int pos = 0, ret, ev_idx = 0;
310 u32 xf = flags & PERF_ADDITIONAL_STATE_MASK;
311 u32 types, events;
312 char xs[16] = { 0 };
313
314 /* Clear additional state bits */
315 flags &= ~PERF_ADDITIONAL_STATE_MASK;
316
317 if (flags & PERF_IP_FLAG_TRACE_BEGIN)
318 prefix = "tr strt ";
319 else if (flags & PERF_IP_FLAG_TRACE_END)
320 prefix = "tr end ";
321 else
322 prefix = "";
323
324 ret = snprintf(str + pos, size - pos, "%s", prefix);
325 if (ret < 0)
326 return ret;
327 pos += ret;
328
329 flags &= ~(PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END);
330
331 types = flags & ~PERF_IP_FLAG_BRANCH_EVENT_MASK;
332 for (i = 0; sample_flags[i].name; i++) {
333 if (sample_flags[i].flags != types)
334 continue;
335
336 ret = snprintf(str + pos, size - pos, "%s", sample_flags[i].name);
337 if (ret < 0)
338 return ret;
339 pos += ret;
340 break;
341 }
342
343 events = flags & PERF_IP_FLAG_BRANCH_EVENT_MASK;
344 for (i = 0; branch_events[i].name; i++) {
345 if (!(branch_events[i].flags & events))
346 continue;
347
348 ret = snprintf(str + pos, size - pos, !ev_idx ? "/%s" : ",%s",
349 branch_events[i].name);
350 if (ret < 0)
351 return ret;
352 pos += ret;
353 ev_idx++;
354 }
355
356 /* Add an end character '/' for events */
357 if (ev_idx) {
358 ret = snprintf(str + pos, size - pos, "/");
359 if (ret < 0)
360 return ret;
361 pos += ret;
362 }
363
364 if (!xf)
365 return pos;
366
367 snprintf(xs, sizeof(xs), "(%s%s%s)",
368 flags & PERF_IP_FLAG_IN_TX ? "x" : "",
369 flags & PERF_IP_FLAG_INTR_DISABLE ? "D" : "",
370 flags & PERF_IP_FLAG_INTR_TOGGLE ? "t" : "");
371
372 /* Right align the string if its length is less than the limit */
373 if ((pos + strlen(xs)) < SAMPLE_FLAGS_STR_ALIGNED_SIZE)
374 ret = snprintf(str + pos, size - pos, "%*s",
375 (int)(SAMPLE_FLAGS_STR_ALIGNED_SIZE - ret), xs);
376 else
377 ret = snprintf(str + pos, size - pos, " %s", xs);
378 if (ret < 0)
379 return ret;
380
381 return pos + ret;
382}
383
384int perf_sample__sprintf_flags(u32 flags, char *str, size_t sz)
385{
386 const char *chars = PERF_IP_FLAG_CHARS;
387 const size_t n = strlen(PERF_IP_FLAG_CHARS);
388 size_t i, pos = 0;
389 int ret;
390
391 ret = sample_flags_to_name(flags, str, sz);
392 if (ret > 0)
393 return ret;
394
395 for (i = 0; i < n; i++, flags >>= 1) {
396 if ((flags & 1) && pos < sz)
397 str[pos++] = chars[i];
398 }
399 for (; i < 32; i++, flags >>= 1) {
400 if ((flags & 1) && pos < sz)
401 str[pos++] = '?';
402 }
403 if (pos < sz)
404 str[pos] = 0;
405
406 return pos;
407}