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 #define _FILE_OFFSET_BITS 64
22
23 #include <dirent.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <getopt.h>
28 #include <stdarg.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/wait.h>
32 #include <sys/mman.h>
33 #include <pthread.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <errno.h>
37
38 #include "../perf.h"
39 #include "util.h"
40 #include "trace-event.h"
41
42 static int input_fd;
43
44 static int read_page;
45
46 int file_bigendian;
47 int host_bigendian;
48 static int long_size;
49
50 static unsigned long page_size;
51
52 static ssize_t calc_data_size;
53 static bool repipe;
54
do_read(int fd,void * buf,int size)55 static int do_read(int fd, void *buf, int size)
56 {
57 int rsize = size;
58
59 while (size) {
60 int ret = read(fd, buf, size);
61
62 if (ret <= 0)
63 return -1;
64
65 if (repipe) {
66 int retw = write(STDOUT_FILENO, buf, ret);
67
68 if (retw <= 0 || retw != ret)
69 die("repiping input file");
70 }
71
72 size -= ret;
73 buf += ret;
74 }
75
76 return rsize;
77 }
78
read_or_die(void * data,int size)79 static int read_or_die(void *data, int size)
80 {
81 int r;
82
83 r = do_read(input_fd, data, size);
84 if (r <= 0)
85 die("reading input file (size expected=%d received=%d)",
86 size, r);
87
88 if (calc_data_size)
89 calc_data_size += r;
90
91 return r;
92 }
93
94 /* If it fails, the next read will report it */
skip(int size)95 static void skip(int size)
96 {
97 char buf[BUFSIZ];
98 int r;
99
100 while (size) {
101 r = size > BUFSIZ ? BUFSIZ : size;
102 read_or_die(buf, r);
103 size -= r;
104 };
105 }
106
read4(void)107 static unsigned int read4(void)
108 {
109 unsigned int data;
110
111 read_or_die(&data, 4);
112 return __data2host4(data);
113 }
114
read8(void)115 static unsigned long long read8(void)
116 {
117 unsigned long long data;
118
119 read_or_die(&data, 8);
120 return __data2host8(data);
121 }
122
read_string(void)123 static char *read_string(void)
124 {
125 char buf[BUFSIZ];
126 char *str = NULL;
127 int size = 0;
128 off_t r;
129 char c;
130
131 for (;;) {
132 r = read(input_fd, &c, 1);
133 if (r < 0)
134 die("reading input file");
135
136 if (!r)
137 die("no data");
138
139 if (repipe) {
140 int retw = write(STDOUT_FILENO, &c, 1);
141
142 if (retw <= 0 || retw != r)
143 die("repiping input file string");
144 }
145
146 buf[size++] = c;
147
148 if (!c)
149 break;
150 }
151
152 if (calc_data_size)
153 calc_data_size += size;
154
155 str = malloc_or_die(size);
156 memcpy(str, buf, size);
157
158 return str;
159 }
160
read_proc_kallsyms(void)161 static void read_proc_kallsyms(void)
162 {
163 unsigned int size;
164 char *buf;
165
166 size = read4();
167 if (!size)
168 return;
169
170 buf = malloc_or_die(size + 1);
171 read_or_die(buf, size);
172 buf[size] = '\0';
173
174 parse_proc_kallsyms(buf, size);
175
176 free(buf);
177 }
178
read_ftrace_printk(void)179 static void read_ftrace_printk(void)
180 {
181 unsigned int size;
182 char *buf;
183
184 size = read4();
185 if (!size)
186 return;
187
188 buf = malloc_or_die(size);
189 read_or_die(buf, size);
190
191 parse_ftrace_printk(buf, size);
192
193 free(buf);
194 }
195
read_header_files(void)196 static void read_header_files(void)
197 {
198 unsigned long long size;
199 char *header_event;
200 char buf[BUFSIZ];
201
202 read_or_die(buf, 12);
203
204 if (memcmp(buf, "header_page", 12) != 0)
205 die("did not read header page");
206
207 size = read8();
208 skip(size);
209
210 /*
211 * The size field in the page is of type long,
212 * use that instead, since it represents the kernel.
213 */
214 long_size = header_page_size_size;
215
216 read_or_die(buf, 13);
217 if (memcmp(buf, "header_event", 13) != 0)
218 die("did not read header event");
219
220 size = read8();
221 header_event = malloc_or_die(size);
222 read_or_die(header_event, size);
223 free(header_event);
224 }
225
read_ftrace_file(unsigned long long size)226 static void read_ftrace_file(unsigned long long size)
227 {
228 char *buf;
229
230 buf = malloc_or_die(size);
231 read_or_die(buf, size);
232 parse_ftrace_file(buf, size);
233 free(buf);
234 }
235
read_event_file(char * sys,unsigned long long size)236 static void read_event_file(char *sys, unsigned long long size)
237 {
238 char *buf;
239
240 buf = malloc_or_die(size);
241 read_or_die(buf, size);
242 parse_event_file(buf, size, sys);
243 free(buf);
244 }
245
read_ftrace_files(void)246 static void read_ftrace_files(void)
247 {
248 unsigned long long size;
249 int count;
250 int i;
251
252 count = read4();
253
254 for (i = 0; i < count; i++) {
255 size = read8();
256 read_ftrace_file(size);
257 }
258 }
259
read_event_files(void)260 static void read_event_files(void)
261 {
262 unsigned long long size;
263 char *sys;
264 int systems;
265 int count;
266 int i,x;
267
268 systems = read4();
269
270 for (i = 0; i < systems; i++) {
271 sys = read_string();
272
273 count = read4();
274 for (x=0; x < count; x++) {
275 size = read8();
276 read_event_file(sys, size);
277 }
278 }
279 }
280
281 struct cpu_data {
282 unsigned long long offset;
283 unsigned long long size;
284 unsigned long long timestamp;
285 struct record *next;
286 char *page;
287 int cpu;
288 int index;
289 int page_size;
290 };
291
292 static struct cpu_data *cpu_data;
293
update_cpu_data_index(int cpu)294 static void update_cpu_data_index(int cpu)
295 {
296 cpu_data[cpu].offset += page_size;
297 cpu_data[cpu].size -= page_size;
298 cpu_data[cpu].index = 0;
299 }
300
get_next_page(int cpu)301 static void get_next_page(int cpu)
302 {
303 off_t save_seek;
304 off_t ret;
305
306 if (!cpu_data[cpu].page)
307 return;
308
309 if (read_page) {
310 if (cpu_data[cpu].size <= page_size) {
311 free(cpu_data[cpu].page);
312 cpu_data[cpu].page = NULL;
313 return;
314 }
315
316 update_cpu_data_index(cpu);
317
318 /* other parts of the code may expect the pointer to not move */
319 save_seek = lseek(input_fd, 0, SEEK_CUR);
320
321 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
322 if (ret == (off_t)-1)
323 die("failed to lseek");
324 ret = read(input_fd, cpu_data[cpu].page, page_size);
325 if (ret < 0)
326 die("failed to read page");
327
328 /* reset the file pointer back */
329 lseek(input_fd, save_seek, SEEK_SET);
330
331 return;
332 }
333
334 munmap(cpu_data[cpu].page, page_size);
335 cpu_data[cpu].page = NULL;
336
337 if (cpu_data[cpu].size <= page_size)
338 return;
339
340 update_cpu_data_index(cpu);
341
342 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
343 input_fd, cpu_data[cpu].offset);
344 if (cpu_data[cpu].page == MAP_FAILED)
345 die("failed to mmap cpu %d at offset 0x%llx",
346 cpu, cpu_data[cpu].offset);
347 }
348
type_len4host(unsigned int type_len_ts)349 static unsigned int type_len4host(unsigned int type_len_ts)
350 {
351 if (file_bigendian)
352 return (type_len_ts >> 27) & ((1 << 5) - 1);
353 else
354 return type_len_ts & ((1 << 5) - 1);
355 }
356
ts4host(unsigned int type_len_ts)357 static unsigned int ts4host(unsigned int type_len_ts)
358 {
359 if (file_bigendian)
360 return type_len_ts & ((1 << 27) - 1);
361 else
362 return type_len_ts >> 5;
363 }
364
calc_index(void * ptr,int cpu)365 static int calc_index(void *ptr, int cpu)
366 {
367 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
368 }
369
trace_peek_data(int cpu)370 struct record *trace_peek_data(int cpu)
371 {
372 struct record *data;
373 void *page = cpu_data[cpu].page;
374 int idx = cpu_data[cpu].index;
375 void *ptr = page + idx;
376 unsigned long long extend;
377 unsigned int type_len_ts;
378 unsigned int type_len;
379 unsigned int delta;
380 unsigned int length = 0;
381
382 if (cpu_data[cpu].next)
383 return cpu_data[cpu].next;
384
385 if (!page)
386 return NULL;
387
388 if (!idx) {
389 /* FIXME: handle header page */
390 if (header_page_ts_size != 8)
391 die("expected a long long type for timestamp");
392 cpu_data[cpu].timestamp = data2host8(ptr);
393 ptr += 8;
394 switch (header_page_size_size) {
395 case 4:
396 cpu_data[cpu].page_size = data2host4(ptr);
397 ptr += 4;
398 break;
399 case 8:
400 cpu_data[cpu].page_size = data2host8(ptr);
401 ptr += 8;
402 break;
403 default:
404 die("bad long size");
405 }
406 ptr = cpu_data[cpu].page + header_page_data_offset;
407 }
408
409 read_again:
410 idx = calc_index(ptr, cpu);
411
412 if (idx >= cpu_data[cpu].page_size) {
413 get_next_page(cpu);
414 return trace_peek_data(cpu);
415 }
416
417 type_len_ts = data2host4(ptr);
418 ptr += 4;
419
420 type_len = type_len4host(type_len_ts);
421 delta = ts4host(type_len_ts);
422
423 switch (type_len) {
424 case RINGBUF_TYPE_PADDING:
425 if (!delta)
426 die("error, hit unexpected end of page");
427 length = data2host4(ptr);
428 ptr += 4;
429 length *= 4;
430 ptr += length;
431 goto read_again;
432
433 case RINGBUF_TYPE_TIME_EXTEND:
434 extend = data2host4(ptr);
435 ptr += 4;
436 extend <<= TS_SHIFT;
437 extend += delta;
438 cpu_data[cpu].timestamp += extend;
439 goto read_again;
440
441 case RINGBUF_TYPE_TIME_STAMP:
442 ptr += 12;
443 break;
444 case 0:
445 length = data2host4(ptr);
446 ptr += 4;
447 die("here! length=%d", length);
448 break;
449 default:
450 length = type_len * 4;
451 break;
452 }
453
454 cpu_data[cpu].timestamp += delta;
455
456 data = malloc_or_die(sizeof(*data));
457 memset(data, 0, sizeof(*data));
458
459 data->ts = cpu_data[cpu].timestamp;
460 data->size = length;
461 data->data = ptr;
462 ptr += length;
463
464 cpu_data[cpu].index = calc_index(ptr, cpu);
465 cpu_data[cpu].next = data;
466
467 return data;
468 }
469
trace_read_data(int cpu)470 struct record *trace_read_data(int cpu)
471 {
472 struct record *data;
473
474 data = trace_peek_data(cpu);
475 cpu_data[cpu].next = NULL;
476
477 return data;
478 }
479
trace_report(int fd,bool __repipe)480 ssize_t trace_report(int fd, bool __repipe)
481 {
482 char buf[BUFSIZ];
483 char test[] = { 23, 8, 68 };
484 char *version;
485 int show_version = 0;
486 int show_funcs = 0;
487 int show_printk = 0;
488 ssize_t size;
489
490 calc_data_size = 1;
491 repipe = __repipe;
492
493 input_fd = fd;
494
495 read_or_die(buf, 3);
496 if (memcmp(buf, test, 3) != 0)
497 die("no trace data in the file");
498
499 read_or_die(buf, 7);
500 if (memcmp(buf, "tracing", 7) != 0)
501 die("not a trace file (missing 'tracing' tag)");
502
503 version = read_string();
504 if (show_version)
505 printf("version = %s\n", version);
506 free(version);
507
508 read_or_die(buf, 1);
509 file_bigendian = buf[0];
510 host_bigendian = bigendian();
511
512 read_or_die(buf, 1);
513 long_size = buf[0];
514
515 page_size = read4();
516
517 read_header_files();
518
519 read_ftrace_files();
520 read_event_files();
521 read_proc_kallsyms();
522 read_ftrace_printk();
523
524 size = calc_data_size - 1;
525 calc_data_size = 0;
526 repipe = false;
527
528 if (show_funcs) {
529 print_funcs();
530 return size;
531 }
532 if (show_printk) {
533 print_printk();
534 return size;
535 }
536
537 return size;
538 }
539