• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008,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 _GNU_SOURCE
22 #include <dirent.h>
23 /* ANDROID_CHANGE_BEGIN */
24 #ifndef __APPLE__
25 #include <mntent.h>
26 #endif
27 /* ANDROID_CHANGE_END */
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/wait.h>
35 #include <pthread.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <stdbool.h>
41 /* ANDROID_CHANGE_BEGIN */
42 #if 0
43 #include <linux/list.h>
44 #include <linux/kernel.h>
45 #else
46 #include "include/linux/list.h"
47 #include "include/linux/kernel.h"
48 #endif
49 /* ANDROID_CHANGE_END */
50 
51 #include "../perf.h"
52 #include "trace-event.h"
53 #include "debugfs.h"
54 #include "evsel.h"
55 
56 #define VERSION "0.5"
57 
58 #define _STR(x) #x
59 #define STR(x) _STR(x)
60 #define MAX_PATH 256
61 
62 #define TRACE_CTRL	"tracing_on"
63 #define TRACE		"trace"
64 #define AVAILABLE	"available_tracers"
65 #define CURRENT		"current_tracer"
66 #define ITER_CTRL	"trace_options"
67 #define MAX_LATENCY	"tracing_max_latency"
68 
69 unsigned int page_size;
70 
71 static const char *output_file = "trace.info";
72 static int output_fd;
73 
74 struct event_list {
75 	struct event_list *next;
76 	const char *event;
77 };
78 
79 struct events {
80 	struct events *sibling;
81 	struct events *children;
82 	struct events *next;
83 	char *name;
84 };
85 
86 
87 
die(const char * fmt,...)88 static void die(const char *fmt, ...)
89 {
90 	va_list ap;
91 	int ret = errno;
92 
93 	if (errno)
94 		perror("trace-cmd");
95 	else
96 		ret = -1;
97 
98 	va_start(ap, fmt);
99 	fprintf(stderr, "  ");
100 	vfprintf(stderr, fmt, ap);
101 	va_end(ap);
102 
103 	fprintf(stderr, "\n");
104 	exit(ret);
105 }
106 
malloc_or_die(unsigned int size)107 void *malloc_or_die(unsigned int size)
108 {
109 	void *data;
110 
111 	data = malloc(size);
112 	if (!data)
113 		die("malloc");
114 	return data;
115 }
116 
find_debugfs(void)117 static const char *find_debugfs(void)
118 {
119 	const char *path = debugfs_mount(NULL);
120 
121 	if (!path)
122 		die("Your kernel not support debugfs filesystem");
123 
124 	return path;
125 }
126 
127 /*
128  * Finds the path to the debugfs/tracing
129  * Allocates the string and stores it.
130  */
find_tracing_dir(void)131 static const char *find_tracing_dir(void)
132 {
133 	static char *tracing;
134 	static int tracing_found;
135 	const char *debugfs;
136 
137 	if (tracing_found)
138 		return tracing;
139 
140 	debugfs = find_debugfs();
141 
142 	tracing = malloc_or_die(strlen(debugfs) + 9);
143 
144 	sprintf(tracing, "%s/tracing", debugfs);
145 
146 	tracing_found = 1;
147 	return tracing;
148 }
149 
get_tracing_file(const char * name)150 static char *get_tracing_file(const char *name)
151 {
152 	const char *tracing;
153 	char *file;
154 
155 	tracing = find_tracing_dir();
156 	if (!tracing)
157 		return NULL;
158 
159 	file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
160 
161 	sprintf(file, "%s/%s", tracing, name);
162 	return file;
163 }
164 
put_tracing_file(char * file)165 static void put_tracing_file(char *file)
166 {
167 	free(file);
168 }
169 
170 static ssize_t calc_data_size;
171 
write_or_die(const void * buf,size_t len)172 static ssize_t write_or_die(const void *buf, size_t len)
173 {
174 	int ret;
175 
176 	if (calc_data_size) {
177 		calc_data_size += len;
178 		return len;
179 	}
180 
181 	ret = write(output_fd, buf, len);
182 	if (ret < 0)
183 		die("writing to '%s'", output_file);
184 
185 	return ret;
186 }
187 
bigendian(void)188 int bigendian(void)
189 {
190 	unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
191 	unsigned int *ptr;
192 
193 	ptr = (unsigned int *)(void *)str;
194 	return *ptr == 0x01020304;
195 }
196 
copy_file_fd(int fd)197 static unsigned long long copy_file_fd(int fd)
198 {
199 	unsigned long long size = 0;
200 	char buf[BUFSIZ];
201 	int r;
202 
203 	do {
204 		r = read(fd, buf, BUFSIZ);
205 		if (r > 0) {
206 			size += r;
207 			write_or_die(buf, r);
208 		}
209 	} while (r > 0);
210 
211 	return size;
212 }
213 
copy_file(const char * file)214 static unsigned long long copy_file(const char *file)
215 {
216 	unsigned long long size = 0;
217 	int fd;
218 
219 	fd = open(file, O_RDONLY);
220 	if (fd < 0)
221 		die("Can't read '%s'", file);
222 	size = copy_file_fd(fd);
223 	close(fd);
224 
225 	return size;
226 }
227 
get_size_fd(int fd)228 static unsigned long get_size_fd(int fd)
229 {
230 	unsigned long long size = 0;
231 	char buf[BUFSIZ];
232 	int r;
233 
234 	do {
235 		r = read(fd, buf, BUFSIZ);
236 		if (r > 0)
237 			size += r;
238 	} while (r > 0);
239 
240 	lseek(fd, 0, SEEK_SET);
241 
242 	return size;
243 }
244 
get_size(const char * file)245 static unsigned long get_size(const char *file)
246 {
247 	unsigned long long size = 0;
248 	int fd;
249 
250 	fd = open(file, O_RDONLY);
251 	if (fd < 0)
252 		die("Can't read '%s'", file);
253 	size = get_size_fd(fd);
254 	close(fd);
255 
256 	return size;
257 }
258 
read_header_files(void)259 static void read_header_files(void)
260 {
261 	unsigned long long size, check_size;
262 	char *path;
263 	int fd;
264 
265 	path = get_tracing_file("events/header_page");
266 	fd = open(path, O_RDONLY);
267 	if (fd < 0)
268 		die("can't read '%s'", path);
269 
270 	/* unfortunately, you can not stat debugfs files for size */
271 	size = get_size_fd(fd);
272 
273 	write_or_die("header_page", 12);
274 	write_or_die(&size, 8);
275 	check_size = copy_file_fd(fd);
276 	close(fd);
277 
278 	if (size != check_size)
279 		die("wrong size for '%s' size=%lld read=%lld",
280 		    path, size, check_size);
281 	put_tracing_file(path);
282 
283 	path = get_tracing_file("events/header_event");
284 	fd = open(path, O_RDONLY);
285 	if (fd < 0)
286 		die("can't read '%s'", path);
287 
288 	size = get_size_fd(fd);
289 
290 	write_or_die("header_event", 13);
291 	write_or_die(&size, 8);
292 	check_size = copy_file_fd(fd);
293 	if (size != check_size)
294 		die("wrong size for '%s'", path);
295 	put_tracing_file(path);
296 	close(fd);
297 }
298 
name_in_tp_list(char * sys,struct tracepoint_path * tps)299 static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
300 {
301 	while (tps) {
302 		if (!strcmp(sys, tps->name))
303 			return true;
304 		tps = tps->next;
305 	}
306 
307 	return false;
308 }
309 
copy_event_system(const char * sys,struct tracepoint_path * tps)310 static void copy_event_system(const char *sys, struct tracepoint_path *tps)
311 {
312 	unsigned long long size, check_size;
313 	struct dirent *dent;
314 	struct stat st;
315 	char *format;
316 	DIR *dir;
317 	int count = 0;
318 	int ret;
319 
320 	dir = opendir(sys);
321 	if (!dir)
322 		die("can't read directory '%s'", sys);
323 
324 	while ((dent = readdir(dir))) {
325 		if (dent->d_type != DT_DIR ||
326 		    strcmp(dent->d_name, ".") == 0 ||
327 		    strcmp(dent->d_name, "..") == 0 ||
328 		    !name_in_tp_list(dent->d_name, tps))
329 			continue;
330 		format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
331 		sprintf(format, "%s/%s/format", sys, dent->d_name);
332 		ret = stat(format, &st);
333 		free(format);
334 		if (ret < 0)
335 			continue;
336 		count++;
337 	}
338 
339 	write_or_die(&count, 4);
340 
341 	rewinddir(dir);
342 	while ((dent = readdir(dir))) {
343 		if (dent->d_type != DT_DIR ||
344 		    strcmp(dent->d_name, ".") == 0 ||
345 		    strcmp(dent->d_name, "..") == 0 ||
346 		    !name_in_tp_list(dent->d_name, tps))
347 			continue;
348 		format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
349 		sprintf(format, "%s/%s/format", sys, dent->d_name);
350 		ret = stat(format, &st);
351 
352 		if (ret >= 0) {
353 			/* unfortunately, you can not stat debugfs files for size */
354 			size = get_size(format);
355 			write_or_die(&size, 8);
356 			check_size = copy_file(format);
357 			if (size != check_size)
358 				die("error in size of file '%s'", format);
359 		}
360 
361 		free(format);
362 	}
363 	closedir(dir);
364 }
365 
read_ftrace_files(struct tracepoint_path * tps)366 static void read_ftrace_files(struct tracepoint_path *tps)
367 {
368 	char *path;
369 
370 	path = get_tracing_file("events/ftrace");
371 
372 	copy_event_system(path, tps);
373 
374 	put_tracing_file(path);
375 }
376 
system_in_tp_list(char * sys,struct tracepoint_path * tps)377 static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
378 {
379 	while (tps) {
380 		if (!strcmp(sys, tps->system))
381 			return true;
382 		tps = tps->next;
383 	}
384 
385 	return false;
386 }
387 
read_event_files(struct tracepoint_path * tps)388 static void read_event_files(struct tracepoint_path *tps)
389 {
390 	struct dirent *dent;
391 	struct stat st;
392 	char *path;
393 	char *sys;
394 	DIR *dir;
395 	int count = 0;
396 	int ret;
397 
398 	path = get_tracing_file("events");
399 
400 	dir = opendir(path);
401 	if (!dir)
402 		die("can't read directory '%s'", path);
403 
404 	while ((dent = readdir(dir))) {
405 		if (dent->d_type != DT_DIR ||
406 		    strcmp(dent->d_name, ".") == 0 ||
407 		    strcmp(dent->d_name, "..") == 0 ||
408 		    strcmp(dent->d_name, "ftrace") == 0 ||
409 		    !system_in_tp_list(dent->d_name, tps))
410 			continue;
411 		count++;
412 	}
413 
414 	write_or_die(&count, 4);
415 
416 	rewinddir(dir);
417 	while ((dent = readdir(dir))) {
418 		if (dent->d_type != DT_DIR ||
419 		    strcmp(dent->d_name, ".") == 0 ||
420 		    strcmp(dent->d_name, "..") == 0 ||
421 		    strcmp(dent->d_name, "ftrace") == 0 ||
422 		    !system_in_tp_list(dent->d_name, tps))
423 			continue;
424 		sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
425 		sprintf(sys, "%s/%s", path, dent->d_name);
426 		ret = stat(sys, &st);
427 		if (ret >= 0) {
428 			write_or_die(dent->d_name, strlen(dent->d_name) + 1);
429 			copy_event_system(sys, tps);
430 		}
431 		free(sys);
432 	}
433 
434 	closedir(dir);
435 	put_tracing_file(path);
436 }
437 
read_proc_kallsyms(void)438 static void read_proc_kallsyms(void)
439 {
440 	unsigned int size, check_size;
441 	const char *path = "/proc/kallsyms";
442 	struct stat st;
443 	int ret;
444 
445 	ret = stat(path, &st);
446 	if (ret < 0) {
447 		/* not found */
448 		size = 0;
449 		write_or_die(&size, 4);
450 		return;
451 	}
452 	size = get_size(path);
453 	write_or_die(&size, 4);
454 	check_size = copy_file(path);
455 	if (size != check_size)
456 		die("error in size of file '%s'", path);
457 
458 }
459 
read_ftrace_printk(void)460 static void read_ftrace_printk(void)
461 {
462 	unsigned int size, check_size;
463 	char *path;
464 	struct stat st;
465 	int ret;
466 
467 	path = get_tracing_file("printk_formats");
468 	ret = stat(path, &st);
469 	if (ret < 0) {
470 		/* not found */
471 		size = 0;
472 		write_or_die(&size, 4);
473 		goto out;
474 	}
475 	size = get_size(path);
476 	write_or_die(&size, 4);
477 	check_size = copy_file(path);
478 	if (size != check_size)
479 		die("error in size of file '%s'", path);
480 out:
481 	put_tracing_file(path);
482 }
483 
484 static struct tracepoint_path *
get_tracepoints_path(struct list_head * pattrs)485 get_tracepoints_path(struct list_head *pattrs)
486 {
487 	struct tracepoint_path path, *ppath = &path;
488 	struct perf_evsel *pos;
489 	int nr_tracepoints = 0;
490 
491 	list_for_each_entry(pos, pattrs, node) {
492 		if (pos->attr.type != PERF_TYPE_TRACEPOINT)
493 			continue;
494 		++nr_tracepoints;
495 		ppath->next = tracepoint_id_to_path(pos->attr.config);
496 		if (!ppath->next)
497 			die("%s\n", "No memory to alloc tracepoints list");
498 		ppath = ppath->next;
499 	}
500 
501 	return nr_tracepoints > 0 ? path.next : NULL;
502 }
503 
have_tracepoints(struct list_head * pattrs)504 bool have_tracepoints(struct list_head *pattrs)
505 {
506 	struct perf_evsel *pos;
507 
508 	list_for_each_entry(pos, pattrs, node)
509 		if (pos->attr.type == PERF_TYPE_TRACEPOINT)
510 			return true;
511 
512 	return false;
513 }
514 
read_tracing_data(int fd,struct list_head * pattrs)515 int read_tracing_data(int fd, struct list_head *pattrs)
516 {
517 	char buf[BUFSIZ];
518 	struct tracepoint_path *tps = get_tracepoints_path(pattrs);
519 
520 	/*
521 	 * What? No tracepoints? No sense writing anything here, bail out.
522 	 */
523 	if (tps == NULL)
524 		return -1;
525 
526 	output_fd = fd;
527 
528 	buf[0] = 23;
529 	buf[1] = 8;
530 	buf[2] = 68;
531 	memcpy(buf + 3, "tracing", 7);
532 
533 	write_or_die(buf, 10);
534 
535 	write_or_die(VERSION, strlen(VERSION) + 1);
536 
537 	/* save endian */
538 	if (bigendian())
539 		buf[0] = 1;
540 	else
541 		buf[0] = 0;
542 
543 	write_or_die(buf, 1);
544 
545 	/* save size of long */
546 	buf[0] = sizeof(long);
547 	write_or_die(buf, 1);
548 
549 	/* save page_size */
550 	page_size = sysconf(_SC_PAGESIZE);
551 	write_or_die(&page_size, 4);
552 
553 	read_header_files();
554 	read_ftrace_files(tps);
555 	read_event_files(tps);
556 	read_proc_kallsyms();
557 	read_ftrace_printk();
558 
559 	return 0;
560 }
561 
read_tracing_data_size(int fd,struct list_head * pattrs)562 ssize_t read_tracing_data_size(int fd, struct list_head *pattrs)
563 {
564 	ssize_t size;
565 	int err = 0;
566 
567 	calc_data_size = 1;
568 	err = read_tracing_data(fd, pattrs);
569 	size = calc_data_size - 1;
570 	calc_data_size = 0;
571 
572 	if (err < 0)
573 		return err;
574 
575 	return size;
576 }
577