18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <sys/sysmacros.h> 38c2ecf20Sopenharmony_ci#include <sys/types.h> 48c2ecf20Sopenharmony_ci#include <errno.h> 58c2ecf20Sopenharmony_ci#include <libgen.h> 68c2ecf20Sopenharmony_ci#include <stdio.h> 78c2ecf20Sopenharmony_ci#include <stdlib.h> 88c2ecf20Sopenharmony_ci#include <string.h> 98c2ecf20Sopenharmony_ci#include <fcntl.h> 108c2ecf20Sopenharmony_ci#include <unistd.h> 118c2ecf20Sopenharmony_ci#include <inttypes.h> 128c2ecf20Sopenharmony_ci#include <byteswap.h> 138c2ecf20Sopenharmony_ci#include <sys/stat.h> 148c2ecf20Sopenharmony_ci#include <sys/mman.h> 158c2ecf20Sopenharmony_ci#include <linux/stringify.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "build-id.h" 188c2ecf20Sopenharmony_ci#include "event.h" 198c2ecf20Sopenharmony_ci#include "debug.h" 208c2ecf20Sopenharmony_ci#include "evlist.h" 218c2ecf20Sopenharmony_ci#include "symbol.h" 228c2ecf20Sopenharmony_ci#include <elf.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "tsc.h" 258c2ecf20Sopenharmony_ci#include "session.h" 268c2ecf20Sopenharmony_ci#include "jit.h" 278c2ecf20Sopenharmony_ci#include "jitdump.h" 288c2ecf20Sopenharmony_ci#include "genelf.h" 298c2ecf20Sopenharmony_ci#include "thread.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/ctype.h> 328c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct jit_buf_desc { 358c2ecf20Sopenharmony_ci struct perf_data *output; 368c2ecf20Sopenharmony_ci struct perf_session *session; 378c2ecf20Sopenharmony_ci struct machine *machine; 388c2ecf20Sopenharmony_ci union jr_entry *entry; 398c2ecf20Sopenharmony_ci void *buf; 408c2ecf20Sopenharmony_ci uint64_t sample_type; 418c2ecf20Sopenharmony_ci size_t bufsize; 428c2ecf20Sopenharmony_ci FILE *in; 438c2ecf20Sopenharmony_ci bool needs_bswap; /* handles cross-endianness */ 448c2ecf20Sopenharmony_ci bool use_arch_timestamp; 458c2ecf20Sopenharmony_ci void *debug_data; 468c2ecf20Sopenharmony_ci void *unwinding_data; 478c2ecf20Sopenharmony_ci uint64_t unwinding_size; 488c2ecf20Sopenharmony_ci uint64_t unwinding_mapped_size; 498c2ecf20Sopenharmony_ci uint64_t eh_frame_hdr_size; 508c2ecf20Sopenharmony_ci size_t nr_debug_entries; 518c2ecf20Sopenharmony_ci uint32_t code_load_count; 528c2ecf20Sopenharmony_ci u64 bytes_written; 538c2ecf20Sopenharmony_ci struct rb_root code_root; 548c2ecf20Sopenharmony_ci char dir[PATH_MAX]; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct debug_line_info { 588c2ecf20Sopenharmony_ci unsigned long vma; 598c2ecf20Sopenharmony_ci unsigned int lineno; 608c2ecf20Sopenharmony_ci /* The filename format is unspecified, absolute path, relative etc. */ 618c2ecf20Sopenharmony_ci char const filename[]; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistruct jit_tool { 658c2ecf20Sopenharmony_ci struct perf_tool tool; 668c2ecf20Sopenharmony_ci struct perf_data output; 678c2ecf20Sopenharmony_ci struct perf_data input; 688c2ecf20Sopenharmony_ci u64 bytes_written; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define hmax(a, b) ((a) > (b) ? (a) : (b)) 728c2ecf20Sopenharmony_ci#define get_jit_tool(t) (container_of(tool, struct jit_tool, tool)) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int 758c2ecf20Sopenharmony_cijit_emit_elf(char *filename, 768c2ecf20Sopenharmony_ci const char *sym, 778c2ecf20Sopenharmony_ci uint64_t code_addr, 788c2ecf20Sopenharmony_ci const void *code, 798c2ecf20Sopenharmony_ci int csize, 808c2ecf20Sopenharmony_ci void *debug, 818c2ecf20Sopenharmony_ci int nr_debug_entries, 828c2ecf20Sopenharmony_ci void *unwinding, 838c2ecf20Sopenharmony_ci uint32_t unwinding_header_size, 848c2ecf20Sopenharmony_ci uint32_t unwinding_size) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci int ret, fd; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (verbose > 0) 898c2ecf20Sopenharmony_ci fprintf(stderr, "write ELF image %s\n", filename); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644); 928c2ecf20Sopenharmony_ci if (fd == -1) { 938c2ecf20Sopenharmony_ci pr_warning("cannot create jit ELF %s: %s\n", filename, strerror(errno)); 948c2ecf20Sopenharmony_ci return -1; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries, 988c2ecf20Sopenharmony_ci unwinding, unwinding_header_size, unwinding_size); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci close(fd); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (ret) 1038c2ecf20Sopenharmony_ci unlink(filename); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return ret; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic void 1098c2ecf20Sopenharmony_cijit_close(struct jit_buf_desc *jd) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci if (!(jd && jd->in)) 1128c2ecf20Sopenharmony_ci return; 1138c2ecf20Sopenharmony_ci funlockfile(jd->in); 1148c2ecf20Sopenharmony_ci fclose(jd->in); 1158c2ecf20Sopenharmony_ci jd->in = NULL; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int 1198c2ecf20Sopenharmony_cijit_validate_events(struct perf_session *session) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct evsel *evsel; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* 1248c2ecf20Sopenharmony_ci * check that all events use CLOCK_MONOTONIC 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci evlist__for_each_entry(session->evlist, evsel) { 1278c2ecf20Sopenharmony_ci if (evsel->core.attr.use_clockid == 0 || evsel->core.attr.clockid != CLOCK_MONOTONIC) 1288c2ecf20Sopenharmony_ci return -1; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int 1348c2ecf20Sopenharmony_cijit_open(struct jit_buf_desc *jd, const char *name) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct jitheader header; 1378c2ecf20Sopenharmony_ci struct jr_prefix *prefix; 1388c2ecf20Sopenharmony_ci ssize_t bs, bsz = 0; 1398c2ecf20Sopenharmony_ci void *n, *buf = NULL; 1408c2ecf20Sopenharmony_ci int ret, retval = -1; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci jd->in = fopen(name, "r"); 1438c2ecf20Sopenharmony_ci if (!jd->in) 1448c2ecf20Sopenharmony_ci return -1; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci bsz = hmax(sizeof(header), sizeof(*prefix)); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci buf = malloc(bsz); 1498c2ecf20Sopenharmony_ci if (!buf) 1508c2ecf20Sopenharmony_ci goto error; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* 1538c2ecf20Sopenharmony_ci * protect from writer modifying the file while we are reading it 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ci flockfile(jd->in); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci ret = fread(buf, sizeof(header), 1, jd->in); 1588c2ecf20Sopenharmony_ci if (ret != 1) 1598c2ecf20Sopenharmony_ci goto error; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci memcpy(&header, buf, sizeof(header)); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (header.magic != JITHEADER_MAGIC) { 1648c2ecf20Sopenharmony_ci if (header.magic != JITHEADER_MAGIC_SW) 1658c2ecf20Sopenharmony_ci goto error; 1668c2ecf20Sopenharmony_ci jd->needs_bswap = true; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (jd->needs_bswap) { 1708c2ecf20Sopenharmony_ci header.version = bswap_32(header.version); 1718c2ecf20Sopenharmony_ci header.total_size = bswap_32(header.total_size); 1728c2ecf20Sopenharmony_ci header.pid = bswap_32(header.pid); 1738c2ecf20Sopenharmony_ci header.elf_mach = bswap_32(header.elf_mach); 1748c2ecf20Sopenharmony_ci header.timestamp = bswap_64(header.timestamp); 1758c2ecf20Sopenharmony_ci header.flags = bswap_64(header.flags); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (verbose > 2) 1818c2ecf20Sopenharmony_ci pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n", 1828c2ecf20Sopenharmony_ci header.version, 1838c2ecf20Sopenharmony_ci header.total_size, 1848c2ecf20Sopenharmony_ci (unsigned long long)header.timestamp, 1858c2ecf20Sopenharmony_ci header.pid, 1868c2ecf20Sopenharmony_ci header.elf_mach, 1878c2ecf20Sopenharmony_ci jd->use_arch_timestamp); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (header.version > JITHEADER_VERSION) { 1908c2ecf20Sopenharmony_ci pr_err("wrong jitdump version %u, expected " __stringify(JITHEADER_VERSION), 1918c2ecf20Sopenharmony_ci header.version); 1928c2ecf20Sopenharmony_ci goto error; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (header.flags & JITDUMP_FLAGS_RESERVED) { 1968c2ecf20Sopenharmony_ci pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n", 1978c2ecf20Sopenharmony_ci (unsigned long long)header.flags & JITDUMP_FLAGS_RESERVED); 1988c2ecf20Sopenharmony_ci goto error; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (jd->use_arch_timestamp && !jd->session->time_conv.time_mult) { 2028c2ecf20Sopenharmony_ci pr_err("jitdump file uses arch timestamps but there is no timestamp conversion\n"); 2038c2ecf20Sopenharmony_ci goto error; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * validate event is using the correct clockid 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci if (!jd->use_arch_timestamp && jit_validate_events(jd->session)) { 2108c2ecf20Sopenharmony_ci pr_err("error, jitted code must be sampled with perf record -k 1\n"); 2118c2ecf20Sopenharmony_ci goto error; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci bs = header.total_size - sizeof(header); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (bs > bsz) { 2178c2ecf20Sopenharmony_ci n = realloc(buf, bs); 2188c2ecf20Sopenharmony_ci if (!n) 2198c2ecf20Sopenharmony_ci goto error; 2208c2ecf20Sopenharmony_ci bsz = bs; 2218c2ecf20Sopenharmony_ci buf = n; 2228c2ecf20Sopenharmony_ci /* read extra we do not know about */ 2238c2ecf20Sopenharmony_ci ret = fread(buf, bs - bsz, 1, jd->in); 2248c2ecf20Sopenharmony_ci if (ret != 1) 2258c2ecf20Sopenharmony_ci goto error; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * keep dirname for generating files and mmap records 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci strcpy(jd->dir, name); 2318c2ecf20Sopenharmony_ci dirname(jd->dir); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_cierror: 2358c2ecf20Sopenharmony_ci funlockfile(jd->in); 2368c2ecf20Sopenharmony_ci fclose(jd->in); 2378c2ecf20Sopenharmony_ci return retval; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic union jr_entry * 2418c2ecf20Sopenharmony_cijit_get_next_entry(struct jit_buf_desc *jd) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct jr_prefix *prefix; 2448c2ecf20Sopenharmony_ci union jr_entry *jr; 2458c2ecf20Sopenharmony_ci void *addr; 2468c2ecf20Sopenharmony_ci size_t bs, size; 2478c2ecf20Sopenharmony_ci int id, ret; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (!(jd && jd->in)) 2508c2ecf20Sopenharmony_ci return NULL; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (jd->buf == NULL) { 2538c2ecf20Sopenharmony_ci size_t sz = getpagesize(); 2548c2ecf20Sopenharmony_ci if (sz < sizeof(*prefix)) 2558c2ecf20Sopenharmony_ci sz = sizeof(*prefix); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci jd->buf = malloc(sz); 2588c2ecf20Sopenharmony_ci if (jd->buf == NULL) 2598c2ecf20Sopenharmony_ci return NULL; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci jd->bufsize = sz; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci prefix = jd->buf; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* 2678c2ecf20Sopenharmony_ci * file is still locked at this point 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ci ret = fread(prefix, sizeof(*prefix), 1, jd->in); 2708c2ecf20Sopenharmony_ci if (ret != 1) 2718c2ecf20Sopenharmony_ci return NULL; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (jd->needs_bswap) { 2748c2ecf20Sopenharmony_ci prefix->id = bswap_32(prefix->id); 2758c2ecf20Sopenharmony_ci prefix->total_size = bswap_32(prefix->total_size); 2768c2ecf20Sopenharmony_ci prefix->timestamp = bswap_64(prefix->timestamp); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci id = prefix->id; 2798c2ecf20Sopenharmony_ci size = prefix->total_size; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci bs = (size_t)size; 2828c2ecf20Sopenharmony_ci if (bs < sizeof(*prefix)) 2838c2ecf20Sopenharmony_ci return NULL; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (id >= JIT_CODE_MAX) { 2868c2ecf20Sopenharmony_ci pr_warning("next_entry: unknown record type %d, skipping\n", id); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci if (bs > jd->bufsize) { 2898c2ecf20Sopenharmony_ci void *n; 2908c2ecf20Sopenharmony_ci n = realloc(jd->buf, bs); 2918c2ecf20Sopenharmony_ci if (!n) 2928c2ecf20Sopenharmony_ci return NULL; 2938c2ecf20Sopenharmony_ci jd->buf = n; 2948c2ecf20Sopenharmony_ci jd->bufsize = bs; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci addr = ((void *)jd->buf) + sizeof(*prefix); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ret = fread(addr, bs - sizeof(*prefix), 1, jd->in); 3008c2ecf20Sopenharmony_ci if (ret != 1) 3018c2ecf20Sopenharmony_ci return NULL; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci jr = (union jr_entry *)jd->buf; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci switch(id) { 3068c2ecf20Sopenharmony_ci case JIT_CODE_DEBUG_INFO: 3078c2ecf20Sopenharmony_ci if (jd->needs_bswap) { 3088c2ecf20Sopenharmony_ci uint64_t n; 3098c2ecf20Sopenharmony_ci jr->info.code_addr = bswap_64(jr->info.code_addr); 3108c2ecf20Sopenharmony_ci jr->info.nr_entry = bswap_64(jr->info.nr_entry); 3118c2ecf20Sopenharmony_ci for (n = 0 ; n < jr->info.nr_entry; n++) { 3128c2ecf20Sopenharmony_ci jr->info.entries[n].addr = bswap_64(jr->info.entries[n].addr); 3138c2ecf20Sopenharmony_ci jr->info.entries[n].lineno = bswap_32(jr->info.entries[n].lineno); 3148c2ecf20Sopenharmony_ci jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci case JIT_CODE_UNWINDING_INFO: 3198c2ecf20Sopenharmony_ci if (jd->needs_bswap) { 3208c2ecf20Sopenharmony_ci jr->unwinding.unwinding_size = bswap_64(jr->unwinding.unwinding_size); 3218c2ecf20Sopenharmony_ci jr->unwinding.eh_frame_hdr_size = bswap_64(jr->unwinding.eh_frame_hdr_size); 3228c2ecf20Sopenharmony_ci jr->unwinding.mapped_size = bswap_64(jr->unwinding.mapped_size); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci case JIT_CODE_CLOSE: 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci case JIT_CODE_LOAD: 3288c2ecf20Sopenharmony_ci if (jd->needs_bswap) { 3298c2ecf20Sopenharmony_ci jr->load.pid = bswap_32(jr->load.pid); 3308c2ecf20Sopenharmony_ci jr->load.tid = bswap_32(jr->load.tid); 3318c2ecf20Sopenharmony_ci jr->load.vma = bswap_64(jr->load.vma); 3328c2ecf20Sopenharmony_ci jr->load.code_addr = bswap_64(jr->load.code_addr); 3338c2ecf20Sopenharmony_ci jr->load.code_size = bswap_64(jr->load.code_size); 3348c2ecf20Sopenharmony_ci jr->load.code_index= bswap_64(jr->load.code_index); 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci jd->code_load_count++; 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci case JIT_CODE_MOVE: 3398c2ecf20Sopenharmony_ci if (jd->needs_bswap) { 3408c2ecf20Sopenharmony_ci jr->move.pid = bswap_32(jr->move.pid); 3418c2ecf20Sopenharmony_ci jr->move.tid = bswap_32(jr->move.tid); 3428c2ecf20Sopenharmony_ci jr->move.vma = bswap_64(jr->move.vma); 3438c2ecf20Sopenharmony_ci jr->move.old_code_addr = bswap_64(jr->move.old_code_addr); 3448c2ecf20Sopenharmony_ci jr->move.new_code_addr = bswap_64(jr->move.new_code_addr); 3458c2ecf20Sopenharmony_ci jr->move.code_size = bswap_64(jr->move.code_size); 3468c2ecf20Sopenharmony_ci jr->move.code_index = bswap_64(jr->move.code_index); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci case JIT_CODE_MAX: 3508c2ecf20Sopenharmony_ci default: 3518c2ecf20Sopenharmony_ci /* skip unknown record (we have read them) */ 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci return jr; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int 3588c2ecf20Sopenharmony_cijit_inject_event(struct jit_buf_desc *jd, union perf_event *event) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci ssize_t size; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci size = perf_data__write(jd->output, event, event->header.size); 3638c2ecf20Sopenharmony_ci if (size < 0) 3648c2ecf20Sopenharmony_ci return -1; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci jd->bytes_written += size; 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct perf_tsc_conversion tc = { .time_shift = 0, }; 3738c2ecf20Sopenharmony_ci struct perf_record_time_conv *time_conv = &jd->session->time_conv; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (!jd->use_arch_timestamp) 3768c2ecf20Sopenharmony_ci return timestamp; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci tc.time_shift = time_conv->time_shift; 3798c2ecf20Sopenharmony_ci tc.time_mult = time_conv->time_mult; 3808c2ecf20Sopenharmony_ci tc.time_zero = time_conv->time_zero; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* 3838c2ecf20Sopenharmony_ci * The event TIME_CONV was extended for the fields from "time_cycles" 3848c2ecf20Sopenharmony_ci * when supported cap_user_time_short, for backward compatibility, 3858c2ecf20Sopenharmony_ci * checks the event size and assigns these extended fields if these 3868c2ecf20Sopenharmony_ci * fields are contained in the event. 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci if (event_contains(*time_conv, time_cycles)) { 3898c2ecf20Sopenharmony_ci tc.time_cycles = time_conv->time_cycles; 3908c2ecf20Sopenharmony_ci tc.time_mask = time_conv->time_mask; 3918c2ecf20Sopenharmony_ci tc.cap_user_time_zero = time_conv->cap_user_time_zero; 3928c2ecf20Sopenharmony_ci tc.cap_user_time_short = time_conv->cap_user_time_short; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!tc.cap_user_time_zero) 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return tsc_to_perf_time(timestamp, &tc); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct perf_sample sample; 4048c2ecf20Sopenharmony_ci union perf_event *event; 4058c2ecf20Sopenharmony_ci struct perf_tool *tool = jd->session->tool; 4068c2ecf20Sopenharmony_ci uint64_t code, addr; 4078c2ecf20Sopenharmony_ci uintptr_t uaddr; 4088c2ecf20Sopenharmony_ci char *filename; 4098c2ecf20Sopenharmony_ci struct stat st; 4108c2ecf20Sopenharmony_ci size_t size; 4118c2ecf20Sopenharmony_ci u16 idr_size; 4128c2ecf20Sopenharmony_ci const char *sym; 4138c2ecf20Sopenharmony_ci uint64_t count; 4148c2ecf20Sopenharmony_ci int ret, csize, usize; 4158c2ecf20Sopenharmony_ci pid_t pid, tid; 4168c2ecf20Sopenharmony_ci struct { 4178c2ecf20Sopenharmony_ci u32 pid, tid; 4188c2ecf20Sopenharmony_ci u64 time; 4198c2ecf20Sopenharmony_ci } *id; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci pid = jr->load.pid; 4228c2ecf20Sopenharmony_ci tid = jr->load.tid; 4238c2ecf20Sopenharmony_ci csize = jr->load.code_size; 4248c2ecf20Sopenharmony_ci usize = jd->unwinding_mapped_size; 4258c2ecf20Sopenharmony_ci addr = jr->load.code_addr; 4268c2ecf20Sopenharmony_ci sym = (void *)((unsigned long)jr + sizeof(jr->load)); 4278c2ecf20Sopenharmony_ci code = (unsigned long)jr + jr->load.p.total_size - csize; 4288c2ecf20Sopenharmony_ci count = jr->load.code_index; 4298c2ecf20Sopenharmony_ci idr_size = jd->machine->id_hdr_size; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci event = calloc(1, sizeof(*event) + idr_size); 4328c2ecf20Sopenharmony_ci if (!event) 4338c2ecf20Sopenharmony_ci return -1; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci filename = event->mmap2.filename; 4368c2ecf20Sopenharmony_ci size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so", 4378c2ecf20Sopenharmony_ci jd->dir, 4388c2ecf20Sopenharmony_ci pid, 4398c2ecf20Sopenharmony_ci count); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci size++; /* for \0 */ 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci size = PERF_ALIGN(size, sizeof(u64)); 4448c2ecf20Sopenharmony_ci uaddr = (uintptr_t)code; 4458c2ecf20Sopenharmony_ci ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries, 4468c2ecf20Sopenharmony_ci jd->unwinding_data, jd->eh_frame_hdr_size, jd->unwinding_size); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (jd->debug_data && jd->nr_debug_entries) { 4498c2ecf20Sopenharmony_ci zfree(&jd->debug_data); 4508c2ecf20Sopenharmony_ci jd->nr_debug_entries = 0; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (jd->unwinding_data && jd->eh_frame_hdr_size) { 4548c2ecf20Sopenharmony_ci zfree(&jd->unwinding_data); 4558c2ecf20Sopenharmony_ci jd->eh_frame_hdr_size = 0; 4568c2ecf20Sopenharmony_ci jd->unwinding_mapped_size = 0; 4578c2ecf20Sopenharmony_ci jd->unwinding_size = 0; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (ret) { 4618c2ecf20Sopenharmony_ci free(event); 4628c2ecf20Sopenharmony_ci return -1; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci if (stat(filename, &st)) 4658c2ecf20Sopenharmony_ci memset(&st, 0, sizeof(st)); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci event->mmap2.header.type = PERF_RECORD_MMAP2; 4688c2ecf20Sopenharmony_ci event->mmap2.header.misc = PERF_RECORD_MISC_USER; 4698c2ecf20Sopenharmony_ci event->mmap2.header.size = (sizeof(event->mmap2) - 4708c2ecf20Sopenharmony_ci (sizeof(event->mmap2.filename) - size) + idr_size); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET; 4738c2ecf20Sopenharmony_ci event->mmap2.start = addr; 4748c2ecf20Sopenharmony_ci event->mmap2.len = usize ? ALIGN_8(csize) + usize : csize; 4758c2ecf20Sopenharmony_ci event->mmap2.pid = pid; 4768c2ecf20Sopenharmony_ci event->mmap2.tid = tid; 4778c2ecf20Sopenharmony_ci event->mmap2.ino = st.st_ino; 4788c2ecf20Sopenharmony_ci event->mmap2.maj = major(st.st_dev); 4798c2ecf20Sopenharmony_ci event->mmap2.min = minor(st.st_dev); 4808c2ecf20Sopenharmony_ci event->mmap2.prot = st.st_mode; 4818c2ecf20Sopenharmony_ci event->mmap2.flags = MAP_SHARED; 4828c2ecf20Sopenharmony_ci event->mmap2.ino_generation = 1; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci id = (void *)((unsigned long)event + event->mmap.header.size - idr_size); 4858c2ecf20Sopenharmony_ci if (jd->sample_type & PERF_SAMPLE_TID) { 4868c2ecf20Sopenharmony_ci id->pid = pid; 4878c2ecf20Sopenharmony_ci id->tid = tid; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci if (jd->sample_type & PERF_SAMPLE_TIME) 4908c2ecf20Sopenharmony_ci id->time = convert_timestamp(jd, jr->load.p.timestamp); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* 4938c2ecf20Sopenharmony_ci * create pseudo sample to induce dso hit increment 4948c2ecf20Sopenharmony_ci * use first address as sample address 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci memset(&sample, 0, sizeof(sample)); 4978c2ecf20Sopenharmony_ci sample.cpumode = PERF_RECORD_MISC_USER; 4988c2ecf20Sopenharmony_ci sample.pid = pid; 4998c2ecf20Sopenharmony_ci sample.tid = tid; 5008c2ecf20Sopenharmony_ci sample.time = id->time; 5018c2ecf20Sopenharmony_ci sample.ip = addr; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci ret = perf_event__process_mmap2(tool, event, &sample, jd->machine); 5048c2ecf20Sopenharmony_ci if (ret) 5058c2ecf20Sopenharmony_ci return ret; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci ret = jit_inject_event(jd, event); 5088c2ecf20Sopenharmony_ci /* 5098c2ecf20Sopenharmony_ci * mark dso as use to generate buildid in the header 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_ci if (!ret) 5128c2ecf20Sopenharmony_ci build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return ret; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct perf_sample sample; 5208c2ecf20Sopenharmony_ci union perf_event *event; 5218c2ecf20Sopenharmony_ci struct perf_tool *tool = jd->session->tool; 5228c2ecf20Sopenharmony_ci char *filename; 5238c2ecf20Sopenharmony_ci size_t size; 5248c2ecf20Sopenharmony_ci struct stat st; 5258c2ecf20Sopenharmony_ci int usize; 5268c2ecf20Sopenharmony_ci u16 idr_size; 5278c2ecf20Sopenharmony_ci int ret; 5288c2ecf20Sopenharmony_ci pid_t pid, tid; 5298c2ecf20Sopenharmony_ci struct { 5308c2ecf20Sopenharmony_ci u32 pid, tid; 5318c2ecf20Sopenharmony_ci u64 time; 5328c2ecf20Sopenharmony_ci } *id; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci pid = jr->move.pid; 5358c2ecf20Sopenharmony_ci tid = jr->move.tid; 5368c2ecf20Sopenharmony_ci usize = jd->unwinding_mapped_size; 5378c2ecf20Sopenharmony_ci idr_size = jd->machine->id_hdr_size; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* 5408c2ecf20Sopenharmony_ci * +16 to account for sample_id_all (hack) 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci event = calloc(1, sizeof(*event) + 16); 5438c2ecf20Sopenharmony_ci if (!event) 5448c2ecf20Sopenharmony_ci return -1; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci filename = event->mmap2.filename; 5478c2ecf20Sopenharmony_ci size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so", 5488c2ecf20Sopenharmony_ci jd->dir, 5498c2ecf20Sopenharmony_ci pid, 5508c2ecf20Sopenharmony_ci jr->move.code_index); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci size++; /* for \0 */ 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (stat(filename, &st)) 5558c2ecf20Sopenharmony_ci memset(&st, 0, sizeof(st)); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci size = PERF_ALIGN(size, sizeof(u64)); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci event->mmap2.header.type = PERF_RECORD_MMAP2; 5608c2ecf20Sopenharmony_ci event->mmap2.header.misc = PERF_RECORD_MISC_USER; 5618c2ecf20Sopenharmony_ci event->mmap2.header.size = (sizeof(event->mmap2) - 5628c2ecf20Sopenharmony_ci (sizeof(event->mmap2.filename) - size) + idr_size); 5638c2ecf20Sopenharmony_ci event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET; 5648c2ecf20Sopenharmony_ci event->mmap2.start = jr->move.new_code_addr; 5658c2ecf20Sopenharmony_ci event->mmap2.len = usize ? ALIGN_8(jr->move.code_size) + usize 5668c2ecf20Sopenharmony_ci : jr->move.code_size; 5678c2ecf20Sopenharmony_ci event->mmap2.pid = pid; 5688c2ecf20Sopenharmony_ci event->mmap2.tid = tid; 5698c2ecf20Sopenharmony_ci event->mmap2.ino = st.st_ino; 5708c2ecf20Sopenharmony_ci event->mmap2.maj = major(st.st_dev); 5718c2ecf20Sopenharmony_ci event->mmap2.min = minor(st.st_dev); 5728c2ecf20Sopenharmony_ci event->mmap2.prot = st.st_mode; 5738c2ecf20Sopenharmony_ci event->mmap2.flags = MAP_SHARED; 5748c2ecf20Sopenharmony_ci event->mmap2.ino_generation = 1; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci id = (void *)((unsigned long)event + event->mmap.header.size - idr_size); 5778c2ecf20Sopenharmony_ci if (jd->sample_type & PERF_SAMPLE_TID) { 5788c2ecf20Sopenharmony_ci id->pid = pid; 5798c2ecf20Sopenharmony_ci id->tid = tid; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci if (jd->sample_type & PERF_SAMPLE_TIME) 5828c2ecf20Sopenharmony_ci id->time = convert_timestamp(jd, jr->load.p.timestamp); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* 5858c2ecf20Sopenharmony_ci * create pseudo sample to induce dso hit increment 5868c2ecf20Sopenharmony_ci * use first address as sample address 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_ci memset(&sample, 0, sizeof(sample)); 5898c2ecf20Sopenharmony_ci sample.cpumode = PERF_RECORD_MISC_USER; 5908c2ecf20Sopenharmony_ci sample.pid = pid; 5918c2ecf20Sopenharmony_ci sample.tid = tid; 5928c2ecf20Sopenharmony_ci sample.time = id->time; 5938c2ecf20Sopenharmony_ci sample.ip = jr->move.new_code_addr; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci ret = perf_event__process_mmap2(tool, event, &sample, jd->machine); 5968c2ecf20Sopenharmony_ci if (ret) 5978c2ecf20Sopenharmony_ci return ret; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci ret = jit_inject_event(jd, event); 6008c2ecf20Sopenharmony_ci if (!ret) 6018c2ecf20Sopenharmony_ci build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return ret; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci void *data; 6098c2ecf20Sopenharmony_ci size_t sz; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (!(jd && jr)) 6128c2ecf20Sopenharmony_ci return -1; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci sz = jr->prefix.total_size - sizeof(jr->info); 6158c2ecf20Sopenharmony_ci data = malloc(sz); 6168c2ecf20Sopenharmony_ci if (!data) 6178c2ecf20Sopenharmony_ci return -1; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci memcpy(data, &jr->info.entries, sz); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci jd->debug_data = data; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* 6248c2ecf20Sopenharmony_ci * we must use nr_entry instead of size here because 6258c2ecf20Sopenharmony_ci * we cannot distinguish actual entry from padding otherwise 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci jd->nr_debug_entries = jr->info.nr_entry; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci return 0; 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cistatic int 6338c2ecf20Sopenharmony_cijit_repipe_unwinding_info(struct jit_buf_desc *jd, union jr_entry *jr) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci void *unwinding_data; 6368c2ecf20Sopenharmony_ci uint32_t unwinding_data_size; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (!(jd && jr)) 6398c2ecf20Sopenharmony_ci return -1; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci unwinding_data_size = jr->prefix.total_size - sizeof(jr->unwinding); 6428c2ecf20Sopenharmony_ci unwinding_data = malloc(unwinding_data_size); 6438c2ecf20Sopenharmony_ci if (!unwinding_data) 6448c2ecf20Sopenharmony_ci return -1; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci memcpy(unwinding_data, &jr->unwinding.unwinding_data, 6478c2ecf20Sopenharmony_ci unwinding_data_size); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci jd->eh_frame_hdr_size = jr->unwinding.eh_frame_hdr_size; 6508c2ecf20Sopenharmony_ci jd->unwinding_size = jr->unwinding.unwinding_size; 6518c2ecf20Sopenharmony_ci jd->unwinding_mapped_size = jr->unwinding.mapped_size; 6528c2ecf20Sopenharmony_ci jd->unwinding_data = unwinding_data; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci return 0; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic int 6588c2ecf20Sopenharmony_cijit_process_dump(struct jit_buf_desc *jd) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci union jr_entry *jr; 6618c2ecf20Sopenharmony_ci int ret = 0; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci while ((jr = jit_get_next_entry(jd))) { 6648c2ecf20Sopenharmony_ci switch(jr->prefix.id) { 6658c2ecf20Sopenharmony_ci case JIT_CODE_LOAD: 6668c2ecf20Sopenharmony_ci ret = jit_repipe_code_load(jd, jr); 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci case JIT_CODE_MOVE: 6698c2ecf20Sopenharmony_ci ret = jit_repipe_code_move(jd, jr); 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci case JIT_CODE_DEBUG_INFO: 6728c2ecf20Sopenharmony_ci ret = jit_repipe_debug_info(jd, jr); 6738c2ecf20Sopenharmony_ci break; 6748c2ecf20Sopenharmony_ci case JIT_CODE_UNWINDING_INFO: 6758c2ecf20Sopenharmony_ci ret = jit_repipe_unwinding_info(jd, jr); 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci default: 6788c2ecf20Sopenharmony_ci ret = 0; 6798c2ecf20Sopenharmony_ci continue; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci return ret; 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistatic int 6868c2ecf20Sopenharmony_cijit_inject(struct jit_buf_desc *jd, char *path) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci int ret; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (verbose > 0) 6918c2ecf20Sopenharmony_ci fprintf(stderr, "injecting: %s\n", path); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci ret = jit_open(jd, path); 6948c2ecf20Sopenharmony_ci if (ret) 6958c2ecf20Sopenharmony_ci return -1; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci ret = jit_process_dump(jd); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci jit_close(jd); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (verbose > 0) 7028c2ecf20Sopenharmony_ci fprintf(stderr, "injected: %s (%d)\n", path, ret); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci return 0; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci/* 7088c2ecf20Sopenharmony_ci * File must be with pattern .../jit-XXXX.dump 7098c2ecf20Sopenharmony_ci * where XXXX is the PID of the process which did the mmap() 7108c2ecf20Sopenharmony_ci * as captured in the RECORD_MMAP record 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_cistatic int 7138c2ecf20Sopenharmony_cijit_detect(char *mmap_name, pid_t pid) 7148c2ecf20Sopenharmony_ci { 7158c2ecf20Sopenharmony_ci char *p; 7168c2ecf20Sopenharmony_ci char *end = NULL; 7178c2ecf20Sopenharmony_ci pid_t pid2; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (verbose > 2) 7208c2ecf20Sopenharmony_ci fprintf(stderr, "jit marker trying : %s\n", mmap_name); 7218c2ecf20Sopenharmony_ci /* 7228c2ecf20Sopenharmony_ci * get file name 7238c2ecf20Sopenharmony_ci */ 7248c2ecf20Sopenharmony_ci p = strrchr(mmap_name, '/'); 7258c2ecf20Sopenharmony_ci if (!p) 7268c2ecf20Sopenharmony_ci return -1; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* 7298c2ecf20Sopenharmony_ci * match prefix 7308c2ecf20Sopenharmony_ci */ 7318c2ecf20Sopenharmony_ci if (strncmp(p, "/jit-", 5)) 7328c2ecf20Sopenharmony_ci return -1; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* 7358c2ecf20Sopenharmony_ci * skip prefix 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_ci p += 5; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* 7408c2ecf20Sopenharmony_ci * must be followed by a pid 7418c2ecf20Sopenharmony_ci */ 7428c2ecf20Sopenharmony_ci if (!isdigit(*p)) 7438c2ecf20Sopenharmony_ci return -1; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci pid2 = (int)strtol(p, &end, 10); 7468c2ecf20Sopenharmony_ci if (!end) 7478c2ecf20Sopenharmony_ci return -1; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* 7508c2ecf20Sopenharmony_ci * pid does not match mmap pid 7518c2ecf20Sopenharmony_ci * pid==0 in system-wide mode (synthesized) 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_ci if (pid && pid2 != pid) 7548c2ecf20Sopenharmony_ci return -1; 7558c2ecf20Sopenharmony_ci /* 7568c2ecf20Sopenharmony_ci * validate suffix 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_ci if (strcmp(end, ".dump")) 7598c2ecf20Sopenharmony_ci return -1; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (verbose > 0) 7628c2ecf20Sopenharmony_ci fprintf(stderr, "jit marker found: %s\n", mmap_name); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic void jit_add_pid(struct machine *machine, pid_t pid) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct thread *thread = machine__findnew_thread(machine, pid, pid); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (!thread) { 7728c2ecf20Sopenharmony_ci pr_err("%s: thread %d not found or created\n", __func__, pid); 7738c2ecf20Sopenharmony_ci return; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci thread->priv = (void *)1; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic bool jit_has_pid(struct machine *machine, pid_t pid) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci struct thread *thread = machine__find_thread(machine, pid, pid); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (!thread) 7848c2ecf20Sopenharmony_ci return 0; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci return (bool)thread->priv; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ciint 7908c2ecf20Sopenharmony_cijit_process(struct perf_session *session, 7918c2ecf20Sopenharmony_ci struct perf_data *output, 7928c2ecf20Sopenharmony_ci struct machine *machine, 7938c2ecf20Sopenharmony_ci char *filename, 7948c2ecf20Sopenharmony_ci pid_t pid, 7958c2ecf20Sopenharmony_ci u64 *nbytes) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci struct evsel *first; 7988c2ecf20Sopenharmony_ci struct jit_buf_desc jd; 7998c2ecf20Sopenharmony_ci int ret; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci /* 8028c2ecf20Sopenharmony_ci * first, detect marker mmap (i.e., the jitdump mmap) 8038c2ecf20Sopenharmony_ci */ 8048c2ecf20Sopenharmony_ci if (jit_detect(filename, pid)) { 8058c2ecf20Sopenharmony_ci // Strip //anon* mmaps if we processed a jitdump for this pid 8068c2ecf20Sopenharmony_ci if (jit_has_pid(machine, pid) && (strncmp(filename, "//anon", 6) == 0)) 8078c2ecf20Sopenharmony_ci return 1; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci return 0; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci memset(&jd, 0, sizeof(jd)); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci jd.session = session; 8158c2ecf20Sopenharmony_ci jd.output = output; 8168c2ecf20Sopenharmony_ci jd.machine = machine; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* 8198c2ecf20Sopenharmony_ci * track sample_type to compute id_all layout 8208c2ecf20Sopenharmony_ci * perf sets the same sample type to all events as of now 8218c2ecf20Sopenharmony_ci */ 8228c2ecf20Sopenharmony_ci first = evlist__first(session->evlist); 8238c2ecf20Sopenharmony_ci jd.sample_type = first->core.attr.sample_type; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci *nbytes = 0; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci ret = jit_inject(&jd, filename); 8288c2ecf20Sopenharmony_ci if (!ret) { 8298c2ecf20Sopenharmony_ci jit_add_pid(machine, pid); 8308c2ecf20Sopenharmony_ci *nbytes = jd.bytes_written; 8318c2ecf20Sopenharmony_ci ret = 1; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci return ret; 8358c2ecf20Sopenharmony_ci} 836