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