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 
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 
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 */
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 
107 static unsigned int read4(void)
108 {
109 	unsigned int data;
110 
111 	read_or_die(&data, 4);
112 	return __data2host4(data);
113 }
114 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
365 static int calc_index(void *ptr, int cpu)
366 {
367 	return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
368 }
369 
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 
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 
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