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