Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / perf / util / trace-event-read.c
blobecbbb93f018539ea0748706fca090f838a89f853
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>
19 #include "trace-event.h"
20 #include "debug.h"
21 #include "util.h"
23 static int input_fd;
25 static ssize_t trace_data_size;
26 static bool repipe;
28 static int __do_read(int fd, void *buf, int size)
30 int rsize = size;
32 while (size) {
33 int ret = read(fd, buf, size);
35 if (ret <= 0)
36 return -1;
38 if (repipe) {
39 int retw = write(STDOUT_FILENO, buf, ret);
41 if (retw <= 0 || retw != ret) {
42 pr_debug("repiping input file");
43 return -1;
47 size -= ret;
48 buf += ret;
51 return rsize;
54 static int do_read(void *data, int size)
56 int r;
58 r = __do_read(input_fd, data, size);
59 if (r <= 0) {
60 pr_debug("reading input file (size expected=%d received=%d)",
61 size, r);
62 return -1;
65 trace_data_size += r;
67 return r;
70 /* If it fails, the next read will report it */
71 static void skip(int size)
73 char buf[BUFSIZ];
74 int r;
76 while (size) {
77 r = size > BUFSIZ ? BUFSIZ : size;
78 do_read(buf, r);
79 size -= r;
83 static unsigned int read4(struct tep_handle *pevent)
85 unsigned int data;
87 if (do_read(&data, 4) < 0)
88 return 0;
89 return tep_read_number(pevent, &data, 4);
92 static unsigned long long read8(struct tep_handle *pevent)
94 unsigned long long data;
96 if (do_read(&data, 8) < 0)
97 return 0;
98 return tep_read_number(pevent, &data, 8);
101 static char *read_string(void)
103 char buf[BUFSIZ];
104 char *str = NULL;
105 int size = 0;
106 off_t r;
107 char c;
109 for (;;) {
110 r = read(input_fd, &c, 1);
111 if (r < 0) {
112 pr_debug("reading input file");
113 goto out;
116 if (!r) {
117 pr_debug("no data");
118 goto out;
121 if (repipe) {
122 int retw = write(STDOUT_FILENO, &c, 1);
124 if (retw <= 0 || retw != r) {
125 pr_debug("repiping input file string");
126 goto out;
130 buf[size++] = c;
132 if (!c)
133 break;
136 trace_data_size += size;
138 str = malloc(size);
139 if (str)
140 memcpy(str, buf, size);
141 out:
142 return str;
145 static int read_proc_kallsyms(struct tep_handle *pevent)
147 unsigned int size;
149 size = read4(pevent);
150 if (!size)
151 return 0;
153 * Just skip it, now that we configure libtraceevent to use the
154 * tools/perf/ symbol resolver.
156 * We need to skip it so that we can continue parsing old perf.data
157 * files, that contains this /proc/kallsyms payload.
159 * Newer perf.data files will have just the 4-bytes zeros "kallsyms
160 * payload", so that older tools can continue reading it and interpret
161 * it as "no kallsyms payload is present".
163 lseek(input_fd, size, SEEK_CUR);
164 trace_data_size += size;
165 return 0;
168 static int read_ftrace_printk(struct tep_handle *pevent)
170 unsigned int size;
171 char *buf;
173 /* it can have 0 size */
174 size = read4(pevent);
175 if (!size)
176 return 0;
178 buf = malloc(size + 1);
179 if (buf == NULL)
180 return -1;
182 if (do_read(buf, size) < 0) {
183 free(buf);
184 return -1;
187 buf[size] = '\0';
189 parse_ftrace_printk(pevent, buf, size);
191 free(buf);
192 return 0;
195 static int read_header_files(struct tep_handle *pevent)
197 unsigned long long size;
198 char *header_page;
199 char buf[BUFSIZ];
200 int ret = 0;
202 if (do_read(buf, 12) < 0)
203 return -1;
205 if (memcmp(buf, "header_page", 12) != 0) {
206 pr_debug("did not read header page");
207 return -1;
210 size = read8(pevent);
212 header_page = malloc(size);
213 if (header_page == NULL)
214 return -1;
216 if (do_read(header_page, size) < 0) {
217 pr_debug("did not read header page");
218 free(header_page);
219 return -1;
222 if (!tep_parse_header_page(pevent, header_page, size,
223 tep_get_long_size(pevent))) {
225 * The commit field in the page is of type long,
226 * use that instead, since it represents the kernel.
228 tep_set_long_size(pevent, tep_get_header_page_size(pevent));
230 free(header_page);
232 if (do_read(buf, 13) < 0)
233 return -1;
235 if (memcmp(buf, "header_event", 13) != 0) {
236 pr_debug("did not read header event");
237 return -1;
240 size = read8(pevent);
241 skip(size);
243 return ret;
246 static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size)
248 int ret;
249 char *buf;
251 buf = malloc(size);
252 if (buf == NULL) {
253 pr_debug("memory allocation failure\n");
254 return -1;
257 ret = do_read(buf, size);
258 if (ret < 0) {
259 pr_debug("error reading ftrace file.\n");
260 goto out;
263 ret = parse_ftrace_file(pevent, buf, size);
264 if (ret < 0)
265 pr_debug("error parsing ftrace file.\n");
266 out:
267 free(buf);
268 return ret;
271 static int read_event_file(struct tep_handle *pevent, char *sys,
272 unsigned long long size)
274 int ret;
275 char *buf;
277 buf = malloc(size);
278 if (buf == NULL) {
279 pr_debug("memory allocation failure\n");
280 return -1;
283 ret = do_read(buf, size);
284 if (ret < 0)
285 goto out;
287 ret = parse_event_file(pevent, buf, size, sys);
288 if (ret < 0)
289 pr_debug("error parsing event file.\n");
290 out:
291 free(buf);
292 return ret;
295 static int read_ftrace_files(struct tep_handle *pevent)
297 unsigned long long size;
298 int count;
299 int i;
300 int ret;
302 count = read4(pevent);
304 for (i = 0; i < count; i++) {
305 size = read8(pevent);
306 ret = read_ftrace_file(pevent, size);
307 if (ret)
308 return ret;
310 return 0;
313 static int read_event_files(struct tep_handle *pevent)
315 unsigned long long size;
316 char *sys;
317 int systems;
318 int count;
319 int i,x;
320 int ret;
322 systems = read4(pevent);
324 for (i = 0; i < systems; i++) {
325 sys = read_string();
326 if (sys == NULL)
327 return -1;
329 count = read4(pevent);
331 for (x=0; x < count; x++) {
332 size = read8(pevent);
333 ret = read_event_file(pevent, sys, size);
334 if (ret) {
335 free(sys);
336 return ret;
339 free(sys);
341 return 0;
344 static int read_saved_cmdline(struct tep_handle *pevent)
346 unsigned long long size;
347 char *buf;
348 int ret;
350 /* it can have 0 size */
351 size = read8(pevent);
352 if (!size)
353 return 0;
355 buf = malloc(size + 1);
356 if (buf == NULL) {
357 pr_debug("memory allocation failure\n");
358 return -1;
361 ret = do_read(buf, size);
362 if (ret < 0) {
363 pr_debug("error reading saved cmdlines\n");
364 goto out;
366 buf[ret] = '\0';
368 parse_saved_cmdline(pevent, buf, size);
369 ret = 0;
370 out:
371 free(buf);
372 return ret;
375 ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
377 char buf[BUFSIZ];
378 char test[] = { 23, 8, 68 };
379 char *version;
380 int show_version = 0;
381 int show_funcs = 0;
382 int show_printk = 0;
383 ssize_t size = -1;
384 int file_bigendian;
385 int host_bigendian;
386 int file_long_size;
387 int file_page_size;
388 struct tep_handle *pevent = NULL;
389 int err;
391 repipe = __repipe;
392 input_fd = fd;
394 if (do_read(buf, 3) < 0)
395 return -1;
396 if (memcmp(buf, test, 3) != 0) {
397 pr_debug("no trace data in the file");
398 return -1;
401 if (do_read(buf, 7) < 0)
402 return -1;
403 if (memcmp(buf, "tracing", 7) != 0) {
404 pr_debug("not a trace file (missing 'tracing' tag)");
405 return -1;
408 version = read_string();
409 if (version == NULL)
410 return -1;
411 if (show_version)
412 printf("version = %s\n", version);
414 if (do_read(buf, 1) < 0) {
415 free(version);
416 return -1;
418 file_bigendian = buf[0];
419 host_bigendian = host_is_bigendian() ? 1 : 0;
421 if (trace_event__init(tevent)) {
422 pr_debug("trace_event__init failed");
423 goto out;
426 pevent = tevent->pevent;
428 tep_set_flag(pevent, TEP_NSEC_OUTPUT);
429 tep_set_file_bigendian(pevent, file_bigendian);
430 tep_set_local_bigendian(pevent, host_bigendian);
432 if (do_read(buf, 1) < 0)
433 goto out;
434 file_long_size = buf[0];
436 file_page_size = read4(pevent);
437 if (!file_page_size)
438 goto out;
440 tep_set_long_size(pevent, file_long_size);
441 tep_set_page_size(pevent, file_page_size);
443 err = read_header_files(pevent);
444 if (err)
445 goto out;
446 err = read_ftrace_files(pevent);
447 if (err)
448 goto out;
449 err = read_event_files(pevent);
450 if (err)
451 goto out;
452 err = read_proc_kallsyms(pevent);
453 if (err)
454 goto out;
455 err = read_ftrace_printk(pevent);
456 if (err)
457 goto out;
458 if (atof(version) >= 0.6) {
459 err = read_saved_cmdline(pevent);
460 if (err)
461 goto out;
464 size = trace_data_size;
465 repipe = false;
467 if (show_funcs) {
468 tep_print_funcs(pevent);
469 } else if (show_printk) {
470 tep_print_printk(pevent);
473 pevent = NULL;
475 out:
476 if (pevent)
477 trace_event__cleanup(tevent);
478 free(version);
479 return size;