xref: /linux/tools/perf/util/trace-event-read.c (revision 83684c4e4d62cb02b2e4d0d18963d1035439278e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
4  */
5 #include <dirent.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdarg.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <sys/wait.h>
13 #include <sys/mman.h>
14 #include <event-parse.h>
15 #include <fcntl.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <limits.h>
19 
20 #include "trace-event.h"
21 #include "debug.h"
22 #include "util.h"
23 
24 static int input_fd;
25 
26 static ssize_t trace_data_size;
27 static bool repipe;
28 
29 static ssize_t __do_read(int fd, void *buf, size_t size)
30 {
31 	size_t rsize = size;
32 
33 	while (size) {
34 		ssize_t ret = read(fd, buf, size);
35 
36 		if (ret <= 0)
37 			return -1;
38 
39 		if (repipe) {
40 			ssize_t retw = write(STDOUT_FILENO, buf, ret);
41 
42 			if (retw <= 0 || retw != ret) {
43 				pr_debug("repiping input file");
44 				return -1;
45 			}
46 		}
47 
48 		size -= ret;
49 		buf += ret;
50 	}
51 
52 	return rsize;
53 }
54 
55 static ssize_t do_read(void *data, size_t size)
56 {
57 	ssize_t r;
58 
59 	r = __do_read(input_fd, data, size);
60 	if (r <= 0) {
61 		pr_debug("reading input file (size expected=%zu received=%zd)",
62 			 size, r);
63 		return -1;
64 	}
65 
66 	trace_data_size += r;
67 
68 	return r;
69 }
70 
71 /* If it fails, the next read will report it */
72 static void skip(size_t size)
73 {
74 	char buf[BUFSIZ];
75 	ssize_t ret;
76 
77 	while (size) {
78 		size_t len = size > BUFSIZ ? BUFSIZ : size;
79 
80 		ret = do_read(buf, len);
81 		if (ret <= 0)
82 			break;
83 
84 		size -= ret;
85 	}
86 }
87 
88 static unsigned int read4(struct tep_handle *pevent)
89 {
90 	unsigned int data;
91 
92 	if (do_read(&data, 4) < 0)
93 		return 0;
94 	return tep_read_number(pevent, &data, 4);
95 }
96 
97 static unsigned long long read8(struct tep_handle *pevent)
98 {
99 	unsigned long long data;
100 
101 	if (do_read(&data, 8) < 0)
102 		return 0;
103 	return tep_read_number(pevent, &data, 8);
104 }
105 
106 static char *read_string(void)
107 {
108 	char buf[BUFSIZ];
109 	char *str = NULL;
110 	int size = 0;
111 	off_t r;
112 	char c;
113 
114 	for (;;) {
115 		r = read(input_fd, &c, 1);
116 		if (r < 0) {
117 			pr_debug("reading input file");
118 			goto out;
119 		}
120 
121 		if (!r) {
122 			pr_debug("no data");
123 			goto out;
124 		}
125 
126 		if (repipe) {
127 			int retw = write(STDOUT_FILENO, &c, 1);
128 
129 			if (retw <= 0 || retw != r) {
130 				pr_debug("repiping input file string");
131 				goto out;
132 			}
133 		}
134 
135 		if (size >= (int)sizeof(buf) - 1) {
136 			pr_debug("string too long (max %zu bytes)", sizeof(buf) - 1);
137 			goto out;
138 		}
139 
140 		buf[size++] = c;
141 
142 		if (!c)
143 			break;
144 	}
145 
146 	trace_data_size += size;
147 
148 	str = malloc(size);
149 	if (str)
150 		memcpy(str, buf, size);
151 out:
152 	return str;
153 }
154 
155 static int read_proc_kallsyms(struct tep_handle *pevent)
156 {
157 	unsigned int size;
158 
159 	size = read4(pevent);
160 	if (!size)
161 		return 0;
162 	/*
163 	 * Just skip it, now that we configure libtraceevent to use the
164 	 * tools/perf/ symbol resolver.
165 	 *
166 	 * We need to skip it so that we can continue parsing old perf.data
167 	 * files, that contains this /proc/kallsyms payload.
168 	 *
169 	 * Newer perf.data files will have just the 4-bytes zeros "kallsyms
170 	 * payload", so that older tools can continue reading it and interpret
171 	 * it as "no kallsyms payload is present".
172 	 */
173 	lseek(input_fd, size, SEEK_CUR);
174 	trace_data_size += size;
175 	return 0;
176 }
177 
178 static int read_ftrace_printk(struct tep_handle *pevent)
179 {
180 	unsigned int size;
181 	char *buf;
182 
183 	/* it can have 0 size */
184 	size = read4(pevent);
185 	if (!size)
186 		return 0;
187 
188 	if (size == UINT_MAX) {
189 		pr_debug("invalid ftrace printk size\n");
190 		return -1;
191 	}
192 
193 	buf = malloc(size + 1);
194 	if (buf == NULL)
195 		return -1;
196 
197 	if (do_read(buf, size) < 0) {
198 		free(buf);
199 		return -1;
200 	}
201 
202 	buf[size] = '\0';
203 
204 	parse_ftrace_printk(pevent, buf, size);
205 
206 	free(buf);
207 	return 0;
208 }
209 
210 static int read_header_files(struct tep_handle *pevent)
211 {
212 	unsigned long long size;
213 	char *header_page;
214 	char buf[BUFSIZ];
215 	ssize_t ret = 0;
216 
217 	if (do_read(buf, 12) < 0)
218 		return -1;
219 
220 	if (memcmp(buf, "header_page", 12) != 0) {
221 		pr_debug("did not read header page");
222 		return -1;
223 	}
224 
225 	size = read8(pevent);
226 
227 	header_page = malloc(size);
228 	if (header_page == NULL)
229 		return -1;
230 
231 	if (do_read(header_page, size) < 0) {
232 		pr_debug("did not read header page");
233 		free(header_page);
234 		return -1;
235 	}
236 
237 	if (!tep_parse_header_page(pevent, header_page, size,
238 				   tep_get_long_size(pevent))) {
239 		/*
240 		 * The commit field in the page is of type long,
241 		 * use that instead, since it represents the kernel.
242 		 */
243 		tep_set_long_size(pevent, tep_get_header_page_size(pevent));
244 	}
245 	free(header_page);
246 
247 	if (do_read(buf, 13) < 0)
248 		return -1;
249 
250 	if (memcmp(buf, "header_event", 13) != 0) {
251 		pr_debug("did not read header event");
252 		return -1;
253 	}
254 
255 	size = read8(pevent);
256 	skip(size);
257 
258 	return ret;
259 }
260 
261 static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size)
262 {
263 	ssize_t ret;
264 	char *buf;
265 
266 	buf = malloc(size);
267 	if (buf == NULL) {
268 		pr_debug("memory allocation failure\n");
269 		return -1;
270 	}
271 
272 	ret = do_read(buf, size);
273 	if (ret < 0) {
274 		pr_debug("error reading ftrace file.\n");
275 		goto out;
276 	}
277 
278 	ret = parse_ftrace_file(pevent, buf, size);
279 	if (ret < 0)
280 		pr_debug("error parsing ftrace file.\n");
281 out:
282 	free(buf);
283 	return ret;
284 }
285 
286 static int read_event_file(struct tep_handle *pevent, char *sys,
287 			   unsigned long long size)
288 {
289 	ssize_t ret;
290 	char *buf;
291 
292 	buf = malloc(size);
293 	if (buf == NULL) {
294 		pr_debug("memory allocation failure\n");
295 		return -1;
296 	}
297 
298 	ret = do_read(buf, size);
299 	if (ret < 0)
300 		goto out;
301 
302 	ret = parse_event_file(pevent, buf, size, sys);
303 	if (ret < 0)
304 		pr_debug("error parsing event file.\n");
305 out:
306 	free(buf);
307 	return ret;
308 }
309 
310 static int read_ftrace_files(struct tep_handle *pevent)
311 {
312 	unsigned long long size;
313 	int count;
314 	int i;
315 	int ret;
316 
317 	count = read4(pevent);
318 
319 	for (i = 0; i < count; i++) {
320 		size = read8(pevent);
321 		ret = read_ftrace_file(pevent, size);
322 		if (ret)
323 			return ret;
324 	}
325 	return 0;
326 }
327 
328 static int read_event_files(struct tep_handle *pevent)
329 {
330 	unsigned long long size;
331 	char *sys;
332 	int systems;
333 	int count;
334 	int i,x;
335 	ssize_t ret;
336 
337 	systems = read4(pevent);
338 
339 	for (i = 0; i < systems; i++) {
340 		sys = read_string();
341 		if (sys == NULL)
342 			return -1;
343 
344 		count = read4(pevent);
345 
346 		for (x=0; x < count; x++) {
347 			size = read8(pevent);
348 			ret = read_event_file(pevent, sys, size);
349 			if (ret) {
350 				free(sys);
351 				return ret;
352 			}
353 		}
354 		free(sys);
355 	}
356 	return 0;
357 }
358 
359 static int read_saved_cmdline(struct tep_handle *pevent)
360 {
361 	unsigned long long size;
362 	char *buf;
363 	ssize_t ret;
364 
365 	/* it can have 0 size */
366 	size = read8(pevent);
367 	if (!size)
368 		return 0;
369 
370 	if (size == ULLONG_MAX) {
371 		pr_debug("invalid saved cmdline size");
372 		return -1;
373 	}
374 
375 	buf = malloc(size + 1);
376 	if (buf == NULL) {
377 		pr_debug("memory allocation failure\n");
378 		return -1;
379 	}
380 
381 	ret = do_read(buf, size);
382 	if (ret < 0) {
383 		pr_debug("error reading saved cmdlines\n");
384 		goto out;
385 	}
386 	buf[ret] = '\0';
387 
388 	parse_saved_cmdline(pevent, buf, size);
389 	ret = 0;
390 out:
391 	free(buf);
392 	return ret;
393 }
394 
395 ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
396 {
397 	char buf[BUFSIZ];
398 	char test[] = { 23, 8, 68 };
399 	char *version;
400 	int show_version = 0;
401 	int show_funcs = 0;
402 	int show_printk = 0;
403 	ssize_t size = -1;
404 	int file_bigendian;
405 	int host_bigendian;
406 	int file_long_size;
407 	int file_page_size;
408 	struct tep_handle *pevent = NULL;
409 	int err;
410 
411 	repipe = __repipe;
412 	input_fd = fd;
413 
414 	if (do_read(buf, 3) < 0)
415 		return -1;
416 	if (memcmp(buf, test, 3) != 0) {
417 		pr_debug("no trace data in the file");
418 		return -1;
419 	}
420 
421 	if (do_read(buf, 7) < 0)
422 		return -1;
423 	if (memcmp(buf, "tracing", 7) != 0) {
424 		pr_debug("not a trace file (missing 'tracing' tag)");
425 		return -1;
426 	}
427 
428 	version = read_string();
429 	if (version == NULL)
430 		return -1;
431 	if (show_version)
432 		printf("version = %s\n", version);
433 
434 	if (do_read(buf, 1) < 0) {
435 		free(version);
436 		return -1;
437 	}
438 	file_bigendian = buf[0];
439 	host_bigendian = host_is_bigendian() ? 1 : 0;
440 
441 	if (trace_event__init(tevent)) {
442 		pr_debug("trace_event__init failed");
443 		goto out;
444 	}
445 
446 	pevent = tevent->pevent;
447 
448 	tep_set_flag(pevent, TEP_NSEC_OUTPUT);
449 	tep_set_file_bigendian(pevent, file_bigendian);
450 	tep_set_local_bigendian(pevent, host_bigendian);
451 
452 	if (do_read(buf, 1) < 0)
453 		goto out;
454 	file_long_size = buf[0];
455 
456 	file_page_size = read4(pevent);
457 	if (!file_page_size)
458 		goto out;
459 
460 	tep_set_long_size(pevent, file_long_size);
461 	tep_set_page_size(pevent, file_page_size);
462 
463 	err = read_header_files(pevent);
464 	if (err)
465 		goto out;
466 	err = read_ftrace_files(pevent);
467 	if (err)
468 		goto out;
469 	err = read_event_files(pevent);
470 	if (err)
471 		goto out;
472 	err = read_proc_kallsyms(pevent);
473 	if (err)
474 		goto out;
475 	err = read_ftrace_printk(pevent);
476 	if (err)
477 		goto out;
478 	if (atof(version) >= 0.6) {
479 		err = read_saved_cmdline(pevent);
480 		if (err)
481 			goto out;
482 	}
483 
484 	size = trace_data_size;
485 	repipe = false;
486 
487 	if (show_funcs) {
488 		tep_print_funcs(pevent);
489 	} else if (show_printk) {
490 		tep_print_printk(pevent);
491 	}
492 
493 	pevent = NULL;
494 
495 out:
496 	if (pevent)
497 		trace_event__cleanup(tevent);
498 	free(version);
499 	return size;
500 }
501