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 write_or_die(const void *buf, size_t len)
158 {
159 	int ret;
160 
161 	ret = write(output_fd, buf, len);
162 	if (ret < 0)
163 		die("writing to '%s'", output_file);
164 
165 	return ret;
166 }
167 
168 int bigendian(void)
169 {
170 	unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
171 	unsigned int *ptr;
172 
173 	ptr = (unsigned int *)(void *)str;
174 	return *ptr == 0x01020304;
175 }
176 
177 static unsigned long long copy_file_fd(int fd)
178 {
179 	unsigned long long size = 0;
180 	char buf[BUFSIZ];
181 	int r;
182 
183 	do {
184 		r = read(fd, buf, BUFSIZ);
185 		if (r > 0) {
186 			size += r;
187 			write_or_die(buf, r);
188 		}
189 	} while (r > 0);
190 
191 	return size;
192 }
193 
194 static unsigned long long copy_file(const char *file)
195 {
196 	unsigned long long size = 0;
197 	int fd;
198 
199 	fd = open(file, O_RDONLY);
200 	if (fd < 0)
201 		die("Can't read '%s'", file);
202 	size = copy_file_fd(fd);
203 	close(fd);
204 
205 	return size;
206 }
207 
208 static unsigned long get_size_fd(int fd)
209 {
210 	unsigned long long size = 0;
211 	char buf[BUFSIZ];
212 	int r;
213 
214 	do {
215 		r = read(fd, buf, BUFSIZ);
216 		if (r > 0)
217 			size += r;
218 	} while (r > 0);
219 
220 	lseek(fd, 0, SEEK_SET);
221 
222 	return size;
223 }
224 
225 static unsigned long get_size(const char *file)
226 {
227 	unsigned long long size = 0;
228 	int fd;
229 
230 	fd = open(file, O_RDONLY);
231 	if (fd < 0)
232 		die("Can't read '%s'", file);
233 	size = get_size_fd(fd);
234 	close(fd);
235 
236 	return size;
237 }
238 
239 static void read_header_files(void)
240 {
241 	unsigned long long size, check_size;
242 	char *path;
243 	int fd;
244 
245 	path = get_tracing_file("events/header_page");
246 	fd = open(path, O_RDONLY);
247 	if (fd < 0)
248 		die("can't read '%s'", path);
249 
250 	/* unfortunately, you can not stat debugfs files for size */
251 	size = get_size_fd(fd);
252 
253 	write_or_die("header_page", 12);
254 	write_or_die(&size, 8);
255 	check_size = copy_file_fd(fd);
256 	close(fd);
257 
258 	if (size != check_size)
259 		die("wrong size for '%s' size=%lld read=%lld",
260 		    path, size, check_size);
261 	put_tracing_file(path);
262 
263 	path = get_tracing_file("events/header_event");
264 	fd = open(path, O_RDONLY);
265 	if (fd < 0)
266 		die("can't read '%s'", path);
267 
268 	size = get_size_fd(fd);
269 
270 	write_or_die("header_event", 13);
271 	write_or_die(&size, 8);
272 	check_size = copy_file_fd(fd);
273 	if (size != check_size)
274 		die("wrong size for '%s'", path);
275 	put_tracing_file(path);
276 	close(fd);
277 }
278 
279 static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
280 {
281 	while (tps) {
282 		if (!strcmp(sys, tps->name))
283 			return true;
284 		tps = tps->next;
285 	}
286 
287 	return false;
288 }
289 
290 static void copy_event_system(const char *sys, struct tracepoint_path *tps)
291 {
292 	unsigned long long size, check_size;
293 	struct dirent *dent;
294 	struct stat st;
295 	char *format;
296 	DIR *dir;
297 	int count = 0;
298 	int ret;
299 
300 	dir = opendir(sys);
301 	if (!dir)
302 		die("can't read directory '%s'", sys);
303 
304 	while ((dent = readdir(dir))) {
305 		if (dent->d_type != DT_DIR ||
306 		    strcmp(dent->d_name, ".") == 0 ||
307 		    strcmp(dent->d_name, "..") == 0 ||
308 		    !name_in_tp_list(dent->d_name, tps))
309 			continue;
310 		format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
311 		sprintf(format, "%s/%s/format", sys, dent->d_name);
312 		ret = stat(format, &st);
313 		free(format);
314 		if (ret < 0)
315 			continue;
316 		count++;
317 	}
318 
319 	write_or_die(&count, 4);
320 
321 	rewinddir(dir);
322 	while ((dent = readdir(dir))) {
323 		if (dent->d_type != DT_DIR ||
324 		    strcmp(dent->d_name, ".") == 0 ||
325 		    strcmp(dent->d_name, "..") == 0 ||
326 		    !name_in_tp_list(dent->d_name, tps))
327 			continue;
328 		format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
329 		sprintf(format, "%s/%s/format", sys, dent->d_name);
330 		ret = stat(format, &st);
331 
332 		if (ret >= 0) {
333 			/* unfortunately, you can not stat debugfs files for size */
334 			size = get_size(format);
335 			write_or_die(&size, 8);
336 			check_size = copy_file(format);
337 			if (size != check_size)
338 				die("error in size of file '%s'", format);
339 		}
340 
341 		free(format);
342 	}
343 	closedir(dir);
344 }
345 
346 static void read_ftrace_files(struct tracepoint_path *tps)
347 {
348 	char *path;
349 
350 	path = get_tracing_file("events/ftrace");
351 
352 	copy_event_system(path, tps);
353 
354 	put_tracing_file(path);
355 }
356 
357 static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
358 {
359 	while (tps) {
360 		if (!strcmp(sys, tps->system))
361 			return true;
362 		tps = tps->next;
363 	}
364 
365 	return false;
366 }
367 
368 static void read_event_files(struct tracepoint_path *tps)
369 {
370 	struct dirent *dent;
371 	struct stat st;
372 	char *path;
373 	char *sys;
374 	DIR *dir;
375 	int count = 0;
376 	int ret;
377 
378 	path = get_tracing_file("events");
379 
380 	dir = opendir(path);
381 	if (!dir)
382 		die("can't read directory '%s'", path);
383 
384 	while ((dent = readdir(dir))) {
385 		if (dent->d_type != DT_DIR ||
386 		    strcmp(dent->d_name, ".") == 0 ||
387 		    strcmp(dent->d_name, "..") == 0 ||
388 		    strcmp(dent->d_name, "ftrace") == 0 ||
389 		    !system_in_tp_list(dent->d_name, tps))
390 			continue;
391 		count++;
392 	}
393 
394 	write_or_die(&count, 4);
395 
396 	rewinddir(dir);
397 	while ((dent = readdir(dir))) {
398 		if (dent->d_type != DT_DIR ||
399 		    strcmp(dent->d_name, ".") == 0 ||
400 		    strcmp(dent->d_name, "..") == 0 ||
401 		    strcmp(dent->d_name, "ftrace") == 0 ||
402 		    !system_in_tp_list(dent->d_name, tps))
403 			continue;
404 		sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
405 		sprintf(sys, "%s/%s", path, dent->d_name);
406 		ret = stat(sys, &st);
407 		if (ret >= 0) {
408 			write_or_die(dent->d_name, strlen(dent->d_name) + 1);
409 			copy_event_system(sys, tps);
410 		}
411 		free(sys);
412 	}
413 
414 	closedir(dir);
415 	put_tracing_file(path);
416 }
417 
418 static void read_proc_kallsyms(void)
419 {
420 	unsigned int size, check_size;
421 	const char *path = "/proc/kallsyms";
422 	struct stat st;
423 	int ret;
424 
425 	ret = stat(path, &st);
426 	if (ret < 0) {
427 		/* not found */
428 		size = 0;
429 		write_or_die(&size, 4);
430 		return;
431 	}
432 	size = get_size(path);
433 	write_or_die(&size, 4);
434 	check_size = copy_file(path);
435 	if (size != check_size)
436 		die("error in size of file '%s'", path);
437 
438 }
439 
440 static void read_ftrace_printk(void)
441 {
442 	unsigned int size, check_size;
443 	char *path;
444 	struct stat st;
445 	int ret;
446 
447 	path = get_tracing_file("printk_formats");
448 	ret = stat(path, &st);
449 	if (ret < 0) {
450 		/* not found */
451 		size = 0;
452 		write_or_die(&size, 4);
453 		goto out;
454 	}
455 	size = get_size(path);
456 	write_or_die(&size, 4);
457 	check_size = copy_file(path);
458 	if (size != check_size)
459 		die("error in size of file '%s'", path);
460 out:
461 	put_tracing_file(path);
462 }
463 
464 static struct tracepoint_path *
465 get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
466 {
467 	struct tracepoint_path path, *ppath = &path;
468 	int i, nr_tracepoints = 0;
469 
470 	for (i = 0; i < nb_events; i++) {
471 		if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
472 			continue;
473 		++nr_tracepoints;
474 		ppath->next = tracepoint_id_to_path(pattrs[i].config);
475 		if (!ppath->next)
476 			die("%s\n", "No memory to alloc tracepoints list");
477 		ppath = ppath->next;
478 	}
479 
480 	return nr_tracepoints > 0 ? path.next : NULL;
481 }
482 
483 int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
484 {
485 	char buf[BUFSIZ];
486 	struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events);
487 
488 	/*
489 	 * What? No tracepoints? No sense writing anything here, bail out.
490 	 */
491 	if (tps == NULL)
492 		return -1;
493 
494 	output_fd = fd;
495 
496 	buf[0] = 23;
497 	buf[1] = 8;
498 	buf[2] = 68;
499 	memcpy(buf + 3, "tracing", 7);
500 
501 	write_or_die(buf, 10);
502 
503 	write_or_die(VERSION, strlen(VERSION) + 1);
504 
505 	/* save endian */
506 	if (bigendian())
507 		buf[0] = 1;
508 	else
509 		buf[0] = 0;
510 
511 	write_or_die(buf, 1);
512 
513 	/* save size of long */
514 	buf[0] = sizeof(long);
515 	write_or_die(buf, 1);
516 
517 	/* save page_size */
518 	page_size = sysconf(_SC_PAGESIZE);
519 	write_or_die(&page_size, 4);
520 
521 	read_header_files();
522 	read_ftrace_files(tps);
523 	read_event_files(tps);
524 	read_proc_kallsyms();
525 	read_ftrace_printk();
526 
527 	return 0;
528 }
529