perf tools: Add trace event debugfs IO handler
[safe/jmp/linux-2.6] / tools / perf / util / trace-event-info.c
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 <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <pthread.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <ctype.h>
34 #include <errno.h>
35
36 #include "trace-event.h"
37
38
39 #define VERSION "0.5"
40
41 #define _STR(x) #x
42 #define STR(x) _STR(x)
43 #define MAX_PATH 256
44
45 #define TRACE_CTRL      "tracing_on"
46 #define TRACE           "trace"
47 #define AVAILABLE       "available_tracers"
48 #define CURRENT         "current_tracer"
49 #define ITER_CTRL       "trace_options"
50 #define MAX_LATENCY     "tracing_max_latency"
51
52 unsigned int page_size;
53
54 static const char *output_file = "trace.info";
55 static int output_fd;
56
57 struct event_list {
58         struct event_list *next;
59         const char *event;
60 };
61
62 struct events {
63         struct events *sibling;
64         struct events *children;
65         struct events *next;
66         char *name;
67 };
68
69
70
71 static void die(const char *fmt, ...)
72 {
73         va_list ap;
74         int ret = errno;
75
76         if (errno)
77                 perror("trace-cmd");
78         else
79                 ret = -1;
80
81         va_start(ap, fmt);
82         fprintf(stderr, "  ");
83         vfprintf(stderr, fmt, ap);
84         va_end(ap);
85
86         fprintf(stderr, "\n");
87         exit(ret);
88 }
89
90 void *malloc_or_die(unsigned int size)
91 {
92         void *data;
93
94         data = malloc(size);
95         if (!data)
96                 die("malloc");
97         return data;
98 }
99
100 static const char *find_debugfs(void)
101 {
102         static char debugfs[MAX_PATH+1];
103         static int debugfs_found;
104         char type[100];
105         FILE *fp;
106
107         if (debugfs_found)
108                 return debugfs;
109
110         if ((fp = fopen("/proc/mounts","r")) == NULL)
111                 die("Can't open /proc/mounts for read");
112
113         while (fscanf(fp, "%*s %"
114                       STR(MAX_PATH)
115                       "s %99s %*s %*d %*d\n",
116                       debugfs, type) == 2) {
117                 if (strcmp(type, "debugfs") == 0)
118                         break;
119         }
120         fclose(fp);
121
122         if (strcmp(type, "debugfs") != 0)
123                 die("debugfs not mounted, please mount");
124
125         debugfs_found = 1;
126
127         return debugfs;
128 }
129
130 /*
131  * Finds the path to the debugfs/tracing
132  * Allocates the string and stores it.
133  */
134 static const char *find_tracing_dir(void)
135 {
136         static char *tracing;
137         static int tracing_found;
138         const char *debugfs;
139
140         if (tracing_found)
141                 return tracing;
142
143         debugfs = find_debugfs();
144
145         tracing = malloc_or_die(strlen(debugfs) + 9);
146
147         sprintf(tracing, "%s/tracing", debugfs);
148
149         tracing_found = 1;
150         return tracing;
151 }
152
153 static char *get_tracing_file(const char *name)
154 {
155         const char *tracing;
156         char *file;
157
158         tracing = find_tracing_dir();
159         if (!tracing)
160                 return NULL;
161
162         file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
163
164         sprintf(file, "%s/%s", tracing, name);
165         return file;
166 }
167
168 static void put_tracing_file(char *file)
169 {
170         free(file);
171 }
172
173 static ssize_t write_or_die(const void *buf, size_t len)
174 {
175         int ret;
176
177         ret = write(output_fd, buf, len);
178         if (ret < 0)
179                 die("writing to '%s'", output_file);
180
181         return ret;
182 }
183
184 int bigendian(void)
185 {
186         unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
187         unsigned int *ptr;
188
189         ptr = (unsigned int *)str;
190         return *ptr == 0x01020304;
191 }
192
193 static unsigned long long copy_file_fd(int fd)
194 {
195         unsigned long long size = 0;
196         char buf[BUFSIZ];
197         int r;
198
199         do {
200                 r = read(fd, buf, BUFSIZ);
201                 if (r > 0) {
202                         size += r;
203                         write_or_die(buf, r);
204                 }
205         } while (r > 0);
206
207         return size;
208 }
209
210 static unsigned long long copy_file(const char *file)
211 {
212         unsigned long long size = 0;
213         int fd;
214
215         fd = open(file, O_RDONLY);
216         if (fd < 0)
217                 die("Can't read '%s'", file);
218         size = copy_file_fd(fd);
219         close(fd);
220
221         return size;
222 }
223
224 static unsigned long get_size_fd(int fd)
225 {
226         unsigned long long size = 0;
227         char buf[BUFSIZ];
228         int r;
229
230         do {
231                 r = read(fd, buf, BUFSIZ);
232                 if (r > 0)
233                         size += r;
234         } while (r > 0);
235
236         lseek(fd, 0, SEEK_SET);
237
238         return size;
239 }
240
241 static unsigned long get_size(const char *file)
242 {
243         unsigned long long size = 0;
244         int fd;
245
246         fd = open(file, O_RDONLY);
247         if (fd < 0)
248                 die("Can't read '%s'", file);
249         size = get_size_fd(fd);
250         close(fd);
251
252         return size;
253 }
254
255 static void read_header_files(void)
256 {
257         unsigned long long size, check_size;
258         char *path;
259         int fd;
260
261         path = get_tracing_file("events/header_page");
262         fd = open(path, O_RDONLY);
263         if (fd < 0)
264                 die("can't read '%s'", path);
265
266         /* unfortunately, you can not stat debugfs files for size */
267         size = get_size_fd(fd);
268
269         write_or_die("header_page", 12);
270         write_or_die(&size, 8);
271         check_size = copy_file_fd(fd);
272         if (size != check_size)
273                 die("wrong size for '%s' size=%lld read=%lld",
274                     path, size, check_size);
275         put_tracing_file(path);
276
277         path = get_tracing_file("events/header_event");
278         fd = open(path, O_RDONLY);
279         if (fd < 0)
280                 die("can't read '%s'", path);
281
282         size = get_size_fd(fd);
283
284         write_or_die("header_event", 13);
285         write_or_die(&size, 8);
286         check_size = copy_file_fd(fd);
287         if (size != check_size)
288                 die("wrong size for '%s'", path);
289         put_tracing_file(path);
290 }
291
292 static void copy_event_system(const char *sys)
293 {
294         unsigned long long size, check_size;
295         struct dirent *dent;
296         struct stat st;
297         char *format;
298         DIR *dir;
299         int count = 0;
300         int ret;
301
302         dir = opendir(sys);
303         if (!dir)
304                 die("can't read directory '%s'", sys);
305
306         while ((dent = readdir(dir))) {
307                 if (strcmp(dent->d_name, ".") == 0 ||
308                     strcmp(dent->d_name, "..") == 0)
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 (strcmp(dent->d_name, ".") == 0 ||
324                     strcmp(dent->d_name, "..") == 0)
325                         continue;
326                 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
327                 sprintf(format, "%s/%s/format", sys, dent->d_name);
328                 ret = stat(format, &st);
329
330                 if (ret >= 0) {
331                         /* unfortunately, you can not stat debugfs files for size */
332                         size = get_size(format);
333                         write_or_die(&size, 8);
334                         check_size = copy_file(format);
335                         if (size != check_size)
336                                 die("error in size of file '%s'", format);
337                 }
338
339                 free(format);
340         }
341 }
342
343 static void read_ftrace_files(void)
344 {
345         char *path;
346
347         path = get_tracing_file("events/ftrace");
348
349         copy_event_system(path);
350
351         put_tracing_file(path);
352 }
353
354 static void read_event_files(void)
355 {
356         struct dirent *dent;
357         struct stat st;
358         char *path;
359         char *sys;
360         DIR *dir;
361         int count = 0;
362         int ret;
363
364         path = get_tracing_file("events");
365
366         dir = opendir(path);
367         if (!dir)
368                 die("can't read directory '%s'", path);
369
370         while ((dent = readdir(dir))) {
371                 if (strcmp(dent->d_name, ".") == 0 ||
372                     strcmp(dent->d_name, "..") == 0 ||
373                     strcmp(dent->d_name, "ftrace") == 0)
374                         continue;
375                 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
376                 sprintf(sys, "%s/%s", path, dent->d_name);
377                 ret = stat(sys, &st);
378                 free(sys);
379                 if (ret < 0)
380                         continue;
381                 if (S_ISDIR(st.st_mode))
382                         count++;
383         }
384
385         write_or_die(&count, 4);
386
387         rewinddir(dir);
388         while ((dent = readdir(dir))) {
389                 if (strcmp(dent->d_name, ".") == 0 ||
390                     strcmp(dent->d_name, "..") == 0 ||
391                     strcmp(dent->d_name, "ftrace") == 0)
392                         continue;
393                 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
394                 sprintf(sys, "%s/%s", path, dent->d_name);
395                 ret = stat(sys, &st);
396                 if (ret >= 0) {
397                         if (S_ISDIR(st.st_mode)) {
398                                 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
399                                 copy_event_system(sys);
400                         }
401                 }
402                 free(sys);
403         }
404
405         put_tracing_file(path);
406 }
407
408 static void read_proc_kallsyms(void)
409 {
410         unsigned int size, check_size;
411         const char *path = "/proc/kallsyms";
412         struct stat st;
413         int ret;
414
415         ret = stat(path, &st);
416         if (ret < 0) {
417                 /* not found */
418                 size = 0;
419                 write_or_die(&size, 4);
420                 return;
421         }
422         size = get_size(path);
423         write_or_die(&size, 4);
424         check_size = copy_file(path);
425         if (size != check_size)
426                 die("error in size of file '%s'", path);
427
428 }
429
430 static void read_ftrace_printk(void)
431 {
432         unsigned int size, check_size;
433         const char *path;
434         struct stat st;
435         int ret;
436
437         path = get_tracing_file("printk_formats");
438         ret = stat(path, &st);
439         if (ret < 0) {
440                 /* not found */
441                 size = 0;
442                 write_or_die(&size, 4);
443                 return;
444         }
445         size = get_size(path);
446         write_or_die(&size, 4);
447         check_size = copy_file(path);
448         if (size != check_size)
449                 die("error in size of file '%s'", path);
450
451 }
452
453 void read_tracing_data(void)
454 {
455         char buf[BUFSIZ];
456
457         output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
458         if (output_fd < 0)
459                 die("creating file '%s'", output_file);
460
461         buf[0] = 23;
462         buf[1] = 8;
463         buf[2] = 68;
464         memcpy(buf + 3, "tracing", 7);
465
466         write_or_die(buf, 10);
467
468         write_or_die(VERSION, strlen(VERSION) + 1);
469
470         /* save endian */
471         if (bigendian())
472                 buf[0] = 1;
473         else
474                 buf[0] = 0;
475
476         write_or_die(buf, 1);
477
478         /* save size of long */
479         buf[0] = sizeof(long);
480         write_or_die(buf, 1);
481
482         /* save page_size */
483         page_size = getpagesize();
484         write_or_die(&page_size, 4);
485
486         read_header_files();
487         read_ftrace_files();
488         read_event_files();
489         read_proc_kallsyms();
490         read_ftrace_printk();
491 }