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