2 #include <sys/sysmacros.h> 14 #include <linux/stringify.h> 28 #include "../builtin.h" 69 #define hmax(a, b) ((a) > (b) ? (a) : (b)) 70 #define get_jit_tool(t) (container_of(tool, struct jit_tool, tool)) 81 uint32_t unwinding_header_size,
87 fprintf(stderr,
"write ELF image %s\n", filename);
89 fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
95 ret =
jit_write_elf(fd, code_addr, sym, (
const void *)code, csize, debug, nr_debug_entries,
96 unwinding, unwinding_header_size, unwinding_size);
125 if (evsel->
attr.use_clockid == 0 || evsel->
attr.clockid != CLOCK_MONOTONIC)
137 void *n, *
buf = NULL;
138 int ret, retval = -1;
140 jd->
in = fopen(name,
"r");
144 bsz =
hmax(
sizeof(header),
sizeof(*prefix));
155 ret = fread(buf,
sizeof(header), 1, jd->
in);
159 memcpy(&header, buf,
sizeof(header));
170 header.
pid = bswap_32(header.
pid);
179 pr_debug(
"version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n",
194 pr_err(
"jitdump file contains invalid or unsupported flags 0x%llx\n",
200 pr_err(
"jitdump file uses arch timestamps but there is no timestamp conversion\n");
208 pr_err(
"error, jitted code must be sampled with perf record -k 1\n");
215 n = realloc(buf, bs);
221 ret = fread(buf, bs - bsz, 1, jd->
in);
228 strcpy(jd->
dir, name);
250 if (jd->
buf == NULL) {
251 size_t sz = getpagesize();
252 if (sz <
sizeof(*prefix))
253 sz =
sizeof(*prefix);
267 ret = fread(prefix,
sizeof(*prefix), 1, jd->
in);
272 prefix->
id = bswap_32(prefix->
id);
280 if (bs <
sizeof(*prefix))
284 pr_warning(
"next_entry: unknown record type %d, skipping\n",
id);
288 n = realloc(jd->
buf, bs);
295 addr = ((
void *)jd->
buf) +
sizeof(*prefix);
297 ret = fread(addr, bs -
sizeof(*prefix), 1, jd->
in);
398 int ret, csize, usize;
410 sym = (
void *)((
unsigned long)jr +
sizeof(jr->
load));
415 event = calloc(1,
sizeof(*event) + idr_size);
420 size = snprintf(filename,
PATH_MAX,
"%s/jitted-%d-%u.so",
427 size = PERF_ALIGN(size,
sizeof(u64));
428 uaddr = (uintptr_t)code;
450 if (stat(filename, &st))
451 memset(&st, 0,
sizeof(st));
453 event->mmap2.header.type = PERF_RECORD_MMAP2;
454 event->mmap2.header.misc = PERF_RECORD_MISC_USER;
455 event->mmap2.header.size = (
sizeof(
event->mmap2) -
459 event->mmap2.start = addr;
460 event->mmap2.len = usize ?
ALIGN_8(csize) + usize : csize;
461 event->mmap2.pid =
pid;
462 event->mmap2.tid = tid;
463 event->mmap2.ino = st.st_ino;
464 event->mmap2.maj = major(st.st_dev);
465 event->mmap2.min = minor(st.st_dev);
466 event->mmap2.prot = st.st_mode;
467 event->mmap2.flags = MAP_SHARED;
468 event->mmap2.ino_generation = 1;
470 id = (
void *)((
unsigned long)
event +
event->mmap.header.size - idr_size);
482 memset(&sample, 0,
sizeof(sample));
483 sample.
cpumode = PERF_RECORD_MISC_USER;
486 sample.
time =
id->time;
528 event = calloc(1,
sizeof(*event) + 16);
532 filename =
event->mmap2.filename;
533 size = snprintf(filename,
PATH_MAX,
"%s/jitted-%d-%"PRIu64,
540 if (stat(filename, &st))
541 memset(&st, 0,
sizeof(st));
543 size = PERF_ALIGN(size,
sizeof(u64));
545 event->mmap2.header.type = PERF_RECORD_MMAP2;
546 event->mmap2.header.misc = PERF_RECORD_MISC_USER;
547 event->mmap2.header.size = (
sizeof(
event->mmap2) -
553 event->mmap2.pid =
pid;
554 event->mmap2.tid = tid;
555 event->mmap2.ino = st.st_ino;
556 event->mmap2.maj = major(st.st_dev);
557 event->mmap2.min = minor(st.st_dev);
558 event->mmap2.prot = st.st_mode;
559 event->mmap2.flags = MAP_SHARED;
560 event->mmap2.ino_generation = 1;
562 id = (
void *)((
unsigned long)
event +
event->mmap.header.size - idr_size);
574 memset(&sample, 0,
sizeof(sample));
575 sample.
cpumode = PERF_RECORD_MISC_USER;
578 sample.
time =
id->time;
622 uint32_t unwinding_data_size;
628 unwinding_data =
malloc(unwinding_data_size);
633 unwinding_data_size);
677 fprintf(stderr,
"injecting: %s\n", path);
688 fprintf(stderr,
"injected: %s (%d)\n", path, ret);
706 fprintf(stderr,
"jit marker trying : %s\n", mmap_name);
710 p = strrchr(mmap_name,
'/');
717 if (strncmp(p,
"/jit-", 5))
731 pid2 = (int)strtol(p, &end, 10);
739 if (pid && pid2 != pid)
744 if (strcmp(end,
".dump"))
748 fprintf(stderr,
"jit marker found: %s\n", mmap_name);
771 memset(&jd, 0,
sizeof(jd));
static int jit_open(struct jit_buf_desc *jd, const char *name)
static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
struct perf_evlist * evlist
#define GEN_ELF_TEXT_OFFSET
#define JITDUMP_FLAGS_ARCH_TIMESTAMP
uint64_t unwinding_mapped_size
struct time_conv_event time_conv
struct perf_data * output
uint64_t eh_frame_hdr_size
uint64_t eh_frame_hdr_size
static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
#define JITHEADER_VERSION
static int input(yyscan_t yyscanner)
struct jr_code_unwinding_info unwinding
static int jit_repipe_unwinding_info(struct jit_buf_desc *jd, union jr_entry *jr)
static union jr_entry * jit_get_next_entry(struct jit_buf_desc *jd)
static int jit_detect(char *mmap_name, pid_t pid)
int jit_process(struct perf_session *session, struct perf_data *output, struct machine *machine, char *filename, pid_t pid, u64 *nbytes)
static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp)
x86 movsq based memset() in arch/x86/lib/memset_64.S") MEMSET_FN(memset_erms
int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __maybe_unused, struct machine *machine)
#define JITHEADER_MAGIC_SW
static int jit_validate_events(struct perf_session *session)
#define pr_debug(fmt,...)
#define evlist__for_each_entry(evlist, evsel)
static int jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
static struct perf_tool tool
static int jit_inject(struct jit_buf_desc *jd, char *path)
static void jit_close(struct jit_buf_desc *jd)
x86 movsq based memcpy() in arch/x86/lib/memcpy_64.S") MEMCPY_FN(memcpy_erms
struct debug_entry entries[0]
#define JITDUMP_FLAGS_RESERVED
struct perf_event_header header
int jit_write_elf(int fd, uint64_t load_addr, const char *sym, const void *code, int csize, void *debug __maybe_unused, int nr_debug_entries __maybe_unused, void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size)
static struct perf_evsel * perf_evlist__first(struct perf_evlist *evlist)
int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct machine *machine)
const char unwinding_data[0]
u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
static int sym(yyscan_t scanner, int type, int config)
ssize_t perf_data__write(struct perf_data *data, void *buf, size_t size)
struct jr_code_debug_info info
static int jit_process_dump(struct jit_buf_desc *jd)
#define pr_warning(fmt,...)
struct perf_session * session
static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
struct perf_event_attr attr
static int jit_emit_elf(char *filename, const char *sym, uint64_t code_addr, const void *code, int csize, void *debug, int nr_debug_entries, void *unwinding, uint32_t unwinding_header_size, uint32_t unwinding_size)