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