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