OSDN Git Service

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