2bb2bdb1f4565eb2cf4492844910dbc9f0e97503
[safe/jmp/linux-2.6] / tools / perf / util / header.c
1 #include <sys/types.h>
2 #include <byteswap.h>
3 #include <unistd.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <linux/list.h>
7 #include <linux/kernel.h>
8
9 #include "util.h"
10 #include "header.h"
11 #include "../perf.h"
12 #include "trace-event.h"
13 #include "session.h"
14 #include "symbol.h"
15 #include "debug.h"
16
17 /*
18  * Create new perf.data header attribute:
19  */
20 struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
21 {
22         struct perf_header_attr *self = malloc(sizeof(*self));
23
24         if (self != NULL) {
25                 self->attr = *attr;
26                 self->ids  = 0;
27                 self->size = 1;
28                 self->id   = malloc(sizeof(u64));
29                 if (self->id == NULL) {
30                         free(self);
31                         self = NULL;
32                 }
33         }
34
35         return self;
36 }
37
38 void perf_header_attr__delete(struct perf_header_attr *self)
39 {
40         free(self->id);
41         free(self);
42 }
43
44 int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
45 {
46         int pos = self->ids;
47
48         self->ids++;
49         if (self->ids > self->size) {
50                 int nsize = self->size * 2;
51                 u64 *nid = realloc(self->id, nsize * sizeof(u64));
52
53                 if (nid == NULL)
54                         return -1;
55
56                 self->size = nsize;
57                 self->id = nid;
58         }
59         self->id[pos] = id;
60         return 0;
61 }
62
63 int perf_header__init(struct perf_header *self)
64 {
65         self->size = 1;
66         self->attr = malloc(sizeof(void *));
67         return self->attr == NULL ? -ENOMEM : 0;
68 }
69
70 void perf_header__exit(struct perf_header *self)
71 {
72         int i;
73         for (i = 0; i < self->attrs; ++i)
74                 perf_header_attr__delete(self->attr[i]);
75         free(self->attr);
76 }
77
78 int perf_header__add_attr(struct perf_header *self,
79                           struct perf_header_attr *attr)
80 {
81         if (self->frozen)
82                 return -1;
83
84         if (self->attrs == self->size) {
85                 int nsize = self->size * 2;
86                 struct perf_header_attr **nattr;
87
88                 nattr = realloc(self->attr, nsize * sizeof(void *));
89                 if (nattr == NULL)
90                         return -1;
91
92                 self->size = nsize;
93                 self->attr = nattr;
94         }
95
96         self->attr[self->attrs++] = attr;
97         return 0;
98 }
99
100 #define MAX_EVENT_NAME 64
101
102 struct perf_trace_event_type {
103         u64     event_id;
104         char    name[MAX_EVENT_NAME];
105 };
106
107 static int event_count;
108 static struct perf_trace_event_type *events;
109
110 int perf_header__push_event(u64 id, const char *name)
111 {
112         if (strlen(name) > MAX_EVENT_NAME)
113                 pr_warning("Event %s will be truncated\n", name);
114
115         if (!events) {
116                 events = malloc(sizeof(struct perf_trace_event_type));
117                 if (events == NULL)
118                         return -ENOMEM;
119         } else {
120                 struct perf_trace_event_type *nevents;
121
122                 nevents = realloc(events, (event_count + 1) * sizeof(*events));
123                 if (nevents == NULL)
124                         return -ENOMEM;
125                 events = nevents;
126         }
127         memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
128         events[event_count].event_id = id;
129         strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
130         event_count++;
131         return 0;
132 }
133
134 char *perf_header__find_event(u64 id)
135 {
136         int i;
137         for (i = 0 ; i < event_count; i++) {
138                 if (events[i].event_id == id)
139                         return events[i].name;
140         }
141         return NULL;
142 }
143
144 static const char *__perf_magic = "PERFFILE";
145
146 #define PERF_MAGIC      (*(u64 *)__perf_magic)
147
148 struct perf_file_attr {
149         struct perf_event_attr  attr;
150         struct perf_file_section        ids;
151 };
152
153 void perf_header__set_feat(struct perf_header *self, int feat)
154 {
155         set_bit(feat, self->adds_features);
156 }
157
158 bool perf_header__has_feat(const struct perf_header *self, int feat)
159 {
160         return test_bit(feat, self->adds_features);
161 }
162
163 static int do_write(int fd, const void *buf, size_t size)
164 {
165         while (size) {
166                 int ret = write(fd, buf, size);
167
168                 if (ret < 0)
169                         return -errno;
170
171                 size -= ret;
172                 buf += ret;
173         }
174
175         return 0;
176 }
177
178 #define NAME_ALIGN 64
179
180 static int write_padded(int fd, const void *bf, size_t count,
181                         size_t count_aligned)
182 {
183         static const char zero_buf[NAME_ALIGN];
184         int err = do_write(fd, bf, count);
185
186         if (!err)
187                 err = do_write(fd, zero_buf, count_aligned - count);
188
189         return err;
190 }
191
192 #define dsos__for_each_with_build_id(pos, head) \
193         list_for_each_entry(pos, head, node)    \
194                 if (!pos->has_build_id)         \
195                         continue;               \
196                 else
197
198 static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
199 {
200         struct dso *pos;
201
202         dsos__for_each_with_build_id(pos, head) {
203                 int err;
204                 struct build_id_event b;
205                 size_t len = pos->long_name_len + 1;
206
207                 len = ALIGN(len, NAME_ALIGN);
208                 memset(&b, 0, sizeof(b));
209                 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
210                 b.header.misc = misc;
211                 b.header.size = sizeof(b) + len;
212                 err = do_write(fd, &b, sizeof(b));
213                 if (err < 0)
214                         return err;
215                 err = write_padded(fd, pos->long_name,
216                                    pos->long_name_len + 1, len);
217                 if (err < 0)
218                         return err;
219         }
220
221         return 0;
222 }
223
224 static int dsos__write_buildid_table(int fd)
225 {
226         int err = __dsos__write_buildid_table(&dsos__kernel,
227                                               PERF_RECORD_MISC_KERNEL, fd);
228         if (err == 0)
229                 err = __dsos__write_buildid_table(&dsos__user,
230                                                   PERF_RECORD_MISC_USER, fd);
231         return err;
232 }
233
234 int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
235                           const char *name, bool is_kallsyms)
236 {
237         const size_t size = PATH_MAX;
238         char *filename = malloc(size),
239              *linkname = malloc(size), *targetname;
240         int len, err = -1;
241
242         if (filename == NULL || linkname == NULL)
243                 goto out_free;
244
245         len = snprintf(filename, size, "%s%s%s",
246                        debugdir, is_kallsyms ? "/" : "", name);
247         if (mkdir_p(filename, 0755))
248                 goto out_free;
249
250         snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
251
252         if (access(filename, F_OK)) {
253                 if (is_kallsyms) {
254                          if (copyfile("/proc/kallsyms", filename))
255                                 goto out_free;
256                 } else if (link(name, filename) && copyfile(name, filename))
257                         goto out_free;
258         }
259
260         len = snprintf(linkname, size, "%s/.build-id/%.2s",
261                        debugdir, sbuild_id);
262
263         if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
264                 goto out_free;
265
266         snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
267         targetname = filename + strlen(debugdir) - 5;
268         memcpy(targetname, "../..", 5);
269
270         if (symlink(targetname, linkname) == 0)
271                 err = 0;
272 out_free:
273         free(filename);
274         free(linkname);
275         return err;
276 }
277
278 static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
279                                  const char *name, const char *debugdir,
280                                  bool is_kallsyms)
281 {
282         char sbuild_id[BUILD_ID_SIZE * 2 + 1];
283
284         build_id__sprintf(build_id, build_id_size, sbuild_id);
285
286         return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
287 }
288
289 int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
290 {
291         const size_t size = PATH_MAX;
292         char *filename = malloc(size),
293              *linkname = malloc(size);
294         int err = -1;
295
296         if (filename == NULL || linkname == NULL)
297                 goto out_free;
298
299         snprintf(linkname, size, "%s/.build-id/%.2s/%s",
300                  debugdir, sbuild_id, sbuild_id + 2);
301
302         if (access(linkname, F_OK))
303                 goto out_free;
304
305         if (readlink(linkname, filename, size) < 0)
306                 goto out_free;
307
308         if (unlink(linkname))
309                 goto out_free;
310
311         /*
312          * Since the link is relative, we must make it absolute:
313          */
314         snprintf(linkname, size, "%s/.build-id/%.2s/%s",
315                  debugdir, sbuild_id, filename);
316
317         if (unlink(linkname))
318                 goto out_free;
319
320         err = 0;
321 out_free:
322         free(filename);
323         free(linkname);
324         return err;
325 }
326
327 static int dso__cache_build_id(struct dso *self, const char *debugdir)
328 {
329         bool is_kallsyms = self->kernel && self->long_name[0] != '/';
330
331         return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
332                                      self->long_name, debugdir, is_kallsyms);
333 }
334
335 static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
336 {
337         struct dso *pos;
338         int err = 0;
339
340         dsos__for_each_with_build_id(pos, head)
341                 if (dso__cache_build_id(pos, debugdir))
342                         err = -1;
343
344         return err;
345 }
346
347 static int dsos__cache_build_ids(void)
348 {
349         int err_kernel, err_user;
350         char debugdir[PATH_MAX];
351
352         snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
353                  DEBUG_CACHE_DIR);
354
355         if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
356                 return -1;
357
358         err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
359         err_user   = __dsos__cache_build_ids(&dsos__user, debugdir);
360         return err_kernel || err_user ? -1 : 0;
361 }
362
363 static int perf_header__adds_write(struct perf_header *self, int fd)
364 {
365         int nr_sections;
366         struct perf_file_section *feat_sec;
367         int sec_size;
368         u64 sec_start;
369         int idx = 0, err;
370
371         if (dsos__read_build_ids())
372                 perf_header__set_feat(self, HEADER_BUILD_ID);
373
374         nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
375         if (!nr_sections)
376                 return 0;
377
378         feat_sec = calloc(sizeof(*feat_sec), nr_sections);
379         if (feat_sec == NULL)
380                 return -ENOMEM;
381
382         sec_size = sizeof(*feat_sec) * nr_sections;
383
384         sec_start = self->data_offset + self->data_size;
385         lseek(fd, sec_start + sec_size, SEEK_SET);
386
387         if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
388                 struct perf_file_section *trace_sec;
389
390                 trace_sec = &feat_sec[idx++];
391
392                 /* Write trace info */
393                 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
394                 read_tracing_data(fd, attrs, nr_counters);
395                 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
396         }
397
398
399         if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
400                 struct perf_file_section *buildid_sec;
401
402                 buildid_sec = &feat_sec[idx++];
403
404                 /* Write build-ids */
405                 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
406                 err = dsos__write_buildid_table(fd);
407                 if (err < 0) {
408                         pr_debug("failed to write buildid table\n");
409                         goto out_free;
410                 }
411                 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
412                 dsos__cache_build_ids();
413         }
414
415         lseek(fd, sec_start, SEEK_SET);
416         err = do_write(fd, feat_sec, sec_size);
417         if (err < 0)
418                 pr_debug("failed to write feature section\n");
419 out_free:
420         free(feat_sec);
421         return err;
422 }
423
424 int perf_header__write(struct perf_header *self, int fd, bool at_exit)
425 {
426         struct perf_file_header f_header;
427         struct perf_file_attr   f_attr;
428         struct perf_header_attr *attr;
429         int i, err;
430
431         lseek(fd, sizeof(f_header), SEEK_SET);
432
433
434         for (i = 0; i < self->attrs; i++) {
435                 attr = self->attr[i];
436
437                 attr->id_offset = lseek(fd, 0, SEEK_CUR);
438                 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
439                 if (err < 0) {
440                         pr_debug("failed to write perf header\n");
441                         return err;
442                 }
443         }
444
445
446         self->attr_offset = lseek(fd, 0, SEEK_CUR);
447
448         for (i = 0; i < self->attrs; i++) {
449                 attr = self->attr[i];
450
451                 f_attr = (struct perf_file_attr){
452                         .attr = attr->attr,
453                         .ids  = {
454                                 .offset = attr->id_offset,
455                                 .size   = attr->ids * sizeof(u64),
456                         }
457                 };
458                 err = do_write(fd, &f_attr, sizeof(f_attr));
459                 if (err < 0) {
460                         pr_debug("failed to write perf header attribute\n");
461                         return err;
462                 }
463         }
464
465         self->event_offset = lseek(fd, 0, SEEK_CUR);
466         self->event_size = event_count * sizeof(struct perf_trace_event_type);
467         if (events) {
468                 err = do_write(fd, events, self->event_size);
469                 if (err < 0) {
470                         pr_debug("failed to write perf header events\n");
471                         return err;
472                 }
473         }
474
475         self->data_offset = lseek(fd, 0, SEEK_CUR);
476
477         if (at_exit) {
478                 err = perf_header__adds_write(self, fd);
479                 if (err < 0)
480                         return err;
481         }
482
483         f_header = (struct perf_file_header){
484                 .magic     = PERF_MAGIC,
485                 .size      = sizeof(f_header),
486                 .attr_size = sizeof(f_attr),
487                 .attrs = {
488                         .offset = self->attr_offset,
489                         .size   = self->attrs * sizeof(f_attr),
490                 },
491                 .data = {
492                         .offset = self->data_offset,
493                         .size   = self->data_size,
494                 },
495                 .event_types = {
496                         .offset = self->event_offset,
497                         .size   = self->event_size,
498                 },
499         };
500
501         memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
502
503         lseek(fd, 0, SEEK_SET);
504         err = do_write(fd, &f_header, sizeof(f_header));
505         if (err < 0) {
506                 pr_debug("failed to write perf header\n");
507                 return err;
508         }
509         lseek(fd, self->data_offset + self->data_size, SEEK_SET);
510
511         self->frozen = 1;
512         return 0;
513 }
514
515 static int do_read(int fd, void *buf, size_t size)
516 {
517         while (size) {
518                 int ret = read(fd, buf, size);
519
520                 if (ret <= 0)
521                         return -1;
522
523                 size -= ret;
524                 buf += ret;
525         }
526
527         return 0;
528 }
529
530 static int perf_header__getbuffer64(struct perf_header *self,
531                                     int fd, void *buf, size_t size)
532 {
533         if (do_read(fd, buf, size))
534                 return -1;
535
536         if (self->needs_swap)
537                 mem_bswap_64(buf, size);
538
539         return 0;
540 }
541
542 int perf_header__process_sections(struct perf_header *self, int fd,
543                                   int (*process)(struct perf_file_section *self,
544                                                  struct perf_header *ph,
545                                                  int feat, int fd))
546 {
547         struct perf_file_section *feat_sec;
548         int nr_sections;
549         int sec_size;
550         int idx = 0;
551         int err = -1, feat = 1;
552
553         nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
554         if (!nr_sections)
555                 return 0;
556
557         feat_sec = calloc(sizeof(*feat_sec), nr_sections);
558         if (!feat_sec)
559                 return -1;
560
561         sec_size = sizeof(*feat_sec) * nr_sections;
562
563         lseek(fd, self->data_offset + self->data_size, SEEK_SET);
564
565         if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
566                 goto out_free;
567
568         err = 0;
569         while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
570                 if (perf_header__has_feat(self, feat)) {
571                         struct perf_file_section *sec = &feat_sec[idx++];
572
573                         err = process(sec, self, feat, fd);
574                         if (err < 0)
575                                 break;
576                 }
577                 ++feat;
578         }
579 out_free:
580         free(feat_sec);
581         return err;
582 }
583
584 int perf_file_header__read(struct perf_file_header *self,
585                            struct perf_header *ph, int fd)
586 {
587         lseek(fd, 0, SEEK_SET);
588
589         if (do_read(fd, self, sizeof(*self)) ||
590             memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
591                 return -1;
592
593         if (self->attr_size != sizeof(struct perf_file_attr)) {
594                 u64 attr_size = bswap_64(self->attr_size);
595
596                 if (attr_size != sizeof(struct perf_file_attr))
597                         return -1;
598
599                 mem_bswap_64(self, offsetof(struct perf_file_header,
600                                             adds_features));
601                 ph->needs_swap = true;
602         }
603
604         if (self->size != sizeof(*self)) {
605                 /* Support the previous format */
606                 if (self->size == offsetof(typeof(*self), adds_features))
607                         bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
608                 else
609                         return -1;
610         }
611
612         memcpy(&ph->adds_features, &self->adds_features,
613                sizeof(ph->adds_features));
614         /*
615          * FIXME: hack that assumes that if we need swap the perf.data file
616          * may be coming from an arch with a different word-size, ergo different
617          * DEFINE_BITMAP format, investigate more later, but for now its mostly
618          * safe to assume that we have a build-id section. Trace files probably
619          * have several other issues in this realm anyway...
620          */
621         if (ph->needs_swap) {
622                 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
623                 perf_header__set_feat(ph, HEADER_BUILD_ID);
624         }
625
626         ph->event_offset = self->event_types.offset;
627         ph->event_size   = self->event_types.size;
628         ph->data_offset  = self->data.offset;
629         ph->data_size    = self->data.size;
630         return 0;
631 }
632
633 static int perf_file_section__process(struct perf_file_section *self,
634                                       struct perf_header *ph,
635                                       int feat, int fd)
636 {
637         if (lseek(fd, self->offset, SEEK_SET) < 0) {
638                 pr_debug("Failed to lseek to %Ld offset for feature %d, "
639                          "continuing...\n", self->offset, feat);
640                 return 0;
641         }
642
643         switch (feat) {
644         case HEADER_TRACE_INFO:
645                 trace_report(fd);
646                 break;
647
648         case HEADER_BUILD_ID:
649                 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
650                         pr_debug("Failed to read buildids, continuing...\n");
651                 break;
652         default:
653                 pr_debug("unknown feature %d, continuing...\n", feat);
654         }
655
656         return 0;
657 }
658
659 int perf_header__read(struct perf_header *self, int fd)
660 {
661         struct perf_file_header f_header;
662         struct perf_file_attr   f_attr;
663         u64                     f_id;
664         int nr_attrs, nr_ids, i, j;
665
666         if (perf_file_header__read(&f_header, self, fd) < 0) {
667                 pr_debug("incompatible file format\n");
668                 return -EINVAL;
669         }
670
671         nr_attrs = f_header.attrs.size / sizeof(f_attr);
672         lseek(fd, f_header.attrs.offset, SEEK_SET);
673
674         for (i = 0; i < nr_attrs; i++) {
675                 struct perf_header_attr *attr;
676                 off_t tmp;
677
678                 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
679                         goto out_errno;
680
681                 tmp = lseek(fd, 0, SEEK_CUR);
682
683                 attr = perf_header_attr__new(&f_attr.attr);
684                 if (attr == NULL)
685                          return -ENOMEM;
686
687                 nr_ids = f_attr.ids.size / sizeof(u64);
688                 lseek(fd, f_attr.ids.offset, SEEK_SET);
689
690                 for (j = 0; j < nr_ids; j++) {
691                         if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
692                                 goto out_errno;
693
694                         if (perf_header_attr__add_id(attr, f_id) < 0) {
695                                 perf_header_attr__delete(attr);
696                                 return -ENOMEM;
697                         }
698                 }
699                 if (perf_header__add_attr(self, attr) < 0) {
700                         perf_header_attr__delete(attr);
701                         return -ENOMEM;
702                 }
703
704                 lseek(fd, tmp, SEEK_SET);
705         }
706
707         if (f_header.event_types.size) {
708                 lseek(fd, f_header.event_types.offset, SEEK_SET);
709                 events = malloc(f_header.event_types.size);
710                 if (events == NULL)
711                         return -ENOMEM;
712                 if (perf_header__getbuffer64(self, fd, events,
713                                              f_header.event_types.size))
714                         goto out_errno;
715                 event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
716         }
717
718         perf_header__process_sections(self, fd, perf_file_section__process);
719
720         lseek(fd, self->data_offset, SEEK_SET);
721
722         self->frozen = 1;
723         return 0;
724 out_errno:
725         return -errno;
726 }
727
728 u64 perf_header__sample_type(struct perf_header *header)
729 {
730         u64 type = 0;
731         int i;
732
733         for (i = 0; i < header->attrs; i++) {
734                 struct perf_header_attr *attr = header->attr[i];
735
736                 if (!type)
737                         type = attr->attr.sample_type;
738                 else if (type != attr->attr.sample_type)
739                         die("non matching sample_type");
740         }
741
742         return type;
743 }
744
745 struct perf_event_attr *
746 perf_header__find_attr(u64 id, struct perf_header *header)
747 {
748         int i;
749
750         for (i = 0; i < header->attrs; i++) {
751                 struct perf_header_attr *attr = header->attr[i];
752                 int j;
753
754                 for (j = 0; j < attr->ids; j++) {
755                         if (attr->id[j] == id)
756                                 return &attr->attr;
757                 }
758         }
759
760         return NULL;
761 }