perf symbols: Cache /proc/kallsyms files by build-id
[linux-flexiantxendom0-3.2.10.git] / 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 static int dso__cache_build_id(struct dso *self, const char *debugdir)
235 {
236         const size_t size = PATH_MAX;
237         char *filename = malloc(size),
238              *linkname = malloc(size), *targetname, *sbuild_id;
239         int len, err = -1;
240         bool is_kallsyms = self->kernel && self->long_name[0] != '/';
241
242         if (filename == NULL || linkname == NULL)
243                 goto out_free;
244
245         len = snprintf(filename, size, "%s%s%s",
246                        debugdir, is_kallsyms ? "/" : "", self->long_name);
247         if (mkdir_p(filename, 0755))
248                 goto out_free;
249
250         len += snprintf(filename + len, sizeof(filename) - len, "/");
251         sbuild_id = filename + len;
252         build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
253
254         if (access(filename, F_OK)) {
255                 if (is_kallsyms) {
256                          if (copyfile("/proc/kallsyms", filename))
257                                 goto out_free;
258                 } else if (link(self->long_name, filename) &&
259                            copyfile(self->long_name, filename))
260                         goto out_free;
261         }
262
263         len = snprintf(linkname, size, "%s/.build-id/%.2s",
264                        debugdir, sbuild_id);
265
266         if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
267                 goto out_free;
268
269         snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
270         targetname = filename + strlen(debugdir) - 5;
271         memcpy(targetname, "../..", 5);
272
273         if (symlink(targetname, linkname) == 0)
274                 err = 0;
275 out_free:
276         free(filename);
277         free(linkname);
278         return err;
279 }
280
281 static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
282 {
283         struct dso *pos;
284         int err = 0;
285
286         dsos__for_each_with_build_id(pos, head)
287                 if (dso__cache_build_id(pos, debugdir))
288                         err = -1;
289
290         return err;
291 }
292
293 static int dsos__cache_build_ids(void)
294 {
295         int err_kernel, err_user;
296         char debugdir[PATH_MAX];
297
298         snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
299                  DEBUG_CACHE_DIR);
300
301         if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
302                 return -1;
303
304         err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
305         err_user   = __dsos__cache_build_ids(&dsos__user, debugdir);
306         return err_kernel || err_user ? -1 : 0;
307 }
308
309 static int perf_header__adds_write(struct perf_header *self, int fd)
310 {
311         int nr_sections;
312         struct perf_file_section *feat_sec;
313         int sec_size;
314         u64 sec_start;
315         int idx = 0, err;
316
317         if (dsos__read_build_ids())
318                 perf_header__set_feat(self, HEADER_BUILD_ID);
319
320         nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
321         if (!nr_sections)
322                 return 0;
323
324         feat_sec = calloc(sizeof(*feat_sec), nr_sections);
325         if (feat_sec == NULL)
326                 return -ENOMEM;
327
328         sec_size = sizeof(*feat_sec) * nr_sections;
329
330         sec_start = self->data_offset + self->data_size;
331         lseek(fd, sec_start + sec_size, SEEK_SET);
332
333         if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
334                 struct perf_file_section *trace_sec;
335
336                 trace_sec = &feat_sec[idx++];
337
338                 /* Write trace info */
339                 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
340                 read_tracing_data(fd, attrs, nr_counters);
341                 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
342         }
343
344
345         if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
346                 struct perf_file_section *buildid_sec;
347
348                 buildid_sec = &feat_sec[idx++];
349
350                 /* Write build-ids */
351                 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
352                 err = dsos__write_buildid_table(fd);
353                 if (err < 0) {
354                         pr_debug("failed to write buildid table\n");
355                         goto out_free;
356                 }
357                 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
358                 dsos__cache_build_ids();
359         }
360
361         lseek(fd, sec_start, SEEK_SET);
362         err = do_write(fd, feat_sec, sec_size);
363         if (err < 0)
364                 pr_debug("failed to write feature section\n");
365 out_free:
366         free(feat_sec);
367         return err;
368 }
369
370 int perf_header__write(struct perf_header *self, int fd, bool at_exit)
371 {
372         struct perf_file_header f_header;
373         struct perf_file_attr   f_attr;
374         struct perf_header_attr *attr;
375         int i, err;
376
377         lseek(fd, sizeof(f_header), SEEK_SET);
378
379
380         for (i = 0; i < self->attrs; i++) {
381                 attr = self->attr[i];
382
383                 attr->id_offset = lseek(fd, 0, SEEK_CUR);
384                 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
385                 if (err < 0) {
386                         pr_debug("failed to write perf header\n");
387                         return err;
388                 }
389         }
390
391
392         self->attr_offset = lseek(fd, 0, SEEK_CUR);
393
394         for (i = 0; i < self->attrs; i++) {
395                 attr = self->attr[i];
396
397                 f_attr = (struct perf_file_attr){
398                         .attr = attr->attr,
399                         .ids  = {
400                                 .offset = attr->id_offset,
401                                 .size   = attr->ids * sizeof(u64),
402                         }
403                 };
404                 err = do_write(fd, &f_attr, sizeof(f_attr));
405                 if (err < 0) {
406                         pr_debug("failed to write perf header attribute\n");
407                         return err;
408                 }
409         }
410
411         self->event_offset = lseek(fd, 0, SEEK_CUR);
412         self->event_size = event_count * sizeof(struct perf_trace_event_type);
413         if (events) {
414                 err = do_write(fd, events, self->event_size);
415                 if (err < 0) {
416                         pr_debug("failed to write perf header events\n");
417                         return err;
418                 }
419         }
420
421         self->data_offset = lseek(fd, 0, SEEK_CUR);
422
423         if (at_exit) {
424                 err = perf_header__adds_write(self, fd);
425                 if (err < 0)
426                         return err;
427         }
428
429         f_header = (struct perf_file_header){
430                 .magic     = PERF_MAGIC,
431                 .size      = sizeof(f_header),
432                 .attr_size = sizeof(f_attr),
433                 .attrs = {
434                         .offset = self->attr_offset,
435                         .size   = self->attrs * sizeof(f_attr),
436                 },
437                 .data = {
438                         .offset = self->data_offset,
439                         .size   = self->data_size,
440                 },
441                 .event_types = {
442                         .offset = self->event_offset,
443                         .size   = self->event_size,
444                 },
445         };
446
447         memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
448
449         lseek(fd, 0, SEEK_SET);
450         err = do_write(fd, &f_header, sizeof(f_header));
451         if (err < 0) {
452                 pr_debug("failed to write perf header\n");
453                 return err;
454         }
455         lseek(fd, self->data_offset + self->data_size, SEEK_SET);
456
457         self->frozen = 1;
458         return 0;
459 }
460
461 static int do_read(int fd, void *buf, size_t size)
462 {
463         while (size) {
464                 int ret = read(fd, buf, size);
465
466                 if (ret <= 0)
467                         return -1;
468
469                 size -= ret;
470                 buf += ret;
471         }
472
473         return 0;
474 }
475
476 static int perf_header__getbuffer64(struct perf_header *self,
477                                     int fd, void *buf, size_t size)
478 {
479         if (do_read(fd, buf, size))
480                 return -1;
481
482         if (self->needs_swap)
483                 mem_bswap_64(buf, size);
484
485         return 0;
486 }
487
488 int perf_header__process_sections(struct perf_header *self, int fd,
489                                   int (*process)(struct perf_file_section *self,
490                                                  struct perf_header *ph,
491                                                  int feat, int fd))
492 {
493         struct perf_file_section *feat_sec;
494         int nr_sections;
495         int sec_size;
496         int idx = 0;
497         int err = -1, feat = 1;
498
499         nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
500         if (!nr_sections)
501                 return 0;
502
503         feat_sec = calloc(sizeof(*feat_sec), nr_sections);
504         if (!feat_sec)
505                 return -1;
506
507         sec_size = sizeof(*feat_sec) * nr_sections;
508
509         lseek(fd, self->data_offset + self->data_size, SEEK_SET);
510
511         if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
512                 goto out_free;
513
514         err = 0;
515         while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
516                 if (perf_header__has_feat(self, feat)) {
517                         struct perf_file_section *sec = &feat_sec[idx++];
518
519                         err = process(sec, self, feat, fd);
520                         if (err < 0)
521                                 break;
522                 }
523                 ++feat;
524         }
525 out_free:
526         free(feat_sec);
527         return err;
528 }
529
530 int perf_file_header__read(struct perf_file_header *self,
531                            struct perf_header *ph, int fd)
532 {
533         lseek(fd, 0, SEEK_SET);
534
535         if (do_read(fd, self, sizeof(*self)) ||
536             memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
537                 return -1;
538
539         if (self->attr_size != sizeof(struct perf_file_attr)) {
540                 u64 attr_size = bswap_64(self->attr_size);
541
542                 if (attr_size != sizeof(struct perf_file_attr))
543                         return -1;
544
545                 mem_bswap_64(self, offsetof(struct perf_file_header,
546                                             adds_features));
547                 ph->needs_swap = true;
548         }
549
550         if (self->size != sizeof(*self)) {
551                 /* Support the previous format */
552                 if (self->size == offsetof(typeof(*self), adds_features))
553                         bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
554                 else
555                         return -1;
556         }
557
558         memcpy(&ph->adds_features, &self->adds_features,
559                sizeof(ph->adds_features));
560         /*
561          * FIXME: hack that assumes that if we need swap the perf.data file
562          * may be coming from an arch with a different word-size, ergo different
563          * DEFINE_BITMAP format, investigate more later, but for now its mostly
564          * safe to assume that we have a build-id section. Trace files probably
565          * have several other issues in this realm anyway...
566          */
567         if (ph->needs_swap) {
568                 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
569                 perf_header__set_feat(ph, HEADER_BUILD_ID);
570         }
571
572         ph->event_offset = self->event_types.offset;
573         ph->event_size   = self->event_types.size;
574         ph->data_offset  = self->data.offset;
575         ph->data_size    = self->data.size;
576         return 0;
577 }
578
579 static int perf_file_section__process(struct perf_file_section *self,
580                                       struct perf_header *ph,
581                                       int feat, int fd)
582 {
583         if (lseek(fd, self->offset, SEEK_SET) < 0) {
584                 pr_debug("Failed to lseek to %Ld offset for feature %d, "
585                          "continuing...\n", self->offset, feat);
586                 return 0;
587         }
588
589         switch (feat) {
590         case HEADER_TRACE_INFO:
591                 trace_report(fd);
592                 break;
593
594         case HEADER_BUILD_ID:
595                 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
596                         pr_debug("Failed to read buildids, continuing...\n");
597                 break;
598         default:
599                 pr_debug("unknown feature %d, continuing...\n", feat);
600         }
601
602         return 0;
603 }
604
605 int perf_header__read(struct perf_header *self, int fd)
606 {
607         struct perf_file_header f_header;
608         struct perf_file_attr   f_attr;
609         u64                     f_id;
610         int nr_attrs, nr_ids, i, j;
611
612         if (perf_file_header__read(&f_header, self, fd) < 0) {
613                 pr_debug("incompatible file format\n");
614                 return -EINVAL;
615         }
616
617         nr_attrs = f_header.attrs.size / sizeof(f_attr);
618         lseek(fd, f_header.attrs.offset, SEEK_SET);
619
620         for (i = 0; i < nr_attrs; i++) {
621                 struct perf_header_attr *attr;
622                 off_t tmp;
623
624                 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
625                         goto out_errno;
626
627                 tmp = lseek(fd, 0, SEEK_CUR);
628
629                 attr = perf_header_attr__new(&f_attr.attr);
630                 if (attr == NULL)
631                          return -ENOMEM;
632
633                 nr_ids = f_attr.ids.size / sizeof(u64);
634                 lseek(fd, f_attr.ids.offset, SEEK_SET);
635
636                 for (j = 0; j < nr_ids; j++) {
637                         if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
638                                 goto out_errno;
639
640                         if (perf_header_attr__add_id(attr, f_id) < 0) {
641                                 perf_header_attr__delete(attr);
642                                 return -ENOMEM;
643                         }
644                 }
645                 if (perf_header__add_attr(self, attr) < 0) {
646                         perf_header_attr__delete(attr);
647                         return -ENOMEM;
648                 }
649
650                 lseek(fd, tmp, SEEK_SET);
651         }
652
653         if (f_header.event_types.size) {
654                 lseek(fd, f_header.event_types.offset, SEEK_SET);
655                 events = malloc(f_header.event_types.size);
656                 if (events == NULL)
657                         return -ENOMEM;
658                 if (perf_header__getbuffer64(self, fd, events,
659                                              f_header.event_types.size))
660                         goto out_errno;
661                 event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
662         }
663
664         perf_header__process_sections(self, fd, perf_file_section__process);
665
666         lseek(fd, self->data_offset, SEEK_SET);
667
668         self->frozen = 1;
669         return 0;
670 out_errno:
671         return -errno;
672 }
673
674 u64 perf_header__sample_type(struct perf_header *header)
675 {
676         u64 type = 0;
677         int i;
678
679         for (i = 0; i < header->attrs; i++) {
680                 struct perf_header_attr *attr = header->attr[i];
681
682                 if (!type)
683                         type = attr->attr.sample_type;
684                 else if (type != attr->attr.sample_type)
685                         die("non matching sample_type");
686         }
687
688         return type;
689 }
690
691 struct perf_event_attr *
692 perf_header__find_attr(u64 id, struct perf_header *header)
693 {
694         int i;
695
696         for (i = 0; i < header->attrs; i++) {
697                 struct perf_header_attr *attr = header->attr[i];
698                 int j;
699
700                 for (j = 0; j < attr->ids; j++) {
701                         if (attr->id[j] == id)
702                                 return &attr->attr;
703                 }
704         }
705
706         return NULL;
707 }