Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2009, Steven Rostedt <srostedt (at) 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 static ssize_t trace_data_size;
     43 static bool repipe;
     44 
     45 static int __do_read(int fd, void *buf, int size)
     46 {
     47 	int rsize = size;
     48 
     49 	while (size) {
     50 		int ret = read(fd, buf, size);
     51 
     52 		if (ret <= 0)
     53 			return -1;
     54 
     55 		if (repipe) {
     56 			int retw = write(STDOUT_FILENO, buf, ret);
     57 
     58 			if (retw <= 0 || retw != ret) {
     59 				pr_debug("repiping input file");
     60 				return -1;
     61 			}
     62 		}
     63 
     64 		size -= ret;
     65 		buf += ret;
     66 	}
     67 
     68 	return rsize;
     69 }
     70 
     71 static int do_read(void *data, int size)
     72 {
     73 	int r;
     74 
     75 	r = __do_read(input_fd, data, size);
     76 	if (r <= 0) {
     77 		pr_debug("reading input file (size expected=%d received=%d)",
     78 			 size, r);
     79 		return -1;
     80 	}
     81 
     82 	trace_data_size += r;
     83 
     84 	return r;
     85 }
     86 
     87 /* If it fails, the next read will report it */
     88 static void skip(int size)
     89 {
     90 	char buf[BUFSIZ];
     91 	int r;
     92 
     93 	while (size) {
     94 		r = size > BUFSIZ ? BUFSIZ : size;
     95 		do_read(buf, r);
     96 		size -= r;
     97 	};
     98 }
     99 
    100 static unsigned int read4(struct pevent *pevent)
    101 {
    102 	unsigned int data;
    103 
    104 	if (do_read(&data, 4) < 0)
    105 		return 0;
    106 	return __data2host4(pevent, data);
    107 }
    108 
    109 static unsigned long long read8(struct pevent *pevent)
    110 {
    111 	unsigned long long data;
    112 
    113 	if (do_read(&data, 8) < 0)
    114 		return 0;
    115 	return __data2host8(pevent, data);
    116 }
    117 
    118 static char *read_string(void)
    119 {
    120 	char buf[BUFSIZ];
    121 	char *str = NULL;
    122 	int size = 0;
    123 	off_t r;
    124 	char c;
    125 
    126 	for (;;) {
    127 		r = read(input_fd, &c, 1);
    128 		if (r < 0) {
    129 			pr_debug("reading input file");
    130 			goto out;
    131 		}
    132 
    133 		if (!r) {
    134 			pr_debug("no data");
    135 			goto out;
    136 		}
    137 
    138 		if (repipe) {
    139 			int retw = write(STDOUT_FILENO, &c, 1);
    140 
    141 			if (retw <= 0 || retw != r) {
    142 				pr_debug("repiping input file string");
    143 				goto out;
    144 			}
    145 		}
    146 
    147 		buf[size++] = c;
    148 
    149 		if (!c)
    150 			break;
    151 	}
    152 
    153 	trace_data_size += size;
    154 
    155 	str = malloc(size);
    156 	if (str)
    157 		memcpy(str, buf, size);
    158 out:
    159 	return str;
    160 }
    161 
    162 static int read_proc_kallsyms(struct pevent *pevent)
    163 {
    164 	unsigned int size;
    165 	char *buf;
    166 
    167 	size = read4(pevent);
    168 	if (!size)
    169 		return 0;
    170 
    171 	buf = malloc(size + 1);
    172 	if (buf == NULL)
    173 		return -1;
    174 
    175 	if (do_read(buf, size) < 0) {
    176 		free(buf);
    177 		return -1;
    178 	}
    179 	buf[size] = '\0';
    180 
    181 	parse_proc_kallsyms(pevent, buf, size);
    182 
    183 	free(buf);
    184 	return 0;
    185 }
    186 
    187 static int read_ftrace_printk(struct pevent *pevent)
    188 {
    189 	unsigned int size;
    190 	char *buf;
    191 
    192 	/* it can have 0 size */
    193 	size = read4(pevent);
    194 	if (!size)
    195 		return 0;
    196 
    197 	buf = malloc(size);
    198 	if (buf == NULL)
    199 		return -1;
    200 
    201 	if (do_read(buf, size) < 0) {
    202 		free(buf);
    203 		return -1;
    204 	}
    205 
    206 	parse_ftrace_printk(pevent, buf, size);
    207 
    208 	free(buf);
    209 	return 0;
    210 }
    211 
    212 static int read_header_files(struct pevent *pevent)
    213 {
    214 	unsigned long long size;
    215 	char *header_page;
    216 	char buf[BUFSIZ];
    217 	int ret = 0;
    218 
    219 	if (do_read(buf, 12) < 0)
    220 		return -1;
    221 
    222 	if (memcmp(buf, "header_page", 12) != 0) {
    223 		pr_debug("did not read header page");
    224 		return -1;
    225 	}
    226 
    227 	size = read8(pevent);
    228 
    229 	header_page = malloc(size);
    230 	if (header_page == NULL)
    231 		return -1;
    232 
    233 	if (do_read(header_page, size) < 0) {
    234 		pr_debug("did not read header page");
    235 		free(header_page);
    236 		return -1;
    237 	}
    238 
    239 	if (!pevent_parse_header_page(pevent, header_page, size,
    240 				      pevent_get_long_size(pevent))) {
    241 		/*
    242 		 * The commit field in the page is of type long,
    243 		 * use that instead, since it represents the kernel.
    244 		 */
    245 		pevent_set_long_size(pevent, pevent->header_page_size_size);
    246 	}
    247 	free(header_page);
    248 
    249 	if (do_read(buf, 13) < 0)
    250 		return -1;
    251 
    252 	if (memcmp(buf, "header_event", 13) != 0) {
    253 		pr_debug("did not read header event");
    254 		return -1;
    255 	}
    256 
    257 	size = read8(pevent);
    258 	skip(size);
    259 
    260 	return ret;
    261 }
    262 
    263 static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
    264 {
    265 	char *buf;
    266 
    267 	buf = malloc(size);
    268 	if (buf == NULL)
    269 		return -1;
    270 
    271 	if (do_read(buf, size) < 0) {
    272 		free(buf);
    273 		return -1;
    274 	}
    275 
    276 	parse_ftrace_file(pevent, buf, size);
    277 	free(buf);
    278 	return 0;
    279 }
    280 
    281 static int read_event_file(struct pevent *pevent, char *sys,
    282 			    unsigned long long size)
    283 {
    284 	char *buf;
    285 
    286 	buf = malloc(size);
    287 	if (buf == NULL)
    288 		return -1;
    289 
    290 	if (do_read(buf, size) < 0) {
    291 		free(buf);
    292 		return -1;
    293 	}
    294 
    295 	parse_event_file(pevent, buf, size, sys);
    296 	free(buf);
    297 	return 0;
    298 }
    299 
    300 static int read_ftrace_files(struct pevent *pevent)
    301 {
    302 	unsigned long long size;
    303 	int count;
    304 	int i;
    305 	int ret;
    306 
    307 	count = read4(pevent);
    308 
    309 	for (i = 0; i < count; i++) {
    310 		size = read8(pevent);
    311 		ret = read_ftrace_file(pevent, size);
    312 		if (ret)
    313 			return ret;
    314 	}
    315 	return 0;
    316 }
    317 
    318 static int read_event_files(struct pevent *pevent)
    319 {
    320 	unsigned long long size;
    321 	char *sys;
    322 	int systems;
    323 	int count;
    324 	int i,x;
    325 	int ret;
    326 
    327 	systems = read4(pevent);
    328 
    329 	for (i = 0; i < systems; i++) {
    330 		sys = read_string();
    331 		if (sys == NULL)
    332 			return -1;
    333 
    334 		count = read4(pevent);
    335 
    336 		for (x=0; x < count; x++) {
    337 			size = read8(pevent);
    338 			ret = read_event_file(pevent, sys, size);
    339 			if (ret)
    340 				return ret;
    341 		}
    342 	}
    343 	return 0;
    344 }
    345 
    346 ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
    347 {
    348 	char buf[BUFSIZ];
    349 	char test[] = { 23, 8, 68 };
    350 	char *version;
    351 	int show_version = 0;
    352 	int show_funcs = 0;
    353 	int show_printk = 0;
    354 	ssize_t size = -1;
    355 	int file_bigendian;
    356 	int host_bigendian;
    357 	int file_long_size;
    358 	int file_page_size;
    359 	struct pevent *pevent;
    360 	int err;
    361 
    362 	*ppevent = NULL;
    363 
    364 	repipe = __repipe;
    365 	input_fd = fd;
    366 
    367 	if (do_read(buf, 3) < 0)
    368 		return -1;
    369 	if (memcmp(buf, test, 3) != 0) {
    370 		pr_debug("no trace data in the file");
    371 		return -1;
    372 	}
    373 
    374 	if (do_read(buf, 7) < 0)
    375 		return -1;
    376 	if (memcmp(buf, "tracing", 7) != 0) {
    377 		pr_debug("not a trace file (missing 'tracing' tag)");
    378 		return -1;
    379 	}
    380 
    381 	version = read_string();
    382 	if (version == NULL)
    383 		return -1;
    384 	if (show_version)
    385 		printf("version = %s\n", version);
    386 	free(version);
    387 
    388 	if (do_read(buf, 1) < 0)
    389 		return -1;
    390 	file_bigendian = buf[0];
    391 	host_bigendian = bigendian();
    392 
    393 	pevent = read_trace_init(file_bigendian, host_bigendian);
    394 	if (pevent == NULL) {
    395 		pr_debug("read_trace_init failed");
    396 		goto out;
    397 	}
    398 
    399 	if (do_read(buf, 1) < 0)
    400 		goto out;
    401 	file_long_size = buf[0];
    402 
    403 	file_page_size = read4(pevent);
    404 	if (!file_page_size)
    405 		goto out;
    406 
    407 	pevent_set_long_size(pevent, file_long_size);
    408 	pevent_set_page_size(pevent, file_page_size);
    409 
    410 	err = read_header_files(pevent);
    411 	if (err)
    412 		goto out;
    413 	err = read_ftrace_files(pevent);
    414 	if (err)
    415 		goto out;
    416 	err = read_event_files(pevent);
    417 	if (err)
    418 		goto out;
    419 	err = read_proc_kallsyms(pevent);
    420 	if (err)
    421 		goto out;
    422 	err = read_ftrace_printk(pevent);
    423 	if (err)
    424 		goto out;
    425 
    426 	size = trace_data_size;
    427 	repipe = false;
    428 
    429 	if (show_funcs) {
    430 		pevent_print_funcs(pevent);
    431 	} else if (show_printk) {
    432 		pevent_print_printk(pevent);
    433 	}
    434 
    435 	*ppevent = pevent;
    436 	pevent = NULL;
    437 
    438 out:
    439 	if (pevent)
    440 		pevent_free(pevent);
    441 	return size;
    442 }
    443