22ded8000ef6a62a166a0db359d9b191c8ba9206
[linux-3.10.git] / tools / perf / util / trace-event-read.c
1 /*
2  * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
3  *
4  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License (not later!)
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20  */
21 #include <dirent.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <getopt.h>
26 #include <stdarg.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <sys/mman.h>
31 #include <pthread.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <errno.h>
35
36 #include "../perf.h"
37 #include "util.h"
38 #include "trace-event.h"
39
40 static int input_fd;
41
42 int file_bigendian;
43 int host_bigendian;
44 static int long_size;
45
46 static ssize_t calc_data_size;
47 static bool repipe;
48
49 static int do_read(int fd, void *buf, int size)
50 {
51         int rsize = size;
52
53         while (size) {
54                 int ret = read(fd, buf, size);
55
56                 if (ret <= 0)
57                         return -1;
58
59                 if (repipe) {
60                         int retw = write(STDOUT_FILENO, buf, ret);
61
62                         if (retw <= 0 || retw != ret)
63                                 die("repiping input file");
64                 }
65
66                 size -= ret;
67                 buf += ret;
68         }
69
70         return rsize;
71 }
72
73 static int read_or_die(void *data, int size)
74 {
75         int r;
76
77         r = do_read(input_fd, data, size);
78         if (r <= 0)
79                 die("reading input file (size expected=%d received=%d)",
80                     size, r);
81
82         if (calc_data_size)
83                 calc_data_size += r;
84
85         return r;
86 }
87
88 /* If it fails, the next read will report it */
89 static void skip(int size)
90 {
91         char buf[BUFSIZ];
92         int r;
93
94         while (size) {
95                 r = size > BUFSIZ ? BUFSIZ : size;
96                 read_or_die(buf, r);
97                 size -= r;
98         };
99 }
100
101 static unsigned int read4(struct pevent *pevent)
102 {
103         unsigned int data;
104
105         read_or_die(&data, 4);
106         return __data2host4(pevent, data);
107 }
108
109 static unsigned long long read8(struct pevent *pevent)
110 {
111         unsigned long long data;
112
113         read_or_die(&data, 8);
114         return __data2host8(pevent, data);
115 }
116
117 static char *read_string(void)
118 {
119         char buf[BUFSIZ];
120         char *str = NULL;
121         int size = 0;
122         off_t r;
123         char c;
124
125         for (;;) {
126                 r = read(input_fd, &c, 1);
127                 if (r < 0)
128                         die("reading input file");
129
130                 if (!r)
131                         die("no data");
132
133                 if (repipe) {
134                         int retw = write(STDOUT_FILENO, &c, 1);
135
136                         if (retw <= 0 || retw != r)
137                                 die("repiping input file string");
138                 }
139
140                 buf[size++] = c;
141
142                 if (!c)
143                         break;
144         }
145
146         if (calc_data_size)
147                 calc_data_size += size;
148
149         str = malloc(size);
150         if (str)
151                 memcpy(str, buf, size);
152
153         return str;
154 }
155
156 static int read_proc_kallsyms(struct pevent *pevent)
157 {
158         unsigned int size;
159         char *buf;
160
161         size = read4(pevent);
162         if (!size)
163                 return 0;
164
165         buf = malloc(size + 1);
166         if (buf == NULL)
167                 return -1;
168
169         read_or_die(buf, size);
170         buf[size] = '\0';
171
172         parse_proc_kallsyms(pevent, buf, size);
173
174         free(buf);
175         return 0;
176 }
177
178 static int read_ftrace_printk(struct pevent *pevent)
179 {
180         unsigned int size;
181         char *buf;
182
183         size = read4(pevent);
184         if (!size)
185                 return 0;
186
187         buf = malloc(size);
188         if (buf == NULL)
189                 return -1;
190
191         read_or_die(buf, size);
192
193         parse_ftrace_printk(pevent, buf, size);
194
195         free(buf);
196         return 0;
197 }
198
199 static int read_header_files(struct pevent *pevent)
200 {
201         unsigned long long size;
202         char *header_event;
203         char buf[BUFSIZ];
204
205         read_or_die(buf, 12);
206
207         if (memcmp(buf, "header_page", 12) != 0)
208                 die("did not read header page");
209
210         size = read8(pevent);
211         skip(size);
212
213         /*
214          * The size field in the page is of type long,
215          * use that instead, since it represents the kernel.
216          */
217         long_size = header_page_size_size;
218
219         read_or_die(buf, 13);
220         if (memcmp(buf, "header_event", 13) != 0)
221                 die("did not read header event");
222
223         size = read8(pevent);
224         header_event = malloc(size);
225         if (header_event == NULL)
226                 return -1;
227
228         read_or_die(header_event, size);
229         free(header_event);
230         return 0;
231 }
232
233 static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
234 {
235         char *buf;
236
237         buf = malloc(size);
238         if (buf == NULL)
239                 return -1;
240
241         read_or_die(buf, size);
242         parse_ftrace_file(pevent, buf, size);
243         free(buf);
244         return 0;
245 }
246
247 static int read_event_file(struct pevent *pevent, char *sys,
248                             unsigned long long size)
249 {
250         char *buf;
251
252         buf = malloc(size);
253         if (buf == NULL)
254                 return -1;
255
256         read_or_die(buf, size);
257         parse_event_file(pevent, buf, size, sys);
258         free(buf);
259         return 0;
260 }
261
262 static int read_ftrace_files(struct pevent *pevent)
263 {
264         unsigned long long size;
265         int count;
266         int i;
267         int ret;
268
269         count = read4(pevent);
270
271         for (i = 0; i < count; i++) {
272                 size = read8(pevent);
273                 ret = read_ftrace_file(pevent, size);
274                 if (ret)
275                         return ret;
276         }
277         return 0;
278 }
279
280 static int read_event_files(struct pevent *pevent)
281 {
282         unsigned long long size;
283         char *sys;
284         int systems;
285         int count;
286         int i,x;
287         int ret;
288
289         systems = read4(pevent);
290
291         for (i = 0; i < systems; i++) {
292                 sys = read_string();
293                 if (sys == NULL)
294                         return -1;
295
296                 count = read4(pevent);
297                 for (x=0; x < count; x++) {
298                         size = read8(pevent);
299                         ret = read_event_file(pevent, sys, size);
300                         if (ret)
301                                 return ret;
302                 }
303         }
304         return 0;
305 }
306
307 ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
308 {
309         char buf[BUFSIZ];
310         char test[] = { 23, 8, 68 };
311         char *version;
312         int show_version = 0;
313         int show_funcs = 0;
314         int show_printk = 0;
315         ssize_t size = -1;
316         struct pevent *pevent;
317         int err;
318
319         *ppevent = NULL;
320
321         calc_data_size = 1;
322         repipe = __repipe;
323
324         input_fd = fd;
325
326         read_or_die(buf, 3);
327         if (memcmp(buf, test, 3) != 0)
328                 die("no trace data in the file");
329
330         read_or_die(buf, 7);
331         if (memcmp(buf, "tracing", 7) != 0)
332                 die("not a trace file (missing 'tracing' tag)");
333
334         version = read_string();
335         if (version == NULL)
336                 return -1;
337         if (show_version)
338                 printf("version = %s\n", version);
339         free(version);
340
341         read_or_die(buf, 1);
342         file_bigendian = buf[0];
343         host_bigendian = bigendian();
344
345         pevent = read_trace_init(file_bigendian, host_bigendian);
346         if (pevent == NULL) {
347                 pr_debug("read_trace_init failed");
348                 goto out;
349         }
350
351         read_or_die(buf, 1);
352         long_size = buf[0];
353
354         page_size = read4(pevent);
355
356         err = read_header_files(pevent);
357         if (err)
358                 goto out;
359         err = read_ftrace_files(pevent);
360         if (err)
361                 goto out;
362         err = read_event_files(pevent);
363         if (err)
364                 goto out;
365         err = read_proc_kallsyms(pevent);
366         if (err)
367                 goto out;
368         err = read_ftrace_printk(pevent);
369         if (err)
370                 goto out;
371
372         size = calc_data_size - 1;
373         calc_data_size = 0;
374         repipe = false;
375
376         if (show_funcs) {
377                 pevent_print_funcs(pevent);
378         } else if (show_printk) {
379                 pevent_print_printk(pevent);
380         }
381
382         *ppevent = pevent;
383         pevent = NULL;
384
385 out:
386         if (pevent)
387                 pevent_free(pevent);
388         return size;
389 }