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