xref: /linux/tools/perf/util/trace-event-scripting.c (revision 5e807647e155c5b2ae256849965e8311b3916d70)
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 <tzanussi@gmail.com>
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 
24 unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
25 
26 struct scripting_context *scripting_context;
27 
28 struct script_spec {
29 	struct list_head	node;
30 	struct scripting_ops	*ops;
31 	char			spec[];
32 };
33 
34 static LIST_HEAD(script_specs);
35 
36 static 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 
49 static void script_spec__add(struct script_spec *s)
50 {
51 	list_add_tail(&s->node, &script_specs);
52 }
53 
54 static 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 
64 static 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 
80 struct 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 
90 int 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 
103 void 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 
123 static int flush_script_unsupported(void)
124 {
125 	return 0;
126 }
127 
128 static int stop_script_unsupported(void)
129 {
130 	return 0;
131 }
132 
133 static 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 
140 static 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 
149 static 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 
159 static 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 
169 struct 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 
179 static 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
193 void setup_python_scripting(void)
194 {
195 	register_python_scripting(&python_scripting_unsupported_ops);
196 }
197 #else
198 extern struct scripting_ops python_scripting_ops;
199 
200 void setup_python_scripting(void)
201 {
202 	register_python_scripting(&python_scripting_ops);
203 }
204 #endif
205 
206 #ifdef HAVE_LIBTRACEEVENT
207 static 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 
216 static 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 
226 static 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 
235 struct 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 
245 static 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
259 void setup_perl_scripting(void)
260 {
261 	register_perl_scripting(&perl_scripting_unsupported_ops);
262 }
263 #else
264 extern struct scripting_ops perl_scripting_ops;
265 
266 void setup_perl_scripting(void)
267 {
268 	register_perl_scripting(&perl_scripting_ops);
269 }
270 #endif
271 #endif
272 
273 static 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 
296 static 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 
305 static 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 
384 int 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 }
408