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