perf: Emit build-ids for processes and the kernel
[akaros.git] / tools / profile / perf / perfconv.c
1 /* Copyright (c) 2015-2016 Google Inc
2  * Davide Libenzi <dlibenzi@google.com>
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  *
5  * See LICENSE for details.
6  *
7  * Converts kprof profiler files into Linux perf ones. The Linux Perf file
8  * format has bee illustrated here:
9  *
10  *       https://lwn.net/Articles/644919/
11  *       https://openlab-mu-internal.web.cern.ch/openlab-mu-internal/03_Documents/
12  *                       3_Technical_Documents/Technical_Reports/2011/Urs_Fassler_report.pdf
13  *
14  */
15
16 #include <ros/common.h>
17 #include <ros/memops.h>
18 #include <ros/profiler_records.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <stdarg.h>
28 #include "perf_format.h"
29 #include "xlib.h"
30 #include "perf_core.h"
31 #include "perfconv.h"
32 #include "elf.h"
33
34 #define MAX_PERF_RECORD_SIZE (32 * 1024 * 1024)
35 #define PERF_RECORD_BUFFER_SIZE 1024
36 #define OFFSET_NORELOC ((uint64_t) -1)
37 #define MEMFILE_BLOCK_SIZE (64 * 1024)
38
39 #define MBWR_SOLID (1 << 0)
40
41 struct perf_record {
42         uint64_t type;
43         uint64_t size;
44         char *data;
45         char buffer[PERF_RECORD_BUFFER_SIZE];
46 };
47
48 static void dbg_print(struct perfconv_context *cctx, int level, FILE *file,
49                                           const char *fmt, ...)
50 {
51         if (cctx->debug_level >= level) {
52                 va_list args;
53
54                 va_start(args, fmt);
55                 vfprintf(file, fmt, args);
56                 va_end(args);
57         }
58 }
59
60 void perfconv_set_dbglevel(int level, struct perfconv_context *cctx)
61 {
62         cctx->debug_level = level;
63 }
64
65 static void free_record(struct perf_record *pr)
66 {
67         if (pr->data != pr->buffer)
68                 free(pr->data);
69         pr->data = NULL;
70 }
71
72 static int read_record(FILE *file, struct perf_record *pr)
73 {
74         if (vb_fdecode_uint64(file, &pr->type) == EOF ||
75                 vb_fdecode_uint64(file, &pr->size) == EOF)
76                 return EOF;
77         if (pr->size > MAX_PERF_RECORD_SIZE) {
78                 fprintf(stderr, "Invalid record size: type=%lu size=%lu\n", pr->type,
79                                 pr->size);
80                 exit(1);
81         }
82         if (pr->size > sizeof(pr->buffer))
83                 pr->data = xmalloc((size_t) pr->size);
84         else
85                 pr->data = pr->buffer;
86         if (fread(pr->data, 1, (size_t) pr->size, file) != (size_t) pr->size) {
87                 fprintf(stderr, "Unable to read record memory: size=%lu\n",
88                                 pr->size);
89                 return EOF;
90         }
91
92         return 0;
93 }
94
95 static struct mem_block *mem_block_alloc(size_t size)
96 {
97         struct mem_block *mb = xmalloc(sizeof(struct mem_block) + size);
98
99         mb->next = NULL;
100         mb->base = mb->wptr = (char *) mb + sizeof(struct mem_block);
101         mb->top = mb->base + size;
102
103         return mb;
104 }
105
106 static char *mem_block_write(struct mem_block *mb, const void *data,
107                                                          size_t size)
108 {
109         char *wrbase = mb->wptr;
110
111         always_assert(size <= mb->top - mb->wptr);
112
113         memcpy(mb->wptr, data, size);
114         mb->wptr += size;
115
116         return wrbase;
117 }
118
119 static void mem_file_init(struct mem_file *mf)
120 {
121         ZERO_DATA(*mf);
122 }
123
124 static int mem_block_can_write(struct mem_block *mb, size_t size, int flags)
125 {
126         size_t space = mb->top - mb->wptr;
127
128         return (flags & MBWR_SOLID) ? (space >= size) : (space > 0);
129 }
130
131 static void *mem_file_write(struct mem_file *mf, const void *data, size_t size,
132                                                         int flags)
133 {
134         void *wrbase = NULL;
135
136         while (size > 0) {
137                 size_t space, csize;
138                 struct mem_block *mb = mf->tail;
139
140                 if (!mb || !mem_block_can_write(mb, size, flags)) {
141                         mb = mem_block_alloc(max(MEMFILE_BLOCK_SIZE, size));
142                         if (!mf->tail)
143                                 mf->head = mb;
144                         else
145                                 mf->tail->next = mb;
146                         mf->tail = mb;
147                 }
148                 space = mb->top - mb->wptr;
149                 csize = min(size, space);
150
151                 wrbase = mem_block_write(mb, data, csize);
152                 mf->size += csize;
153
154                 size -= csize;
155                 data = (const char *) data + csize;
156         }
157
158         return wrbase;
159 }
160
161 static void mem_file_sync(struct mem_file *mf, FILE *file, uint64_t rel_offset)
162 {
163         struct mem_block *mb;
164
165         if (rel_offset != 0) {
166                 struct mem_file_reloc *rel;
167
168                 always_assert(!mf->relocs || rel_offset != OFFSET_NORELOC);
169
170                 for (rel = mf->relocs; rel; rel = rel->next)
171                         *rel->ptr += rel_offset;
172         }
173
174         for (mb = mf->head; mb; mb = mb->next)
175                 xfwrite(mb->base, mb->wptr - mb->base, file);
176 }
177
178 static struct mem_file_reloc *mem_file_add_reloc(struct mem_file *mf,
179                                                                                                  uint64_t *ptr)
180 {
181         struct mem_file_reloc *rel = xzmalloc(sizeof(struct mem_file_reloc));
182
183         rel->ptr = ptr;
184         rel->next = mf->relocs;
185         mf->relocs = rel;
186
187         return rel;
188 }
189
190 void perfconv_add_kernel_mmap(struct perfconv_context *cctx)
191 {
192         char path[] = "[kernel.kallsyms]";
193         struct static_mmap64 *mm;
194
195         mm = xzmalloc(sizeof(struct static_mmap64));
196         mm->pid = -1;                           /* Linux HOST_KERNEL_ID == -1 */
197         mm->tid = 0;                            /* Default thread: swapper */
198         mm->header_misc = PERF_RECORD_MISC_KERNEL;
199         /* Linux sets addr = 0, size = 0xffffffff9fffffff, off = 0xffffffff81000000
200          * Their mmap record is also called [kernel.kallsyms]_text (I think).  They
201          * also have a _text symbol in kallsyms at ffffffff81000000 (equiv to our
202          * KERN_LOAD_ADDR (which is 0xffffffffc0000000)).  Either way, this seems to
203          * work for us; we'll see.  It's also arch-independent (for now). */
204         mm->addr = 0;
205         mm->size = 0xffffffffffffffff;
206         mm->offset = 0x0;
207         mm->path = xstrdup(path);
208
209         mm->next = cctx->static_mmaps;
210         cctx->static_mmaps = mm;
211 }
212
213 static void headers_init(struct perf_headers *hdrs)
214 {
215         ZERO_DATA(*hdrs);
216 }
217
218 /* Prepends a header (the mem_block) to the list of memblocks for the given
219  * HEADER type.  They will all be concatted together during finalization. */
220 static void headers_add_header(struct perf_header *ph,
221                                struct perf_headers *hdrs, size_t nhdr,
222                                                            struct mem_block *mb)
223 {
224         always_assert(nhdr < HEADER_FEAT_BITS);
225
226         mb->next = hdrs->headers[nhdr];
227         hdrs->headers[nhdr] = mb;
228         set_bitno(ph->adds_features, nhdr);
229 }
230
231 /* Emits the headers contents to the mem_file */
232 static void headers_finalize(struct perf_headers *hdrs, struct mem_file *mf)
233 {
234         struct perf_file_section *header_file_secs, *file_sec;
235         struct perf_file_section *file_sec_reloc;
236         size_t nr_hdrs = 0;
237         size_t hdr_off;
238         struct mem_block *mb;
239         size_t mb_sz;
240
241         /* For each header, we need a perf_file_section.  These header file sections
242          * are right after the main perf header, and they point to actual header. */
243         for (int i = 0; i < HEADER_FEAT_BITS; i++)
244                 if (hdrs->headers[i])
245                         nr_hdrs++;
246         if (!nr_hdrs)
247                 return;
248         header_file_secs = xmalloc(sizeof(struct perf_file_section) * nr_hdrs);
249
250         hdr_off = sizeof(struct perf_file_section) * nr_hdrs;
251         file_sec = header_file_secs;
252
253         /* Spit out the perf_file_sections first and track relocations for all of
254          * the offsets. */
255         for (int i = 0; i < HEADER_FEAT_BITS; i++) {
256                 mb = hdrs->headers[i];
257                 if (!mb)
258                         continue;
259                 mb_sz = mb->wptr - mb->base;
260                 /* headers[i] is a chain of memblocks */
261                 while (mb->next) {
262                         mb = mb->next;
263                         mb_sz += mb->wptr - mb->base;
264                 }
265                 file_sec->size = mb_sz;
266                 file_sec->offset = hdr_off;             /* offset rel to this memfile */
267                 /* When we sync the memfile, we'll need to relocate each of the offsets
268                  * so that they are relative to the final file.   mem_file_write()
269                  * should be returning the location of where it wrote our file section
270                  * within the memfile.  that's the offset that we'll reloc later. */
271                 file_sec_reloc = mem_file_write(mf, file_sec,
272                                                 sizeof(struct perf_file_section), 0);
273                 assert(file_sec->size == file_sec_reloc->size);
274                 assert(file_sec->offset == file_sec_reloc->offset);
275                 mem_file_add_reloc(mf, &file_sec_reloc->offset);
276
277                 hdr_off += mb_sz;
278                 file_sec++;
279         }
280         free(header_file_secs);
281
282         /* Spit out the actual headers */
283         for (int i = 0; i < HEADER_FEAT_BITS; i++) {
284                 mb = hdrs->headers[i];
285                 while (mb) {
286                         mem_file_write(mf, mb->base, mb->wptr - mb->base, 0);
287                         mb = mb->next;
288                 }
289         }
290 }
291
292 /* Builds a struct perf_header_string from str and returns it in a mem_block */
293 static struct mem_block *header_make_string(const char *str)
294 {
295         struct perf_header_string *hdr;
296         struct mem_block *mb;
297         size_t str_sz = strlen(str) + 1;
298         size_t hdr_sz = ROUNDUP(str_sz + sizeof(struct perf_header_string),
299                                 PERF_STRING_ALIGN);
300
301         mb = mem_block_alloc(hdr_sz);
302         /* Manually writing to the block to avoid another alloc.  I guess I could do
303          * two writes (len and string) and try to not screw it up, but that'd be a
304          * mess. */
305         hdr = (struct perf_header_string*)mb->wptr;
306         mb->wptr += hdr_sz;
307         hdr->len = str_sz;
308         memcpy(hdr->string, str, str_sz);
309         return mb;
310 }
311
312 /* Opens and reads filename, returning the contents.  Free the ret. */
313 static char *get_str_from_os(const char *filename)
314 {
315         int fd, ret;
316         struct stat fd_stat;
317         char *buf;
318         size_t buf_sz;
319
320         fd = open(filename, O_RDONLY);
321         if (fd < 0)
322                 return 0;
323         ret = fstat(fd, &fd_stat);
324         if (ret) {
325                 close(fd);
326                 return 0;
327         }
328         buf_sz = fd_stat.st_size + 1;
329         buf = xmalloc(buf_sz);
330         ret = read(fd, buf, buf_sz - 1);
331         if (ret <= 0) {
332                 free(buf);
333                 close(fd);
334                 return 0;
335         }
336         close(fd);
337         /* OS strings should be null terminated, but let's be defensive */
338         buf[ret] = 0;
339         return buf;
340 }
341
342 static void hdr_do_osrelease(struct perf_header *ph, struct perf_headers *hdrs)
343 {
344         char *str;
345
346         str = get_str_from_os("#version/version_name");
347         if (!str)
348                 return;
349         headers_add_header(ph, hdrs, HEADER_OSRELEASE, header_make_string(str));
350         free(str);
351 }
352
353 static void hdr_do_nrcpus(struct perf_header *ph, struct perf_headers *hdrs)
354 {
355         char *str;
356         uint32_t nr_cores;
357         struct mem_block *mb;
358         struct nr_cpus *hdr;
359
360         str = get_str_from_os("#vars/num_cores!dw");
361         if (!str)
362                 return;
363         nr_cores = atoi(str);
364         free(str);
365
366         mb = mem_block_alloc(sizeof(struct nr_cpus));
367         hdr = (struct nr_cpus*)mb->wptr;
368         mb->wptr += sizeof(struct nr_cpus);
369
370         hdr->nr_cpus_online = nr_cores;
371         hdr->nr_cpus_available = nr_cores;
372
373         headers_add_header(ph, hdrs, HEADER_NRCPUS, mb);
374 }
375
376 /* Returns TRUE if we already emitted a build-id for path.  If this gets too
377  * slow (which we'll know because of perf!) we can use a hash table (don't hash
378  * on the first few bytes btw - they are usually either /bin or /lib). */
379 static bool lookup_buildid(struct perfconv_context *cctx, const char *path)
380 {
381         struct build_id_event *b_evt;
382         struct mem_block *mb;
383         size_t b_evt_path_sz;
384
385         mb = cctx->hdrs.headers[HEADER_BUILD_ID];
386         while (mb) {
387                 b_evt = (struct build_id_event*)mb->base;
388                 b_evt_path_sz = b_evt->header.size -
389                                 offsetof(struct build_id_event, filename);
390                 /* ignoring the last byte since we forced it to be \0 earlier. */
391                 if (!strncmp(b_evt->filename, path, b_evt_path_sz - 1))
392                         return TRUE;
393                 mb = mb->next;
394         }
395         return FALSE;
396 }
397
398 /* Helper: given a path, allocs and inits a build_id_event within a mem_block,
399  * returning both via parameters.  Caller needs to set header.misc and fill in
400  * the actual build_id. */
401 static void build_id_alloc(const char *path, struct build_id_event **b_evt_p,
402                            struct mem_block **mb_p)
403 {
404         struct build_id_event *b_evt;
405         struct mem_block *mb;
406         size_t path_sz, b_evt_sz;
407
408         path_sz = strlen(path) + 1;
409         b_evt_sz = path_sz + sizeof(struct build_id_event);
410
411         mb = mem_block_alloc(b_evt_sz);
412         b_evt = (struct build_id_event*)mb->wptr;
413         mb->wptr += b_evt_sz;
414
415         b_evt->header.type = 0; /* if this fails, try 67 (synthetic build id) */
416         /* header.size filled in by the caller, depending on the type */
417         b_evt->header.size = b_evt_sz;
418         strlcpy(b_evt->filename, path, path_sz);
419
420         *b_evt_p = b_evt;
421         *mb_p = mb;
422 }
423
424 /* Add a build-id header.  Unlike many of the other headers, this one is built
425  * on the fly as we emit other records. */
426 static void hdr_add_buildid(struct perfconv_context *cctx, const char *path,
427                             int pid)
428 {
429         struct build_id_event *b_evt;
430         struct mem_block *mb;
431         int ret;
432
433         if (lookup_buildid(cctx, path))
434                 return;
435
436         build_id_alloc(path, &b_evt, &mb);
437         b_evt->header.misc = PERF_RECORD_MISC_USER;
438         b_evt->pid = pid;
439         ret = filename__read_build_id(path, b_evt->build_id, BUILD_ID_SIZE);
440         if (ret <= 0)
441                 free(mb);
442         else
443                 headers_add_header(&cctx->ph, &cctx->hdrs, HEADER_BUILD_ID, mb);
444 }
445
446 static void convert_str_to_binary(char *b_id_str, uint8_t *b_id_raw)
447 {
448         char *c = b_id_str;
449
450         for (int i = 0; i < BUILD_ID_SIZE; i++) {
451                 b_id_raw[i] = nibble_to_num(*c) << 4 | nibble_to_num(*(c + 1));
452                 c += 2;
453         }
454 }
455
456 void perfconv_add_kernel_buildid(struct perfconv_context *cctx)
457 {
458         struct build_id_event *b_evt;
459         struct mem_block *mb;
460         int ret, fd;
461         char build_id[BUILD_ID_SIZE * 2 + 1] = {0};
462
463         build_id_alloc("[kernel.kallsyms]", &b_evt, &mb);
464         b_evt->header.misc = PERF_RECORD_MISC_KERNEL;
465         b_evt->pid = -1;
466         fd = xopen("#version/build_id", O_RDONLY, 0);
467         ret = read(fd, build_id, sizeof(build_id));
468         if (ret <= 0) {
469                 free(mb);
470         } else {
471                 convert_str_to_binary(build_id, b_evt->build_id);
472                 headers_add_header(&cctx->ph, &cctx->hdrs, HEADER_BUILD_ID, mb);
473         }
474 }
475
476 /* Helper: adds all the headers, marking them in PH and storing them in
477  * feat_hdrs. */
478 static void headers_build(struct perf_header *ph, struct perf_headers *hdrs,
479                           struct mem_file *feat_hdrs)
480 {
481         hdr_do_osrelease(ph, hdrs);
482         hdr_do_nrcpus(ph, hdrs);
483
484         headers_finalize(hdrs, feat_hdrs);
485 }
486
487 static void perf_header_init(struct perf_header *ph)
488 {
489         ZERO_DATA(*ph);
490         ph->magic = PERF_MAGIC2;
491         ph->size = sizeof(*ph);
492         ph->attr_size = sizeof(struct perf_event_attr);
493 }
494
495 /* For each attr we emit, we push out the attr, then a perf_file_section for the
496  * id(s) for that attr.  This wasn't mentioned in
497  * https://lwn.net/Articles/644919/, but it's what Linux perf expects
498  * (util/header.c).  It looks like you can have multiple IDs per event attr.
499  * We'll only emit one.  The *contents* of the perf_file_section for the ids
500  * aren't in the attr perf_file_section, they are in a separate one
501  * (attr_id_mf).
502  *
503  * Note that *attr_mf*'s relocs are relative to the base of *attr_id_mf*, which
504  * we'll need to sort out later. */
505 static void emit_attr(struct mem_file *attr_mf, struct mem_file *attr_id_mf,
506                       const struct perf_event_attr *attr, uint64_t id)
507 {
508         struct perf_file_section *psids;
509         struct perf_file_section sids;
510
511         mem_file_write(attr_mf, attr, sizeof(*attr), 0);
512
513         sids.offset = attr_id_mf->size;
514         sids.size = sizeof(uint64_t);
515         mem_file_write(attr_id_mf, &id, sizeof(uint64_t), 0);
516
517         psids = mem_file_write(attr_mf, &sids, sizeof(sids), MBWR_SOLID);
518         mem_file_add_reloc(attr_mf, &psids->offset);
519 }
520
521 /* Given raw_info, which is what the kernel sends as user_data for a particular
522  * sample, look up the 'id' for the event/sample.  The 'id' identifies the event
523  * stream that the sample is a part of.  There are many samples per event
524  * stream, all identified by 'id.'  It doesn't matter what 'id', so long as it
525  * is unique.  We happen to use the pointer to the sample's eventsel.
526  *
527  * If this is the first time we've seen 'raw_info', we'll also add an attribute
528  * to the perf ctx.  There is one attr per 'id' / event stream. */
529 static uint64_t perfconv_get_event_id(struct perfconv_context *cctx,
530                                                                           uint64_t raw_info)
531 {
532         struct perf_eventsel *sel = (struct perf_eventsel*)raw_info;
533         struct perf_event_attr attr;
534         uint64_t raw_event;
535
536         assert(sel);
537         if (sel->attr_emitted)
538                 return raw_info;
539         raw_event = sel->ev.event;
540         ZERO_DATA(attr);
541         attr.size = sizeof(attr);
542         attr.mmap = 1;
543         attr.comm = 1;
544         attr.sample_period = sel->ev.trigger_count;
545         /* Closely coupled with struct perf_record_sample */
546         attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
547                            PERF_SAMPLE_ADDR | PERF_SAMPLE_ID | PERF_SAMPLE_CPU |
548                            PERF_SAMPLE_CALLCHAIN;
549         attr.exclude_guest = 1; /* we can't trace VMs yet */
550         attr.exclude_hv = 1;    /* we aren't tracing our hypervisor, AFAIK */
551         attr.exclude_user = !PMEV_GET_USR(raw_event);
552         attr.exclude_kernel = !PMEV_GET_OS(raw_event);
553         attr.type = sel->type;
554         attr.config = sel->config;
555         emit_attr(&cctx->attrs, &cctx->attr_ids, &attr, raw_info);
556         sel->attr_emitted = TRUE;
557         return raw_info;
558 }
559
560 static void emit_static_mmaps(struct perfconv_context *cctx)
561 {
562         struct static_mmap64 *mm;
563
564         for (mm = cctx->static_mmaps; mm; mm = mm->next) {
565                 size_t size = sizeof(struct perf_record_mmap) + strlen(mm->path) + 1;
566                 struct perf_record_mmap *xrec = xzmalloc(size);
567
568                 xrec->header.type = PERF_RECORD_MMAP;
569                 xrec->header.misc = mm->header_misc;
570                 xrec->header.size = size;
571                 xrec->pid = mm->pid;
572                 xrec->tid = mm->tid;
573                 xrec->addr = mm->addr;
574                 xrec->len = mm->size;
575                 xrec->pgoff = mm->offset;
576                 strcpy(xrec->filename, mm->path);
577
578                 mem_file_write(&cctx->data, xrec, size, 0);
579
580                 free(xrec);
581         }
582 }
583
584 static void emit_comm(uint32_t pid, const char *comm,
585                                           struct perfconv_context *cctx)
586 {
587         size_t size = sizeof(struct perf_record_comm) + strlen(comm) + 1;
588         struct perf_record_comm *xrec = xzmalloc(size);
589
590         xrec->header.type = PERF_RECORD_COMM;
591         xrec->header.misc = PERF_RECORD_MISC_USER;
592         xrec->header.size = size;
593         xrec->pid = xrec->tid = pid;
594         strcpy(xrec->comm, comm);
595
596         mem_file_write(&cctx->data, xrec, size, 0);
597
598         free(xrec);
599 }
600
601 static void emit_pid_mmap64(struct perf_record *pr,
602                                                         struct perfconv_context *cctx)
603 {
604         struct proftype_pid_mmap64 *rec = (struct proftype_pid_mmap64 *) pr->data;
605         size_t size = sizeof(struct perf_record_mmap) +
606                       strlen((char*)rec->path) + 1;
607         struct perf_record_mmap *xrec = xzmalloc(size);
608
609         hdr_add_buildid(cctx, (char*)rec->path, rec->pid);
610
611         xrec->header.type = PERF_RECORD_MMAP;
612         xrec->header.misc = PERF_RECORD_MISC_USER;
613         xrec->header.size = size;
614         xrec->pid = xrec->tid = rec->pid;
615         xrec->addr = rec->addr;
616         xrec->len = rec->size;
617         xrec->pgoff = rec->offset;
618         strcpy(xrec->filename, (char*)rec->path);
619
620         mem_file_write(&cctx->data, xrec, size, 0);
621
622         free(xrec);
623 }
624
625 static void emit_kernel_trace64(struct perf_record *pr,
626                                                                 struct perfconv_context *cctx)
627 {
628         struct proftype_kern_trace64 *rec = (struct proftype_kern_trace64 *)
629                 pr->data;
630         size_t size = sizeof(struct perf_record_sample) +
631                 (rec->num_traces - 1) * sizeof(uint64_t);
632         struct perf_record_sample *xrec = xzmalloc(size);
633
634         xrec->header.type = PERF_RECORD_SAMPLE;
635         xrec->header.misc = PERF_RECORD_MISC_KERNEL;
636         xrec->header.size = size;
637         xrec->ip = rec->trace[0];
638         /* TODO: We could have pid/tid for kernel tasks during their lifetime.
639          * During syscalls, we could use the pid of the process.  For the kernel
640          * itself, -1 seems to be generic kernel stuff, and tid == 0 is 'swapper'.
641          *
642          * Right now, the kernel doesn't even tell us the pid, so we have no way of
643          * knowing from userspace. */
644         xrec->pid = -1;
645         xrec->tid = 0;
646         xrec->time = rec->tstamp;
647         xrec->addr = rec->trace[0];
648         xrec->id = perfconv_get_event_id(cctx, rec->info);
649         xrec->cpu = rec->cpu;
650         xrec->nr = rec->num_traces - 1;
651         memcpy(xrec->ips, rec->trace + 1, (rec->num_traces - 1) * sizeof(uint64_t));
652
653         mem_file_write(&cctx->data, xrec, size, 0);
654
655         free(xrec);
656 }
657
658 static void emit_user_trace64(struct perf_record *pr,
659                                                           struct perfconv_context *cctx)
660 {
661         struct proftype_user_trace64 *rec = (struct proftype_user_trace64 *)
662                 pr->data;
663         size_t size = sizeof(struct perf_record_sample) +
664                 (rec->num_traces - 1) * sizeof(uint64_t);
665         struct perf_record_sample *xrec = xzmalloc(size);
666
667         xrec->header.type = PERF_RECORD_SAMPLE;
668         xrec->header.misc = PERF_RECORD_MISC_USER;
669         xrec->header.size = size;
670         xrec->ip = rec->trace[0];
671         xrec->pid = xrec->tid = rec->pid;
672         xrec->time = rec->tstamp;
673         xrec->addr = rec->trace[0];
674         xrec->id = perfconv_get_event_id(cctx, rec->info);
675         xrec->cpu = rec->cpu;
676         xrec->nr = rec->num_traces - 1;
677         memcpy(xrec->ips, rec->trace + 1, (rec->num_traces - 1) * sizeof(uint64_t));
678
679         mem_file_write(&cctx->data, xrec, size, 0);
680
681         free(xrec);
682 }
683
684 static void emit_new_process(struct perf_record *pr,
685                                                          struct perfconv_context *cctx)
686 {
687         struct proftype_new_process *rec = (struct proftype_new_process *) pr->data;
688         const char *comm;
689
690         hdr_add_buildid(cctx, (char*)rec->path, rec->pid);
691
692         comm = strrchr((char*)rec->path, '/');
693         if (!comm)
694                 comm = (char*)rec->path;
695         else
696                 comm++;
697         emit_comm(rec->pid, comm, cctx);
698 }
699
700 struct perfconv_context *perfconv_create_context(struct perf_context *pctx)
701 {
702         struct perfconv_context *cctx = xzmalloc(sizeof(struct perfconv_context));
703
704         cctx->pctx = pctx;
705         perf_header_init(&cctx->ph);
706         headers_init(&cctx->hdrs);
707         mem_file_init(&cctx->fhdrs);
708         mem_file_init(&cctx->attr_ids);
709         mem_file_init(&cctx->attrs);
710         mem_file_init(&cctx->data);
711         /* event_types is ignored in newer versions of perf */
712         mem_file_init(&cctx->event_types);
713
714         return cctx;
715 }
716
717 void perfconv_free_context(struct perfconv_context *cctx)
718 {
719         if (cctx)
720                 free(cctx);
721 }
722
723 void perfconv_process_input(struct perfconv_context *cctx, FILE *input,
724                                                         FILE *output)
725 {
726         size_t processed_records = 0;
727         uint64_t offset;
728         uint64_t attr_ids_off = sizeof(cctx->ph);
729         struct perf_record pr;
730
731         emit_static_mmaps(cctx);
732
733         while (read_record(input, &pr) == 0) {
734                 dbg_print(cctx, 8, stderr, "Valid record: type=%lu size=%lu\n",
735                                   pr.type, pr.size);
736
737                 processed_records++;
738
739                 switch (pr.type) {
740                 case PROFTYPE_KERN_TRACE64:
741                         emit_kernel_trace64(&pr, cctx);
742                         break;
743                 case PROFTYPE_USER_TRACE64:
744                         emit_user_trace64(&pr, cctx);
745                         break;
746                 case PROFTYPE_PID_MMAP64:
747                         emit_pid_mmap64(&pr, cctx);
748                         break;
749                 case PROFTYPE_NEW_PROCESS:
750                         emit_new_process(&pr, cctx);
751                         break;
752                 default:
753                         fprintf(stderr, "Unknown record: type=%lu size=%lu\n", pr.type,
754                                         pr.size);
755                         processed_records--;
756                 }
757
758                 free_record(&pr);
759         }
760
761         /* Add all of the headers before outputting ph */
762         headers_build(&cctx->ph, &cctx->hdrs, &cctx->fhdrs);
763
764         /* attrs, events, and data will come after attr_ids. */
765         offset = sizeof(cctx->ph) + cctx->attr_ids.size;
766
767         /* These are the perf_file_sections in the main perf header.  We need this
768          * sorted out before we emit the PH. */
769         cctx->ph.event_types.offset = offset;
770         cctx->ph.event_types.size = cctx->event_types.size;
771         offset += cctx->event_types.size;
772
773         cctx->ph.attrs.offset = offset;
774         cctx->ph.attrs.size = cctx->attrs.size;
775         offset += cctx->attrs.size;
776
777         cctx->ph.data.offset = offset;
778         cctx->ph.data.size = cctx->data.size;
779         offset += cctx->data.size;
780
781         xfwrite(&cctx->ph, sizeof(cctx->ph), output);
782
783         /* attr_ids comes right after the cctx->ph.  We need to put it before
784          * attrs, since attrs needs to know the offset of the base of attrs_ids for
785          * its relocs. */
786         assert(ftell(output) == attr_ids_off);
787         mem_file_sync(&cctx->attr_ids, output, OFFSET_NORELOC);
788         mem_file_sync(&cctx->event_types, output, OFFSET_NORELOC);
789         /* reloc is based off *attr_ids* base */
790         mem_file_sync(&cctx->attrs, output, attr_ids_off);
791         /* Keep data last, so we can append the feature headers.*/
792         mem_file_sync(&cctx->data, output, OFFSET_NORELOC);
793         /* The feature headers must be right after the data section.  I didn't see
794          * anything in the ABI about this, but Linux's perf has this line:
795          *
796          *              ph->feat_offset  = header->data.offset + header->data.size;
797          */
798         mem_file_sync(&cctx->fhdrs, output,
799                       cctx->ph.data.offset + cctx->ph.data.size);
800
801         dbg_print(cctx, 2, stderr, "Conversion succeeded: %lu records converted\n",
802                           processed_records);
803 }