tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / 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 #include "util.h"
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 <errno.h>
35 #include <stdbool.h>
36 #include <linux/list.h>
37 #include <linux/kernel.h>
38
39 #include "../perf.h"
40 #include "trace-event.h"
41 #include <lk/debugfs.h>
42 #include "evsel.h"
43
44 #define VERSION "0.5"
45
46 static int output_fd;
47
48
49 static const char *find_debugfs(void)
50 {
51         const char *path = perf_debugfs_mount(NULL);
52
53         if (!path)
54                 pr_debug("Your kernel does not support the debugfs filesystem");
55
56         return path;
57 }
58
59 /*
60  * Finds the path to the debugfs/tracing
61  * Allocates the string and stores it.
62  */
63 static const char *find_tracing_dir(void)
64 {
65         static char *tracing;
66         static int tracing_found;
67         const char *debugfs;
68
69         if (tracing_found)
70                 return tracing;
71
72         debugfs = find_debugfs();
73         if (!debugfs)
74                 return NULL;
75
76         tracing = malloc(strlen(debugfs) + 9);
77         if (!tracing)
78                 return NULL;
79
80         sprintf(tracing, "%s/tracing", debugfs);
81
82         tracing_found = 1;
83         return tracing;
84 }
85
86 static char *get_tracing_file(const char *name)
87 {
88         const char *tracing;
89         char *file;
90
91         tracing = find_tracing_dir();
92         if (!tracing)
93                 return NULL;
94
95         file = malloc(strlen(tracing) + strlen(name) + 2);
96         if (!file)
97                 return NULL;
98
99         sprintf(file, "%s/%s", tracing, name);
100         return file;
101 }
102
103 static void put_tracing_file(char *file)
104 {
105         free(file);
106 }
107
108 int bigendian(void)
109 {
110         unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
111         unsigned int *ptr;
112
113         ptr = (unsigned int *)(void *)str;
114         return *ptr == 0x01020304;
115 }
116
117 /* unfortunately, you can not stat debugfs or proc files for size */
118 static int record_file(const char *file, ssize_t hdr_sz)
119 {
120         unsigned long long size = 0;
121         char buf[BUFSIZ], *sizep;
122         off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR);
123         int r, fd;
124         int err = -EIO;
125
126         fd = open(file, O_RDONLY);
127         if (fd < 0) {
128                 pr_debug("Can't read '%s'", file);
129                 return -errno;
130         }
131
132         /* put in zeros for file size, then fill true size later */
133         if (hdr_sz) {
134                 if (write(output_fd, &size, hdr_sz) != hdr_sz)
135                         goto out;
136         }
137
138         do {
139                 r = read(fd, buf, BUFSIZ);
140                 if (r > 0) {
141                         size += r;
142                         if (write(output_fd, buf, r) != r)
143                                 goto out;
144                 }
145         } while (r > 0);
146
147         /* ugh, handle big-endian hdr_size == 4 */
148         sizep = (char*)&size;
149         if (bigendian())
150                 sizep += sizeof(u64) - hdr_sz;
151
152         if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) {
153                 pr_debug("writing file size failed\n");
154                 goto out;
155         }
156
157         err = 0;
158 out:
159         close(fd);
160         return err;
161 }
162
163 static int read_header_files(void)
164 {
165         char *path;
166         struct stat st;
167         int err = -EIO;
168
169         path = get_tracing_file("events/header_page");
170         if (!path) {
171                 pr_debug("can't get tracing/events/header_page");
172                 return -ENOMEM;
173         }
174
175         if (stat(path, &st) < 0) {
176                 pr_debug("can't read '%s'", path);
177                 goto out;
178         }
179
180         if (write(output_fd, "header_page", 12) != 12) {
181                 pr_debug("can't write header_page\n");
182                 goto out;
183         }
184
185         if (record_file(path, 8) < 0) {
186                 pr_debug("can't record header_page file\n");
187                 goto out;
188         }
189
190         put_tracing_file(path);
191
192         path = get_tracing_file("events/header_event");
193         if (!path) {
194                 pr_debug("can't get tracing/events/header_event");
195                 err = -ENOMEM;
196                 goto out;
197         }
198
199         if (stat(path, &st) < 0) {
200                 pr_debug("can't read '%s'", path);
201                 goto out;
202         }
203
204         if (write(output_fd, "header_event", 13) != 13) {
205                 pr_debug("can't write header_event\n");
206                 goto out;
207         }
208
209         if (record_file(path, 8) < 0) {
210                 pr_debug("can't record header_event file\n");
211                 goto out;
212         }
213
214         err = 0;
215 out:
216         put_tracing_file(path);
217         return err;
218 }
219
220 static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
221 {
222         while (tps) {
223                 if (!strcmp(sys, tps->name))
224                         return true;
225                 tps = tps->next;
226         }
227
228         return false;
229 }
230
231 static int copy_event_system(const char *sys, struct tracepoint_path *tps)
232 {
233         struct dirent *dent;
234         struct stat st;
235         char *format;
236         DIR *dir;
237         int count = 0;
238         int ret;
239         int err;
240
241         dir = opendir(sys);
242         if (!dir) {
243                 pr_debug("can't read directory '%s'", sys);
244                 return -errno;
245         }
246
247         while ((dent = readdir(dir))) {
248                 if (dent->d_type != DT_DIR ||
249                     strcmp(dent->d_name, ".") == 0 ||
250                     strcmp(dent->d_name, "..") == 0 ||
251                     !name_in_tp_list(dent->d_name, tps))
252                         continue;
253                 format = malloc(strlen(sys) + strlen(dent->d_name) + 10);
254                 if (!format) {
255                         err = -ENOMEM;
256                         goto out;
257                 }
258                 sprintf(format, "%s/%s/format", sys, dent->d_name);
259                 ret = stat(format, &st);
260                 free(format);
261                 if (ret < 0)
262                         continue;
263                 count++;
264         }
265
266         if (write(output_fd, &count, 4) != 4) {
267                 err = -EIO;
268                 pr_debug("can't write count\n");
269                 goto out;
270         }
271
272         rewinddir(dir);
273         while ((dent = readdir(dir))) {
274                 if (dent->d_type != DT_DIR ||
275                     strcmp(dent->d_name, ".") == 0 ||
276                     strcmp(dent->d_name, "..") == 0 ||
277                     !name_in_tp_list(dent->d_name, tps))
278                         continue;
279                 format = malloc(strlen(sys) + strlen(dent->d_name) + 10);
280                 if (!format) {
281                         err = -ENOMEM;
282                         goto out;
283                 }
284                 sprintf(format, "%s/%s/format", sys, dent->d_name);
285                 ret = stat(format, &st);
286
287                 if (ret >= 0) {
288                         err = record_file(format, 8);
289                         if (err) {
290                                 free(format);
291                                 goto out;
292                         }
293                 }
294                 free(format);
295         }
296         err = 0;
297 out:
298         closedir(dir);
299         return err;
300 }
301
302 static int read_ftrace_files(struct tracepoint_path *tps)
303 {
304         char *path;
305         int ret;
306
307         path = get_tracing_file("events/ftrace");
308         if (!path) {
309                 pr_debug("can't get tracing/events/ftrace");
310                 return -ENOMEM;
311         }
312
313         ret = copy_event_system(path, tps);
314
315         put_tracing_file(path);
316
317         return ret;
318 }
319
320 static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
321 {
322         while (tps) {
323                 if (!strcmp(sys, tps->system))
324                         return true;
325                 tps = tps->next;
326         }
327
328         return false;
329 }
330
331 static int read_event_files(struct tracepoint_path *tps)
332 {
333         struct dirent *dent;
334         struct stat st;
335         char *path;
336         char *sys;
337         DIR *dir;
338         int count = 0;
339         int ret;
340         int err;
341
342         path = get_tracing_file("events");
343         if (!path) {
344                 pr_debug("can't get tracing/events");
345                 return -ENOMEM;
346         }
347
348         dir = opendir(path);
349         if (!dir) {
350                 err = -errno;
351                 pr_debug("can't read directory '%s'", path);
352                 goto out;
353         }
354
355         while ((dent = readdir(dir))) {
356                 if (dent->d_type != DT_DIR ||
357                     strcmp(dent->d_name, ".") == 0 ||
358                     strcmp(dent->d_name, "..") == 0 ||
359                     strcmp(dent->d_name, "ftrace") == 0 ||
360                     !system_in_tp_list(dent->d_name, tps))
361                         continue;
362                 count++;
363         }
364
365         if (write(output_fd, &count, 4) != 4) {
366                 err = -EIO;
367                 pr_debug("can't write count\n");
368                 goto out;
369         }
370
371         rewinddir(dir);
372         while ((dent = readdir(dir))) {
373                 if (dent->d_type != DT_DIR ||
374                     strcmp(dent->d_name, ".") == 0 ||
375                     strcmp(dent->d_name, "..") == 0 ||
376                     strcmp(dent->d_name, "ftrace") == 0 ||
377                     !system_in_tp_list(dent->d_name, tps))
378                         continue;
379                 sys = malloc(strlen(path) + strlen(dent->d_name) + 2);
380                 if (!sys) {
381                         err = -ENOMEM;
382                         goto out;
383                 }
384                 sprintf(sys, "%s/%s", path, dent->d_name);
385                 ret = stat(sys, &st);
386                 if (ret >= 0) {
387                         ssize_t size = strlen(dent->d_name) + 1;
388
389                         if (write(output_fd, dent->d_name, size) != size ||
390                             copy_event_system(sys, tps) < 0) {
391                                 err = -EIO;
392                                 free(sys);
393                                 goto out;
394                         }
395                 }
396                 free(sys);
397         }
398         err = 0;
399 out:
400         closedir(dir);
401         put_tracing_file(path);
402
403         return err;
404 }
405
406 static int read_proc_kallsyms(void)
407 {
408         unsigned int size;
409         const char *path = "/proc/kallsyms";
410         struct stat st;
411         int ret, err = 0;
412
413         ret = stat(path, &st);
414         if (ret < 0) {
415                 /* not found */
416                 size = 0;
417                 if (write(output_fd, &size, 4) != 4)
418                         err = -EIO;
419                 return err;
420         }
421         return record_file(path, 4);
422 }
423
424 static int read_ftrace_printk(void)
425 {
426         unsigned int size;
427         char *path;
428         struct stat st;
429         int ret, err = 0;
430
431         path = get_tracing_file("printk_formats");
432         if (!path) {
433                 pr_debug("can't get tracing/printk_formats");
434                 return -ENOMEM;
435         }
436
437         ret = stat(path, &st);
438         if (ret < 0) {
439                 /* not found */
440                 size = 0;
441                 if (write(output_fd, &size, 4) != 4)
442                         err = -EIO;
443                 goto out;
444         }
445         err = record_file(path, 4);
446
447 out:
448         put_tracing_file(path);
449         return err;
450 }
451
452 static void
453 put_tracepoints_path(struct tracepoint_path *tps)
454 {
455         while (tps) {
456                 struct tracepoint_path *t = tps;
457
458                 tps = tps->next;
459                 free(t->name);
460                 free(t->system);
461                 free(t);
462         }
463 }
464
465 static struct tracepoint_path *
466 get_tracepoints_path(struct list_head *pattrs)
467 {
468         struct tracepoint_path path, *ppath = &path;
469         struct perf_evsel *pos;
470         int nr_tracepoints = 0;
471
472         list_for_each_entry(pos, pattrs, node) {
473                 if (pos->attr.type != PERF_TYPE_TRACEPOINT)
474                         continue;
475                 ++nr_tracepoints;
476                 ppath->next = tracepoint_id_to_path(pos->attr.config);
477                 if (!ppath->next) {
478                         pr_debug("No memory to alloc tracepoints list\n");
479                         put_tracepoints_path(&path);
480                         return NULL;
481                 }
482                 ppath = ppath->next;
483         }
484
485         return nr_tracepoints > 0 ? path.next : NULL;
486 }
487
488 bool have_tracepoints(struct list_head *pattrs)
489 {
490         struct perf_evsel *pos;
491
492         list_for_each_entry(pos, pattrs, node)
493                 if (pos->attr.type == PERF_TYPE_TRACEPOINT)
494                         return true;
495
496         return false;
497 }
498
499 static int tracing_data_header(void)
500 {
501         char buf[20];
502         ssize_t size;
503
504         /* just guessing this is someone's birthday.. ;) */
505         buf[0] = 23;
506         buf[1] = 8;
507         buf[2] = 68;
508         memcpy(buf + 3, "tracing", 7);
509
510         if (write(output_fd, buf, 10) != 10)
511                 return -1;
512
513         size = strlen(VERSION) + 1;
514         if (write(output_fd, VERSION, size) != size)
515                 return -1;
516
517         /* save endian */
518         if (bigendian())
519                 buf[0] = 1;
520         else
521                 buf[0] = 0;
522
523         read_trace_init(buf[0], buf[0]);
524
525         if (write(output_fd, buf, 1) != 1)
526                 return -1;
527
528         /* save size of long */
529         buf[0] = sizeof(long);
530         if (write(output_fd, buf, 1) != 1)
531                 return -1;
532
533         /* save page_size */
534         if (write(output_fd, &page_size, 4) != 4)
535                 return -1;
536
537         return 0;
538 }
539
540 struct tracing_data *tracing_data_get(struct list_head *pattrs,
541                                       int fd, bool temp)
542 {
543         struct tracepoint_path *tps;
544         struct tracing_data *tdata;
545         int err;
546
547         output_fd = fd;
548
549         tps = get_tracepoints_path(pattrs);
550         if (!tps)
551                 return NULL;
552
553         tdata = malloc(sizeof(*tdata));
554         if (!tdata)
555                 return NULL;
556
557         tdata->temp = temp;
558         tdata->size = 0;
559
560         if (temp) {
561                 int temp_fd;
562
563                 snprintf(tdata->temp_file, sizeof(tdata->temp_file),
564                          "/tmp/perf-XXXXXX");
565                 if (!mkstemp(tdata->temp_file)) {
566                         pr_debug("Can't make temp file");
567                         return NULL;
568                 }
569
570                 temp_fd = open(tdata->temp_file, O_RDWR);
571                 if (temp_fd < 0) {
572                         pr_debug("Can't read '%s'", tdata->temp_file);
573                         return NULL;
574                 }
575
576                 /*
577                  * Set the temp file the default output, so all the
578                  * tracing data are stored into it.
579                  */
580                 output_fd = temp_fd;
581         }
582
583         err = tracing_data_header();
584         if (err)
585                 goto out;
586         err = read_header_files();
587         if (err)
588                 goto out;
589         err = read_ftrace_files(tps);
590         if (err)
591                 goto out;
592         err = read_event_files(tps);
593         if (err)
594                 goto out;
595         err = read_proc_kallsyms();
596         if (err)
597                 goto out;
598         err = read_ftrace_printk();
599
600 out:
601         /*
602          * All tracing data are stored by now, we can restore
603          * the default output file in case we used temp file.
604          */
605         if (temp) {
606                 tdata->size = lseek(output_fd, 0, SEEK_CUR);
607                 close(output_fd);
608                 output_fd = fd;
609         }
610
611         if (err) {
612                 free(tdata);
613                 tdata = NULL;
614         }
615
616         put_tracepoints_path(tps);
617         return tdata;
618 }
619
620 int tracing_data_put(struct tracing_data *tdata)
621 {
622         int err = 0;
623
624         if (tdata->temp) {
625                 err = record_file(tdata->temp_file, 0);
626                 unlink(tdata->temp_file);
627         }
628
629         free(tdata);
630         return err;
631 }
632
633 int read_tracing_data(int fd, struct list_head *pattrs)
634 {
635         int err;
636         struct tracing_data *tdata;
637
638         /*
639          * We work over the real file, so we can write data
640          * directly, no temp file is needed.
641          */
642         tdata = tracing_data_get(pattrs, fd, false);
643         if (!tdata)
644                 return -ENOMEM;
645
646         err = tracing_data_put(tdata);
647         return err;
648 }