trace-event-info.c revision 7d82a4640abdcc3ffbd89c7971a11e4ac7953b7f
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
69unsigned int page_size;
70
71static const char *output_file = "trace.info";
72static int output_fd;
73
74struct event_list {
75	struct event_list *next;
76	const char *event;
77};
78
79struct events {
80	struct events *sibling;
81	struct events *children;
82	struct events *next;
83	char *name;
84};
85
86
87
88static 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
107void *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
117static 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 */
131static 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
150static 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
165static void put_tracing_file(char *file)
166{
167	free(file);
168}
169
170static ssize_t calc_data_size;
171
172static 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
188int 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
197static 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
214static 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
228static 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
245static 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
259static 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
299static 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
310static 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
366static 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
377static 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
388static 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
438static 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
460static 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);
480out:
481	put_tracing_file(path);
482}
483
484static struct tracepoint_path *
485get_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
504bool 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
515int 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
562ssize_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