cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

jitdump.c (20265B)


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