| .. | .. |
|---|
| 2 | 2 | #include <sys/sysmacros.h> |
|---|
| 3 | 3 | #include <sys/types.h> |
|---|
| 4 | 4 | #include <errno.h> |
|---|
| 5 | +#include <libgen.h> |
|---|
| 5 | 6 | #include <stdio.h> |
|---|
| 6 | 7 | #include <stdlib.h> |
|---|
| 7 | 8 | #include <string.h> |
|---|
| .. | .. |
|---|
| 13 | 14 | #include <sys/mman.h> |
|---|
| 14 | 15 | #include <linux/stringify.h> |
|---|
| 15 | 16 | |
|---|
| 16 | | -#include "util.h" |
|---|
| 17 | +#include "build-id.h" |
|---|
| 17 | 18 | #include "event.h" |
|---|
| 18 | 19 | #include "debug.h" |
|---|
| 19 | 20 | #include "evlist.h" |
|---|
| .. | .. |
|---|
| 25 | 26 | #include "jit.h" |
|---|
| 26 | 27 | #include "jitdump.h" |
|---|
| 27 | 28 | #include "genelf.h" |
|---|
| 28 | | -#include "../builtin.h" |
|---|
| 29 | +#include "thread.h" |
|---|
| 29 | 30 | |
|---|
| 30 | | -#include "sane_ctype.h" |
|---|
| 31 | +#include <linux/ctype.h> |
|---|
| 32 | +#include <linux/zalloc.h> |
|---|
| 31 | 33 | |
|---|
| 32 | 34 | struct jit_buf_desc { |
|---|
| 33 | 35 | struct perf_data *output; |
|---|
| .. | .. |
|---|
| 38 | 40 | uint64_t sample_type; |
|---|
| 39 | 41 | size_t bufsize; |
|---|
| 40 | 42 | FILE *in; |
|---|
| 41 | | - bool needs_bswap; /* handles cross-endianess */ |
|---|
| 43 | + bool needs_bswap; /* handles cross-endianness */ |
|---|
| 42 | 44 | bool use_arch_timestamp; |
|---|
| 43 | 45 | void *debug_data; |
|---|
| 44 | 46 | void *unwinding_data; |
|---|
| .. | .. |
|---|
| 56 | 58 | unsigned long vma; |
|---|
| 57 | 59 | unsigned int lineno; |
|---|
| 58 | 60 | /* The filename format is unspecified, absolute path, relative etc. */ |
|---|
| 59 | | - char const filename[0]; |
|---|
| 61 | + char const filename[]; |
|---|
| 60 | 62 | }; |
|---|
| 61 | 63 | |
|---|
| 62 | 64 | struct jit_tool { |
|---|
| .. | .. |
|---|
| 116 | 118 | static int |
|---|
| 117 | 119 | jit_validate_events(struct perf_session *session) |
|---|
| 118 | 120 | { |
|---|
| 119 | | - struct perf_evsel *evsel; |
|---|
| 121 | + struct evsel *evsel; |
|---|
| 120 | 122 | |
|---|
| 121 | 123 | /* |
|---|
| 122 | 124 | * check that all events use CLOCK_MONOTONIC |
|---|
| 123 | 125 | */ |
|---|
| 124 | 126 | evlist__for_each_entry(session->evlist, evsel) { |
|---|
| 125 | | - if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC) |
|---|
| 127 | + if (evsel->core.attr.use_clockid == 0 || evsel->core.attr.clockid != CLOCK_MONOTONIC) |
|---|
| 126 | 128 | return -1; |
|---|
| 127 | 129 | } |
|---|
| 128 | 130 | return 0; |
|---|
| .. | .. |
|---|
| 367 | 369 | |
|---|
| 368 | 370 | static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp) |
|---|
| 369 | 371 | { |
|---|
| 370 | | - struct perf_tsc_conversion tc; |
|---|
| 372 | + struct perf_tsc_conversion tc = { .time_shift = 0, }; |
|---|
| 373 | + struct perf_record_time_conv *time_conv = &jd->session->time_conv; |
|---|
| 371 | 374 | |
|---|
| 372 | 375 | if (!jd->use_arch_timestamp) |
|---|
| 373 | 376 | return timestamp; |
|---|
| 374 | 377 | |
|---|
| 375 | | - tc.time_shift = jd->session->time_conv.time_shift; |
|---|
| 376 | | - tc.time_mult = jd->session->time_conv.time_mult; |
|---|
| 377 | | - tc.time_zero = jd->session->time_conv.time_zero; |
|---|
| 378 | + tc.time_shift = time_conv->time_shift; |
|---|
| 379 | + tc.time_mult = time_conv->time_mult; |
|---|
| 380 | + tc.time_zero = time_conv->time_zero; |
|---|
| 378 | 381 | |
|---|
| 379 | | - if (!tc.time_mult) |
|---|
| 380 | | - return 0; |
|---|
| 382 | + /* |
|---|
| 383 | + * The event TIME_CONV was extended for the fields from "time_cycles" |
|---|
| 384 | + * when supported cap_user_time_short, for backward compatibility, |
|---|
| 385 | + * checks the event size and assigns these extended fields if these |
|---|
| 386 | + * fields are contained in the event. |
|---|
| 387 | + */ |
|---|
| 388 | + if (event_contains(*time_conv, time_cycles)) { |
|---|
| 389 | + tc.time_cycles = time_conv->time_cycles; |
|---|
| 390 | + tc.time_mask = time_conv->time_mask; |
|---|
| 391 | + tc.cap_user_time_zero = time_conv->cap_user_time_zero; |
|---|
| 392 | + tc.cap_user_time_short = time_conv->cap_user_time_short; |
|---|
| 393 | + |
|---|
| 394 | + if (!tc.cap_user_time_zero) |
|---|
| 395 | + return 0; |
|---|
| 396 | + } |
|---|
| 381 | 397 | |
|---|
| 382 | 398 | return tsc_to_perf_time(timestamp, &tc); |
|---|
| 383 | 399 | } |
|---|
| .. | .. |
|---|
| 430 | 446 | jd->unwinding_data, jd->eh_frame_hdr_size, jd->unwinding_size); |
|---|
| 431 | 447 | |
|---|
| 432 | 448 | if (jd->debug_data && jd->nr_debug_entries) { |
|---|
| 433 | | - free(jd->debug_data); |
|---|
| 434 | | - jd->debug_data = NULL; |
|---|
| 449 | + zfree(&jd->debug_data); |
|---|
| 435 | 450 | jd->nr_debug_entries = 0; |
|---|
| 436 | 451 | } |
|---|
| 437 | 452 | |
|---|
| 438 | 453 | if (jd->unwinding_data && jd->eh_frame_hdr_size) { |
|---|
| 439 | | - free(jd->unwinding_data); |
|---|
| 440 | | - jd->unwinding_data = NULL; |
|---|
| 454 | + zfree(&jd->unwinding_data); |
|---|
| 441 | 455 | jd->eh_frame_hdr_size = 0; |
|---|
| 442 | 456 | jd->unwinding_mapped_size = 0; |
|---|
| 443 | 457 | jd->unwinding_size = 0; |
|---|
| .. | .. |
|---|
| 750 | 764 | return 0; |
|---|
| 751 | 765 | } |
|---|
| 752 | 766 | |
|---|
| 767 | +static void jit_add_pid(struct machine *machine, pid_t pid) |
|---|
| 768 | +{ |
|---|
| 769 | + struct thread *thread = machine__findnew_thread(machine, pid, pid); |
|---|
| 770 | + |
|---|
| 771 | + if (!thread) { |
|---|
| 772 | + pr_err("%s: thread %d not found or created\n", __func__, pid); |
|---|
| 773 | + return; |
|---|
| 774 | + } |
|---|
| 775 | + |
|---|
| 776 | + thread->priv = (void *)1; |
|---|
| 777 | +} |
|---|
| 778 | + |
|---|
| 779 | +static bool jit_has_pid(struct machine *machine, pid_t pid) |
|---|
| 780 | +{ |
|---|
| 781 | + struct thread *thread = machine__find_thread(machine, pid, pid); |
|---|
| 782 | + |
|---|
| 783 | + if (!thread) |
|---|
| 784 | + return 0; |
|---|
| 785 | + |
|---|
| 786 | + return (bool)thread->priv; |
|---|
| 787 | +} |
|---|
| 788 | + |
|---|
| 753 | 789 | int |
|---|
| 754 | 790 | jit_process(struct perf_session *session, |
|---|
| 755 | 791 | struct perf_data *output, |
|---|
| .. | .. |
|---|
| 758 | 794 | pid_t pid, |
|---|
| 759 | 795 | u64 *nbytes) |
|---|
| 760 | 796 | { |
|---|
| 761 | | - struct perf_evsel *first; |
|---|
| 797 | + struct evsel *first; |
|---|
| 762 | 798 | struct jit_buf_desc jd; |
|---|
| 763 | 799 | int ret; |
|---|
| 764 | 800 | |
|---|
| 765 | 801 | /* |
|---|
| 766 | 802 | * first, detect marker mmap (i.e., the jitdump mmap) |
|---|
| 767 | 803 | */ |
|---|
| 768 | | - if (jit_detect(filename, pid)) |
|---|
| 804 | + if (jit_detect(filename, pid)) { |
|---|
| 805 | + // Strip //anon* mmaps if we processed a jitdump for this pid |
|---|
| 806 | + if (jit_has_pid(machine, pid) && (strncmp(filename, "//anon", 6) == 0)) |
|---|
| 807 | + return 1; |
|---|
| 808 | + |
|---|
| 769 | 809 | return 0; |
|---|
| 810 | + } |
|---|
| 770 | 811 | |
|---|
| 771 | 812 | memset(&jd, 0, sizeof(jd)); |
|---|
| 772 | 813 | |
|---|
| .. | .. |
|---|
| 778 | 819 | * track sample_type to compute id_all layout |
|---|
| 779 | 820 | * perf sets the same sample type to all events as of now |
|---|
| 780 | 821 | */ |
|---|
| 781 | | - first = perf_evlist__first(session->evlist); |
|---|
| 782 | | - jd.sample_type = first->attr.sample_type; |
|---|
| 822 | + first = evlist__first(session->evlist); |
|---|
| 823 | + jd.sample_type = first->core.attr.sample_type; |
|---|
| 783 | 824 | |
|---|
| 784 | 825 | *nbytes = 0; |
|---|
| 785 | 826 | |
|---|
| 786 | 827 | ret = jit_inject(&jd, filename); |
|---|
| 787 | 828 | if (!ret) { |
|---|
| 829 | + jit_add_pid(machine, pid); |
|---|
| 788 | 830 | *nbytes = jd.bytes_written; |
|---|
| 789 | 831 | ret = 1; |
|---|
| 790 | 832 | } |
|---|