tools: rename bitmap_alloc() to bitmap_zalloc()
[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         buf[ret] = '\0';
365
366         parse_saved_cmdline(pevent, buf, size);
367         ret = 0;
368 out:
369         free(buf);
370         return ret;
371 }
372
373 ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
374 {
375         char buf[BUFSIZ];
376         char test[] = { 23, 8, 68 };
377         char *version;
378         int show_version = 0;
379         int show_funcs = 0;
380         int show_printk = 0;
381         ssize_t size = -1;
382         int file_bigendian;
383         int host_bigendian;
384         int file_long_size;
385         int file_page_size;
386         struct tep_handle *pevent = NULL;
387         int err;
388
389         repipe = __repipe;
390         input_fd = fd;
391
392         if (do_read(buf, 3) < 0)
393                 return -1;
394         if (memcmp(buf, test, 3) != 0) {
395                 pr_debug("no trace data in the file");
396                 return -1;
397         }
398
399         if (do_read(buf, 7) < 0)
400                 return -1;
401         if (memcmp(buf, "tracing", 7) != 0) {
402                 pr_debug("not a trace file (missing 'tracing' tag)");
403                 return -1;
404         }
405
406         version = read_string();
407         if (version == NULL)
408                 return -1;
409         if (show_version)
410                 printf("version = %s\n", version);
411
412         if (do_read(buf, 1) < 0) {
413                 free(version);
414                 return -1;
415         }
416         file_bigendian = buf[0];
417         host_bigendian = bigendian();
418
419         if (trace_event__init(tevent)) {
420                 pr_debug("trace_event__init failed");
421                 goto out;
422         }
423
424         pevent = tevent->pevent;
425
426         tep_set_flag(pevent, TEP_NSEC_OUTPUT);
427         tep_set_file_bigendian(pevent, file_bigendian);
428         tep_set_local_bigendian(pevent, host_bigendian);
429
430         if (do_read(buf, 1) < 0)
431                 goto out;
432         file_long_size = buf[0];
433
434         file_page_size = read4(pevent);
435         if (!file_page_size)
436                 goto out;
437
438         tep_set_long_size(pevent, file_long_size);
439         tep_set_page_size(pevent, file_page_size);
440
441         err = read_header_files(pevent);
442         if (err)
443                 goto out;
444         err = read_ftrace_files(pevent);
445         if (err)
446                 goto out;
447         err = read_event_files(pevent);
448         if (err)
449                 goto out;
450         err = read_proc_kallsyms(pevent);
451         if (err)
452                 goto out;
453         err = read_ftrace_printk(pevent);
454         if (err)
455                 goto out;
456         if (atof(version) >= 0.6) {
457                 err = read_saved_cmdline(pevent);
458                 if (err)
459                         goto out;
460         }
461
462         size = trace_data_size;
463         repipe = false;
464
465         if (show_funcs) {
466                 tep_print_funcs(pevent);
467         } else if (show_printk) {
468                 tep_print_printk(pevent);
469         }
470
471         pevent = NULL;
472
473 out:
474         if (pevent)
475                 trace_event__cleanup(tevent);
476         free(version);
477         return size;
478 }