root/tools/perf/util/jitdump.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. jit_emit_elf
  2. jit_close
  3. jit_validate_events
  4. jit_open
  5. jit_get_next_entry
  6. jit_inject_event
  7. convert_timestamp
  8. jit_repipe_code_load
  9. jit_repipe_code_move
  10. jit_repipe_debug_info
  11. jit_repipe_unwinding_info
  12. jit_process_dump
  13. jit_inject
  14. jit_detect
  15. jit_process

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <sys/sysmacros.h>
   3 #include <sys/types.h>
   4 #include <errno.h>
   5 #include <libgen.h>
   6 #include <stdio.h>
   7 #include <stdlib.h>
   8 #include <string.h>
   9 #include <fcntl.h>
  10 #include <unistd.h>
  11 #include <inttypes.h>
  12 #include <byteswap.h>
  13 #include <sys/stat.h>
  14 #include <sys/mman.h>
  15 #include <linux/stringify.h>
  16 
  17 #include "build-id.h"
  18 #include "event.h"
  19 #include "debug.h"
  20 #include "evlist.h"
  21 #include "symbol.h"
  22 #include <elf.h>
  23 
  24 #include "tsc.h"
  25 #include "session.h"
  26 #include "jit.h"
  27 #include "jitdump.h"
  28 #include "genelf.h"
  29 
  30 #include <linux/ctype.h>
  31 #include <linux/zalloc.h>
  32 
  33 struct jit_buf_desc {
  34         struct perf_data *output;
  35         struct perf_session *session;
  36         struct machine *machine;
  37         union jr_entry   *entry;
  38         void             *buf;
  39         uint64_t         sample_type;
  40         size_t           bufsize;
  41         FILE             *in;
  42         bool             needs_bswap; /* handles cross-endianness */
  43         bool             use_arch_timestamp;
  44         void             *debug_data;
  45         void             *unwinding_data;
  46         uint64_t         unwinding_size;
  47         uint64_t         unwinding_mapped_size;
  48         uint64_t         eh_frame_hdr_size;
  49         size_t           nr_debug_entries;
  50         uint32_t         code_load_count;
  51         u64              bytes_written;
  52         struct rb_root   code_root;
  53         char             dir[PATH_MAX];
  54 };
  55 
  56 struct debug_line_info {
  57         unsigned long vma;
  58         unsigned int lineno;
  59         /* The filename format is unspecified, absolute path, relative etc. */
  60         char const filename[0];
  61 };
  62 
  63 struct jit_tool {
  64         struct perf_tool tool;
  65         struct perf_data        output;
  66         struct perf_data        input;
  67         u64 bytes_written;
  68 };
  69 
  70 #define hmax(a, b) ((a) > (b) ? (a) : (b))
  71 #define get_jit_tool(t) (container_of(tool, struct jit_tool, tool))
  72 
  73 static int
  74 jit_emit_elf(char *filename,
  75              const char *sym,
  76              uint64_t code_addr,
  77              const void *code,
  78              int csize,
  79              void *debug,
  80              int nr_debug_entries,
  81              void *unwinding,
  82              uint32_t unwinding_header_size,
  83              uint32_t unwinding_size)
  84 {
  85         int ret, fd;
  86 
  87         if (verbose > 0)
  88                 fprintf(stderr, "write ELF image %s\n", filename);
  89 
  90         fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
  91         if (fd == -1) {
  92                 pr_warning("cannot create jit ELF %s: %s\n", filename, strerror(errno));
  93                 return -1;
  94         }
  95 
  96         ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries,
  97                             unwinding, unwinding_header_size, unwinding_size);
  98 
  99         close(fd);
 100 
 101         if (ret)
 102                 unlink(filename);
 103 
 104         return ret;
 105 }
 106 
 107 static void
 108 jit_close(struct jit_buf_desc *jd)
 109 {
 110         if (!(jd && jd->in))
 111                 return;
 112         funlockfile(jd->in);
 113         fclose(jd->in);
 114         jd->in = NULL;
 115 }
 116 
 117 static int
 118 jit_validate_events(struct perf_session *session)
 119 {
 120         struct evsel *evsel;
 121 
 122         /*
 123          * check that all events use CLOCK_MONOTONIC
 124          */
 125         evlist__for_each_entry(session->evlist, evsel) {
 126                 if (evsel->core.attr.use_clockid == 0 || evsel->core.attr.clockid != CLOCK_MONOTONIC)
 127                         return -1;
 128         }
 129         return 0;
 130 }
 131 
 132 static int
 133 jit_open(struct jit_buf_desc *jd, const char *name)
 134 {
 135         struct jitheader header;
 136         struct jr_prefix *prefix;
 137         ssize_t bs, bsz = 0;
 138         void *n, *buf = NULL;
 139         int ret, retval = -1;
 140 
 141         jd->in = fopen(name, "r");
 142         if (!jd->in)
 143                 return -1;
 144 
 145         bsz = hmax(sizeof(header), sizeof(*prefix));
 146 
 147         buf = malloc(bsz);
 148         if (!buf)
 149                 goto error;
 150 
 151         /*
 152          * protect from writer modifying the file while we are reading it
 153          */
 154         flockfile(jd->in);
 155 
 156         ret = fread(buf, sizeof(header), 1, jd->in);
 157         if (ret != 1)
 158                 goto error;
 159 
 160         memcpy(&header, buf, sizeof(header));
 161 
 162         if (header.magic != JITHEADER_MAGIC) {
 163                 if (header.magic != JITHEADER_MAGIC_SW)
 164                         goto error;
 165                 jd->needs_bswap = true;
 166         }
 167 
 168         if (jd->needs_bswap) {
 169                 header.version    = bswap_32(header.version);
 170                 header.total_size = bswap_32(header.total_size);
 171                 header.pid        = bswap_32(header.pid);
 172                 header.elf_mach   = bswap_32(header.elf_mach);
 173                 header.timestamp  = bswap_64(header.timestamp);
 174                 header.flags      = bswap_64(header.flags);
 175         }
 176 
 177         jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP;
 178 
 179         if (verbose > 2)
 180                 pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n",
 181                         header.version,
 182                         header.total_size,
 183                         (unsigned long long)header.timestamp,
 184                         header.pid,
 185                         header.elf_mach,
 186                         jd->use_arch_timestamp);
 187 
 188         if (header.version > JITHEADER_VERSION) {
 189                 pr_err("wrong jitdump version %u, expected " __stringify(JITHEADER_VERSION),
 190                         header.version);
 191                 goto error;
 192         }
 193 
 194         if (header.flags & JITDUMP_FLAGS_RESERVED) {
 195                 pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
 196                        (unsigned long long)header.flags & JITDUMP_FLAGS_RESERVED);
 197                 goto error;
 198         }
 199 
 200         if (jd->use_arch_timestamp && !jd->session->time_conv.time_mult) {
 201                 pr_err("jitdump file uses arch timestamps but there is no timestamp conversion\n");
 202                 goto error;
 203         }
 204 
 205         /*
 206          * validate event is using the correct clockid
 207          */
 208         if (!jd->use_arch_timestamp && jit_validate_events(jd->session)) {
 209                 pr_err("error, jitted code must be sampled with perf record -k 1\n");
 210                 goto error;
 211         }
 212 
 213         bs = header.total_size - sizeof(header);
 214 
 215         if (bs > bsz) {
 216                 n = realloc(buf, bs);
 217                 if (!n)
 218                         goto error;
 219                 bsz = bs;
 220                 buf = n;
 221                 /* read extra we do not know about */
 222                 ret = fread(buf, bs - bsz, 1, jd->in);
 223                 if (ret != 1)
 224                         goto error;
 225         }
 226         /*
 227          * keep dirname for generating files and mmap records
 228          */
 229         strcpy(jd->dir, name);
 230         dirname(jd->dir);
 231 
 232         return 0;
 233 error:
 234         funlockfile(jd->in);
 235         fclose(jd->in);
 236         return retval;
 237 }
 238 
 239 static union jr_entry *
 240 jit_get_next_entry(struct jit_buf_desc *jd)
 241 {
 242         struct jr_prefix *prefix;
 243         union jr_entry *jr;
 244         void *addr;
 245         size_t bs, size;
 246         int id, ret;
 247 
 248         if (!(jd && jd->in))
 249                 return NULL;
 250 
 251         if (jd->buf == NULL) {
 252                 size_t sz = getpagesize();
 253                 if (sz < sizeof(*prefix))
 254                         sz = sizeof(*prefix);
 255 
 256                 jd->buf = malloc(sz);
 257                 if (jd->buf == NULL)
 258                         return NULL;
 259 
 260                 jd->bufsize = sz;
 261         }
 262 
 263         prefix = jd->buf;
 264 
 265         /*
 266          * file is still locked at this point
 267          */
 268         ret = fread(prefix, sizeof(*prefix), 1, jd->in);
 269         if (ret  != 1)
 270                 return NULL;
 271 
 272         if (jd->needs_bswap) {
 273                 prefix->id         = bswap_32(prefix->id);
 274                 prefix->total_size = bswap_32(prefix->total_size);
 275                 prefix->timestamp  = bswap_64(prefix->timestamp);
 276         }
 277         id   = prefix->id;
 278         size = prefix->total_size;
 279 
 280         bs = (size_t)size;
 281         if (bs < sizeof(*prefix))
 282                 return NULL;
 283 
 284         if (id >= JIT_CODE_MAX) {
 285                 pr_warning("next_entry: unknown record type %d, skipping\n", id);
 286         }
 287         if (bs > jd->bufsize) {
 288                 void *n;
 289                 n = realloc(jd->buf, bs);
 290                 if (!n)
 291                         return NULL;
 292                 jd->buf = n;
 293                 jd->bufsize = bs;
 294         }
 295 
 296         addr = ((void *)jd->buf) + sizeof(*prefix);
 297 
 298         ret = fread(addr, bs - sizeof(*prefix), 1, jd->in);
 299         if (ret != 1)
 300                 return NULL;
 301 
 302         jr = (union jr_entry *)jd->buf;
 303 
 304         switch(id) {
 305         case JIT_CODE_DEBUG_INFO:
 306                 if (jd->needs_bswap) {
 307                         uint64_t n;
 308                         jr->info.code_addr = bswap_64(jr->info.code_addr);
 309                         jr->info.nr_entry  = bswap_64(jr->info.nr_entry);
 310                         for (n = 0 ; n < jr->info.nr_entry; n++) {
 311                                 jr->info.entries[n].addr    = bswap_64(jr->info.entries[n].addr);
 312                                 jr->info.entries[n].lineno  = bswap_32(jr->info.entries[n].lineno);
 313                                 jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim);
 314                         }
 315                 }
 316                 break;
 317         case JIT_CODE_UNWINDING_INFO:
 318                 if (jd->needs_bswap) {
 319                         jr->unwinding.unwinding_size = bswap_64(jr->unwinding.unwinding_size);
 320                         jr->unwinding.eh_frame_hdr_size = bswap_64(jr->unwinding.eh_frame_hdr_size);
 321                         jr->unwinding.mapped_size = bswap_64(jr->unwinding.mapped_size);
 322                 }
 323                 break;
 324         case JIT_CODE_CLOSE:
 325                 break;
 326         case JIT_CODE_LOAD:
 327                 if (jd->needs_bswap) {
 328                         jr->load.pid       = bswap_32(jr->load.pid);
 329                         jr->load.tid       = bswap_32(jr->load.tid);
 330                         jr->load.vma       = bswap_64(jr->load.vma);
 331                         jr->load.code_addr = bswap_64(jr->load.code_addr);
 332                         jr->load.code_size = bswap_64(jr->load.code_size);
 333                         jr->load.code_index= bswap_64(jr->load.code_index);
 334                 }
 335                 jd->code_load_count++;
 336                 break;
 337         case JIT_CODE_MOVE:
 338                 if (jd->needs_bswap) {
 339                         jr->move.pid           = bswap_32(jr->move.pid);
 340                         jr->move.tid           = bswap_32(jr->move.tid);
 341                         jr->move.vma           = bswap_64(jr->move.vma);
 342                         jr->move.old_code_addr = bswap_64(jr->move.old_code_addr);
 343                         jr->move.new_code_addr = bswap_64(jr->move.new_code_addr);
 344                         jr->move.code_size     = bswap_64(jr->move.code_size);
 345                         jr->move.code_index    = bswap_64(jr->move.code_index);
 346                 }
 347                 break;
 348         case JIT_CODE_MAX:
 349         default:
 350                 /* skip unknown record (we have read them) */
 351                 break;
 352         }
 353         return jr;
 354 }
 355 
 356 static int
 357 jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
 358 {
 359         ssize_t size;
 360 
 361         size = perf_data__write(jd->output, event, event->header.size);
 362         if (size < 0)
 363                 return -1;
 364 
 365         jd->bytes_written += size;
 366         return 0;
 367 }
 368 
 369 static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp)
 370 {
 371         struct perf_tsc_conversion tc;
 372 
 373         if (!jd->use_arch_timestamp)
 374                 return timestamp;
 375 
 376         tc.time_shift = jd->session->time_conv.time_shift;
 377         tc.time_mult  = jd->session->time_conv.time_mult;
 378         tc.time_zero  = jd->session->time_conv.time_zero;
 379 
 380         if (!tc.time_mult)
 381                 return 0;
 382 
 383         return tsc_to_perf_time(timestamp, &tc);
 384 }
 385 
 386 static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 387 {
 388         struct perf_sample sample;
 389         union perf_event *event;
 390         struct perf_tool *tool = jd->session->tool;
 391         uint64_t code, addr;
 392         uintptr_t uaddr;
 393         char *filename;
 394         struct stat st;
 395         size_t size;
 396         u16 idr_size;
 397         const char *sym;
 398         uint64_t count;
 399         int ret, csize, usize;
 400         pid_t pid, tid;
 401         struct {
 402                 u32 pid, tid;
 403                 u64 time;
 404         } *id;
 405 
 406         pid   = jr->load.pid;
 407         tid   = jr->load.tid;
 408         csize = jr->load.code_size;
 409         usize = jd->unwinding_mapped_size;
 410         addr  = jr->load.code_addr;
 411         sym   = (void *)((unsigned long)jr + sizeof(jr->load));
 412         code  = (unsigned long)jr + jr->load.p.total_size - csize;
 413         count = jr->load.code_index;
 414         idr_size = jd->machine->id_hdr_size;
 415 
 416         event = calloc(1, sizeof(*event) + idr_size);
 417         if (!event)
 418                 return -1;
 419 
 420         filename = event->mmap2.filename;
 421         size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so",
 422                         jd->dir,
 423                         pid,
 424                         count);
 425 
 426         size++; /* for \0 */
 427 
 428         size = PERF_ALIGN(size, sizeof(u64));
 429         uaddr = (uintptr_t)code;
 430         ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries,
 431                            jd->unwinding_data, jd->eh_frame_hdr_size, jd->unwinding_size);
 432 
 433         if (jd->debug_data && jd->nr_debug_entries) {
 434                 zfree(&jd->debug_data);
 435                 jd->nr_debug_entries = 0;
 436         }
 437 
 438         if (jd->unwinding_data && jd->eh_frame_hdr_size) {
 439                 zfree(&jd->unwinding_data);
 440                 jd->eh_frame_hdr_size = 0;
 441                 jd->unwinding_mapped_size = 0;
 442                 jd->unwinding_size = 0;
 443         }
 444 
 445         if (ret) {
 446                 free(event);
 447                 return -1;
 448         }
 449         if (stat(filename, &st))
 450                 memset(&st, 0, sizeof(st));
 451 
 452         event->mmap2.header.type = PERF_RECORD_MMAP2;
 453         event->mmap2.header.misc = PERF_RECORD_MISC_USER;
 454         event->mmap2.header.size = (sizeof(event->mmap2) -
 455                         (sizeof(event->mmap2.filename) - size) + idr_size);
 456 
 457         event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
 458         event->mmap2.start = addr;
 459         event->mmap2.len   = usize ? ALIGN_8(csize) + usize : csize;
 460         event->mmap2.pid   = pid;
 461         event->mmap2.tid   = tid;
 462         event->mmap2.ino   = st.st_ino;
 463         event->mmap2.maj   = major(st.st_dev);
 464         event->mmap2.min   = minor(st.st_dev);
 465         event->mmap2.prot  = st.st_mode;
 466         event->mmap2.flags = MAP_SHARED;
 467         event->mmap2.ino_generation = 1;
 468 
 469         id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
 470         if (jd->sample_type & PERF_SAMPLE_TID) {
 471                 id->pid  = pid;
 472                 id->tid  = tid;
 473         }
 474         if (jd->sample_type & PERF_SAMPLE_TIME)
 475                 id->time = convert_timestamp(jd, jr->load.p.timestamp);
 476 
 477         /*
 478          * create pseudo sample to induce dso hit increment
 479          * use first address as sample address
 480          */
 481         memset(&sample, 0, sizeof(sample));
 482         sample.cpumode = PERF_RECORD_MISC_USER;
 483         sample.pid  = pid;
 484         sample.tid  = tid;
 485         sample.time = id->time;
 486         sample.ip   = addr;
 487 
 488         ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
 489         if (ret)
 490                 return ret;
 491 
 492         ret = jit_inject_event(jd, event);
 493         /*
 494          * mark dso as use to generate buildid in the header
 495          */
 496         if (!ret)
 497                 build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
 498 
 499         return ret;
 500 }
 501 
 502 static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
 503 {
 504         struct perf_sample sample;
 505         union perf_event *event;
 506         struct perf_tool *tool = jd->session->tool;
 507         char *filename;
 508         size_t size;
 509         struct stat st;
 510         int usize;
 511         u16 idr_size;
 512         int ret;
 513         pid_t pid, tid;
 514         struct {
 515                 u32 pid, tid;
 516                 u64 time;
 517         } *id;
 518 
 519         pid = jr->move.pid;
 520         tid =  jr->move.tid;
 521         usize = jd->unwinding_mapped_size;
 522         idr_size = jd->machine->id_hdr_size;
 523 
 524         /*
 525          * +16 to account for sample_id_all (hack)
 526          */
 527         event = calloc(1, sizeof(*event) + 16);
 528         if (!event)
 529                 return -1;
 530 
 531         filename = event->mmap2.filename;
 532         size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so",
 533                  jd->dir,
 534                  pid,
 535                  jr->move.code_index);
 536 
 537         size++; /* for \0 */
 538 
 539         if (stat(filename, &st))
 540                 memset(&st, 0, sizeof(st));
 541 
 542         size = PERF_ALIGN(size, sizeof(u64));
 543 
 544         event->mmap2.header.type = PERF_RECORD_MMAP2;
 545         event->mmap2.header.misc = PERF_RECORD_MISC_USER;
 546         event->mmap2.header.size = (sizeof(event->mmap2) -
 547                         (sizeof(event->mmap2.filename) - size) + idr_size);
 548         event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
 549         event->mmap2.start = jr->move.new_code_addr;
 550         event->mmap2.len   = usize ? ALIGN_8(jr->move.code_size) + usize
 551                                    : jr->move.code_size;
 552         event->mmap2.pid   = pid;
 553         event->mmap2.tid   = tid;
 554         event->mmap2.ino   = st.st_ino;
 555         event->mmap2.maj   = major(st.st_dev);
 556         event->mmap2.min   = minor(st.st_dev);
 557         event->mmap2.prot  = st.st_mode;
 558         event->mmap2.flags = MAP_SHARED;
 559         event->mmap2.ino_generation = 1;
 560 
 561         id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
 562         if (jd->sample_type & PERF_SAMPLE_TID) {
 563                 id->pid  = pid;
 564                 id->tid  = tid;
 565         }
 566         if (jd->sample_type & PERF_SAMPLE_TIME)
 567                 id->time = convert_timestamp(jd, jr->load.p.timestamp);
 568 
 569         /*
 570          * create pseudo sample to induce dso hit increment
 571          * use first address as sample address
 572          */
 573         memset(&sample, 0, sizeof(sample));
 574         sample.cpumode = PERF_RECORD_MISC_USER;
 575         sample.pid  = pid;
 576         sample.tid  = tid;
 577         sample.time = id->time;
 578         sample.ip   = jr->move.new_code_addr;
 579 
 580         ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
 581         if (ret)
 582                 return ret;
 583 
 584         ret = jit_inject_event(jd, event);
 585         if (!ret)
 586                 build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
 587 
 588         return ret;
 589 }
 590 
 591 static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
 592 {
 593         void *data;
 594         size_t sz;
 595 
 596         if (!(jd && jr))
 597                 return -1;
 598 
 599         sz  = jr->prefix.total_size - sizeof(jr->info);
 600         data = malloc(sz);
 601         if (!data)
 602                 return -1;
 603 
 604         memcpy(data, &jr->info.entries, sz);
 605 
 606         jd->debug_data       = data;
 607 
 608         /*
 609          * we must use nr_entry instead of size here because
 610          * we cannot distinguish actual entry from padding otherwise
 611          */
 612         jd->nr_debug_entries = jr->info.nr_entry;
 613 
 614         return 0;
 615 }
 616 
 617 static int
 618 jit_repipe_unwinding_info(struct jit_buf_desc *jd, union jr_entry *jr)
 619 {
 620         void *unwinding_data;
 621         uint32_t unwinding_data_size;
 622 
 623         if (!(jd && jr))
 624                 return -1;
 625 
 626         unwinding_data_size  = jr->prefix.total_size - sizeof(jr->unwinding);
 627         unwinding_data = malloc(unwinding_data_size);
 628         if (!unwinding_data)
 629                 return -1;
 630 
 631         memcpy(unwinding_data, &jr->unwinding.unwinding_data,
 632                unwinding_data_size);
 633 
 634         jd->eh_frame_hdr_size = jr->unwinding.eh_frame_hdr_size;
 635         jd->unwinding_size = jr->unwinding.unwinding_size;
 636         jd->unwinding_mapped_size = jr->unwinding.mapped_size;
 637         jd->unwinding_data = unwinding_data;
 638 
 639         return 0;
 640 }
 641 
 642 static int
 643 jit_process_dump(struct jit_buf_desc *jd)
 644 {
 645         union jr_entry *jr;
 646         int ret = 0;
 647 
 648         while ((jr = jit_get_next_entry(jd))) {
 649                 switch(jr->prefix.id) {
 650                 case JIT_CODE_LOAD:
 651                         ret = jit_repipe_code_load(jd, jr);
 652                         break;
 653                 case JIT_CODE_MOVE:
 654                         ret = jit_repipe_code_move(jd, jr);
 655                         break;
 656                 case JIT_CODE_DEBUG_INFO:
 657                         ret = jit_repipe_debug_info(jd, jr);
 658                         break;
 659                 case JIT_CODE_UNWINDING_INFO:
 660                         ret = jit_repipe_unwinding_info(jd, jr);
 661                         break;
 662                 default:
 663                         ret = 0;
 664                         continue;
 665                 }
 666         }
 667         return ret;
 668 }
 669 
 670 static int
 671 jit_inject(struct jit_buf_desc *jd, char *path)
 672 {
 673         int ret;
 674 
 675         if (verbose > 0)
 676                 fprintf(stderr, "injecting: %s\n", path);
 677 
 678         ret = jit_open(jd, path);
 679         if (ret)
 680                 return -1;
 681 
 682         ret = jit_process_dump(jd);
 683 
 684         jit_close(jd);
 685 
 686         if (verbose > 0)
 687                 fprintf(stderr, "injected: %s (%d)\n", path, ret);
 688 
 689         return 0;
 690 }
 691 
 692 /*
 693  * File must be with pattern .../jit-XXXX.dump
 694  * where XXXX is the PID of the process which did the mmap()
 695  * as captured in the RECORD_MMAP record
 696  */
 697 static int
 698 jit_detect(char *mmap_name, pid_t pid)
 699  {
 700         char *p;
 701         char *end = NULL;
 702         pid_t pid2;
 703 
 704         if (verbose > 2)
 705                 fprintf(stderr, "jit marker trying : %s\n", mmap_name);
 706         /*
 707          * get file name
 708          */
 709         p = strrchr(mmap_name, '/');
 710         if (!p)
 711                 return -1;
 712 
 713         /*
 714          * match prefix
 715          */
 716         if (strncmp(p, "/jit-", 5))
 717                 return -1;
 718 
 719         /*
 720          * skip prefix
 721          */
 722         p += 5;
 723 
 724         /*
 725          * must be followed by a pid
 726          */
 727         if (!isdigit(*p))
 728                 return -1;
 729 
 730         pid2 = (int)strtol(p, &end, 10);
 731         if (!end)
 732                 return -1;
 733 
 734         /*
 735          * pid does not match mmap pid
 736          * pid==0 in system-wide mode (synthesized)
 737          */
 738         if (pid && pid2 != pid)
 739                 return -1;
 740         /*
 741          * validate suffix
 742          */
 743         if (strcmp(end, ".dump"))
 744                 return -1;
 745 
 746         if (verbose > 0)
 747                 fprintf(stderr, "jit marker found: %s\n", mmap_name);
 748 
 749         return 0;
 750 }
 751 
 752 int
 753 jit_process(struct perf_session *session,
 754             struct perf_data *output,
 755             struct machine *machine,
 756             char *filename,
 757             pid_t pid,
 758             u64 *nbytes)
 759 {
 760         struct evsel *first;
 761         struct jit_buf_desc jd;
 762         int ret;
 763 
 764         /*
 765          * first, detect marker mmap (i.e., the jitdump mmap)
 766          */
 767         if (jit_detect(filename, pid))
 768                 return 0;
 769 
 770         memset(&jd, 0, sizeof(jd));
 771 
 772         jd.session = session;
 773         jd.output  = output;
 774         jd.machine = machine;
 775 
 776         /*
 777          * track sample_type to compute id_all layout
 778          * perf sets the same sample type to all events as of now
 779          */
 780         first = evlist__first(session->evlist);
 781         jd.sample_type = first->core.attr.sample_type;
 782 
 783         *nbytes = 0;
 784 
 785         ret = jit_inject(&jd, filename);
 786         if (!ret) {
 787                 *nbytes = jd.bytes_written;
 788                 ret = 1;
 789         }
 790 
 791         return ret;
 792 }

/* [<][>][^][v][top][bottom][index][help] */