18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * jvmti_agent.c: JVMTI agent interface
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Adapted from the Oprofile code in opagent.c:
58c2ecf20Sopenharmony_ci * This library is free software; you can redistribute it and/or
68c2ecf20Sopenharmony_ci * modify it under the terms of the GNU Lesser General Public
78c2ecf20Sopenharmony_ci * License as published by the Free Software Foundation; either
88c2ecf20Sopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * This library is distributed in the hope that it will be useful,
118c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
128c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
138c2ecf20Sopenharmony_ci * Lesser General Public License for more details.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public
168c2ecf20Sopenharmony_ci * License along with this library; if not, write to the Free Software
178c2ecf20Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * Copyright 2007 OProfile authors
208c2ecf20Sopenharmony_ci * Jens Wilke
218c2ecf20Sopenharmony_ci * Daniel Hansel
228c2ecf20Sopenharmony_ci * Copyright IBM Corporation 2007
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci#include <sys/types.h>
258c2ecf20Sopenharmony_ci#include <sys/stat.h> /* for mkdir() */
268c2ecf20Sopenharmony_ci#include <stdio.h>
278c2ecf20Sopenharmony_ci#include <errno.h>
288c2ecf20Sopenharmony_ci#include <string.h>
298c2ecf20Sopenharmony_ci#include <stdlib.h>
308c2ecf20Sopenharmony_ci#include <stdint.h>
318c2ecf20Sopenharmony_ci#include <limits.h>
328c2ecf20Sopenharmony_ci#include <fcntl.h>
338c2ecf20Sopenharmony_ci#include <unistd.h>
348c2ecf20Sopenharmony_ci#include <time.h>
358c2ecf20Sopenharmony_ci#include <sys/mman.h>
368c2ecf20Sopenharmony_ci#include <syscall.h> /* for gettid() */
378c2ecf20Sopenharmony_ci#include <err.h>
388c2ecf20Sopenharmony_ci#include <linux/kernel.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include "jvmti_agent.h"
418c2ecf20Sopenharmony_ci#include "../util/jitdump.h"
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define JIT_LANG "java"
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic char jit_path[PATH_MAX];
468c2ecf20Sopenharmony_cistatic void *marker_addr;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#ifndef HAVE_GETTID
498c2ecf20Sopenharmony_cistatic inline pid_t gettid(void)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	return (pid_t)syscall(__NR_gettid);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci#endif
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic int get_e_machine(struct jitheader *hdr)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	ssize_t sret;
588c2ecf20Sopenharmony_ci	char id[16];
598c2ecf20Sopenharmony_ci	int fd, ret = -1;
608c2ecf20Sopenharmony_ci	struct {
618c2ecf20Sopenharmony_ci		uint16_t e_type;
628c2ecf20Sopenharmony_ci		uint16_t e_machine;
638c2ecf20Sopenharmony_ci	} info;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	fd = open("/proc/self/exe", O_RDONLY);
668c2ecf20Sopenharmony_ci	if (fd == -1)
678c2ecf20Sopenharmony_ci		return -1;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	sret = read(fd, id, sizeof(id));
708c2ecf20Sopenharmony_ci	if (sret != sizeof(id))
718c2ecf20Sopenharmony_ci		goto error;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	/* check ELF signature */
748c2ecf20Sopenharmony_ci	if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F')
758c2ecf20Sopenharmony_ci		goto error;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	sret = read(fd, &info, sizeof(info));
788c2ecf20Sopenharmony_ci	if (sret != sizeof(info))
798c2ecf20Sopenharmony_ci		goto error;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	hdr->elf_mach = info.e_machine;
828c2ecf20Sopenharmony_ci	ret = 0;
838c2ecf20Sopenharmony_cierror:
848c2ecf20Sopenharmony_ci	close(fd);
858c2ecf20Sopenharmony_ci	return ret;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic int use_arch_timestamp;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic inline uint64_t
918c2ecf20Sopenharmony_ciget_arch_timestamp(void)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__)
948c2ecf20Sopenharmony_ci	unsigned int low, high;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	asm volatile("rdtsc" : "=a" (low), "=d" (high));
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return low | ((uint64_t)high) << 32;
998c2ecf20Sopenharmony_ci#else
1008c2ecf20Sopenharmony_ci	return 0;
1018c2ecf20Sopenharmony_ci#endif
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#define NSEC_PER_SEC	1000000000
1058c2ecf20Sopenharmony_cistatic int perf_clk_id = CLOCK_MONOTONIC;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic inline uint64_t
1088c2ecf20Sopenharmony_citimespec_to_ns(const struct timespec *ts)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci        return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic inline uint64_t
1148c2ecf20Sopenharmony_ciperf_get_timestamp(void)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct timespec ts;
1178c2ecf20Sopenharmony_ci	int ret;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (use_arch_timestamp)
1208c2ecf20Sopenharmony_ci		return get_arch_timestamp();
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	ret = clock_gettime(perf_clk_id, &ts);
1238c2ecf20Sopenharmony_ci	if (ret)
1248c2ecf20Sopenharmony_ci		return 0;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	return timespec_to_ns(&ts);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic int
1308c2ecf20Sopenharmony_cicreate_jit_cache_dir(void)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	char str[32];
1338c2ecf20Sopenharmony_ci	char *base, *p;
1348c2ecf20Sopenharmony_ci	struct tm tm;
1358c2ecf20Sopenharmony_ci	time_t t;
1368c2ecf20Sopenharmony_ci	int ret;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	time(&t);
1398c2ecf20Sopenharmony_ci	localtime_r(&t, &tm);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	base = getenv("JITDUMPDIR");
1428c2ecf20Sopenharmony_ci	if (!base)
1438c2ecf20Sopenharmony_ci		base = getenv("HOME");
1448c2ecf20Sopenharmony_ci	if (!base)
1458c2ecf20Sopenharmony_ci		base = ".";
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	ret = snprintf(jit_path, PATH_MAX, "%s/.debug/", base);
1508c2ecf20Sopenharmony_ci	if (ret >= PATH_MAX) {
1518c2ecf20Sopenharmony_ci		warnx("jvmti: cannot generate jit cache dir because %s/.debug/"
1528c2ecf20Sopenharmony_ci			" is too long, please check the cwd, JITDUMPDIR, and"
1538c2ecf20Sopenharmony_ci			" HOME variables", base);
1548c2ecf20Sopenharmony_ci		return -1;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci	ret = mkdir(jit_path, 0755);
1578c2ecf20Sopenharmony_ci	if (ret == -1) {
1588c2ecf20Sopenharmony_ci		if (errno != EEXIST) {
1598c2ecf20Sopenharmony_ci			warn("jvmti: cannot create jit cache dir %s", jit_path);
1608c2ecf20Sopenharmony_ci			return -1;
1618c2ecf20Sopenharmony_ci		}
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	ret = snprintf(jit_path, PATH_MAX, "%s/.debug/jit", base);
1658c2ecf20Sopenharmony_ci	if (ret >= PATH_MAX) {
1668c2ecf20Sopenharmony_ci		warnx("jvmti: cannot generate jit cache dir because"
1678c2ecf20Sopenharmony_ci			" %s/.debug/jit is too long, please check the cwd,"
1688c2ecf20Sopenharmony_ci			" JITDUMPDIR, and HOME variables", base);
1698c2ecf20Sopenharmony_ci		return -1;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci	ret = mkdir(jit_path, 0755);
1728c2ecf20Sopenharmony_ci	if (ret == -1) {
1738c2ecf20Sopenharmony_ci		if (errno != EEXIST) {
1748c2ecf20Sopenharmony_ci			warn("jvmti: cannot create jit cache dir %s", jit_path);
1758c2ecf20Sopenharmony_ci			return -1;
1768c2ecf20Sopenharmony_ci		}
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	ret = snprintf(jit_path, PATH_MAX, "%s/.debug/jit/%s.XXXXXXXX", base, str);
1808c2ecf20Sopenharmony_ci	if (ret >= PATH_MAX) {
1818c2ecf20Sopenharmony_ci		warnx("jvmti: cannot generate jit cache dir because"
1828c2ecf20Sopenharmony_ci			" %s/.debug/jit/%s.XXXXXXXX is too long, please check"
1838c2ecf20Sopenharmony_ci			" the cwd, JITDUMPDIR, and HOME variables",
1848c2ecf20Sopenharmony_ci			base, str);
1858c2ecf20Sopenharmony_ci		return -1;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci	p = mkdtemp(jit_path);
1888c2ecf20Sopenharmony_ci	if (p != jit_path) {
1898c2ecf20Sopenharmony_ci		warn("jvmti: cannot create jit cache dir %s", jit_path);
1908c2ecf20Sopenharmony_ci		return -1;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return 0;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic int
1978c2ecf20Sopenharmony_ciperf_open_marker_file(int fd)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	long pgsz;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	pgsz = sysconf(_SC_PAGESIZE);
2028c2ecf20Sopenharmony_ci	if (pgsz == -1)
2038c2ecf20Sopenharmony_ci		return -1;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/*
2068c2ecf20Sopenharmony_ci	 * we mmap the jitdump to create an MMAP RECORD in perf.data file.
2078c2ecf20Sopenharmony_ci	 * The mmap is captured either live (perf record running when we mmap)
2088c2ecf20Sopenharmony_ci	 * or  in deferred mode, via /proc/PID/maps
2098c2ecf20Sopenharmony_ci	 * the MMAP record is used as a marker of a jitdump file for more meta
2108c2ecf20Sopenharmony_ci	 * data info about the jitted code. Perf report/annotate detect this
2118c2ecf20Sopenharmony_ci	 * special filename and process the jitdump file.
2128c2ecf20Sopenharmony_ci	 *
2138c2ecf20Sopenharmony_ci	 * mapping must be PROT_EXEC to ensure it is captured by perf record
2148c2ecf20Sopenharmony_ci	 * even when not using -d option
2158c2ecf20Sopenharmony_ci	 */
2168c2ecf20Sopenharmony_ci	marker_addr = mmap(NULL, pgsz, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
2178c2ecf20Sopenharmony_ci	return (marker_addr == MAP_FAILED) ? -1 : 0;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic void
2218c2ecf20Sopenharmony_ciperf_close_marker_file(void)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	long pgsz;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (!marker_addr)
2268c2ecf20Sopenharmony_ci		return;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	pgsz = sysconf(_SC_PAGESIZE);
2298c2ecf20Sopenharmony_ci	if (pgsz == -1)
2308c2ecf20Sopenharmony_ci		return;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	munmap(marker_addr, pgsz);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic void
2368c2ecf20Sopenharmony_ciinit_arch_timestamp(void)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	char *str = getenv("JITDUMP_USE_ARCH_TIMESTAMP");
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if (!str || !*str || !strcmp(str, "0"))
2418c2ecf20Sopenharmony_ci		return;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	use_arch_timestamp = 1;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_civoid *jvmti_open(void)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	char dump_path[PATH_MAX];
2498c2ecf20Sopenharmony_ci	struct jitheader header;
2508c2ecf20Sopenharmony_ci	int fd, ret;
2518c2ecf20Sopenharmony_ci	FILE *fp;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	init_arch_timestamp();
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	/*
2568c2ecf20Sopenharmony_ci	 * check if clockid is supported
2578c2ecf20Sopenharmony_ci	 */
2588c2ecf20Sopenharmony_ci	if (!perf_get_timestamp()) {
2598c2ecf20Sopenharmony_ci		if (use_arch_timestamp)
2608c2ecf20Sopenharmony_ci			warnx("jvmti: arch timestamp not supported");
2618c2ecf20Sopenharmony_ci		else
2628c2ecf20Sopenharmony_ci			warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	memset(&header, 0, sizeof(header));
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/*
2688c2ecf20Sopenharmony_ci	 * jitdump file dir
2698c2ecf20Sopenharmony_ci	 */
2708c2ecf20Sopenharmony_ci	if (create_jit_cache_dir() < 0)
2718c2ecf20Sopenharmony_ci		return NULL;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/*
2748c2ecf20Sopenharmony_ci	 * jitdump file name
2758c2ecf20Sopenharmony_ci	 */
2768c2ecf20Sopenharmony_ci	ret = snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid());
2778c2ecf20Sopenharmony_ci	if (ret >= PATH_MAX) {
2788c2ecf20Sopenharmony_ci		warnx("jvmti: cannot generate jitdump file full path because"
2798c2ecf20Sopenharmony_ci			" %s/jit-%i.dump is too long, please check the cwd,"
2808c2ecf20Sopenharmony_ci			" JITDUMPDIR, and HOME variables", jit_path, getpid());
2818c2ecf20Sopenharmony_ci		return NULL;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
2858c2ecf20Sopenharmony_ci	if (fd == -1)
2868c2ecf20Sopenharmony_ci		return NULL;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	/*
2898c2ecf20Sopenharmony_ci	 * create perf.data maker for the jitdump file
2908c2ecf20Sopenharmony_ci	 */
2918c2ecf20Sopenharmony_ci	if (perf_open_marker_file(fd)) {
2928c2ecf20Sopenharmony_ci		warnx("jvmti: failed to create marker file");
2938c2ecf20Sopenharmony_ci		return NULL;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	fp = fdopen(fd, "w+");
2978c2ecf20Sopenharmony_ci	if (!fp) {
2988c2ecf20Sopenharmony_ci		warn("jvmti: cannot create %s", dump_path);
2998c2ecf20Sopenharmony_ci		close(fd);
3008c2ecf20Sopenharmony_ci		goto error;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	warnx("jvmti: jitdump in %s", dump_path);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (get_e_machine(&header)) {
3068c2ecf20Sopenharmony_ci		warn("get_e_machine failed\n");
3078c2ecf20Sopenharmony_ci		goto error;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	header.magic      = JITHEADER_MAGIC;
3118c2ecf20Sopenharmony_ci	header.version    = JITHEADER_VERSION;
3128c2ecf20Sopenharmony_ci	header.total_size = sizeof(header);
3138c2ecf20Sopenharmony_ci	header.pid        = getpid();
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	header.timestamp = perf_get_timestamp();
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (use_arch_timestamp)
3188c2ecf20Sopenharmony_ci		header.flags |= JITDUMP_FLAGS_ARCH_TIMESTAMP;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (!fwrite(&header, sizeof(header), 1, fp)) {
3218c2ecf20Sopenharmony_ci		warn("jvmti: cannot write dumpfile header");
3228c2ecf20Sopenharmony_ci		goto error;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci	return fp;
3258c2ecf20Sopenharmony_cierror:
3268c2ecf20Sopenharmony_ci	fclose(fp);
3278c2ecf20Sopenharmony_ci	return NULL;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ciint
3318c2ecf20Sopenharmony_cijvmti_close(void *agent)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct jr_code_close rec;
3348c2ecf20Sopenharmony_ci	FILE *fp = agent;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (!fp) {
3378c2ecf20Sopenharmony_ci		warnx("jvmti: invalid fd in close_agent");
3388c2ecf20Sopenharmony_ci		return -1;
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	rec.p.id = JIT_CODE_CLOSE;
3428c2ecf20Sopenharmony_ci	rec.p.total_size = sizeof(rec);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	rec.p.timestamp = perf_get_timestamp();
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (!fwrite(&rec, sizeof(rec), 1, fp))
3478c2ecf20Sopenharmony_ci		return -1;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	fclose(fp);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	fp = NULL;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	perf_close_marker_file();
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return 0;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ciint
3598c2ecf20Sopenharmony_cijvmti_write_code(void *agent, char const *sym,
3608c2ecf20Sopenharmony_ci	uint64_t vma, void const *code, unsigned int const size)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	static int code_generation = 1;
3638c2ecf20Sopenharmony_ci	struct jr_code_load rec;
3648c2ecf20Sopenharmony_ci	size_t sym_len;
3658c2ecf20Sopenharmony_ci	FILE *fp = agent;
3668c2ecf20Sopenharmony_ci	int ret = -1;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	/* don't care about 0 length function, no samples */
3698c2ecf20Sopenharmony_ci	if (size == 0)
3708c2ecf20Sopenharmony_ci		return 0;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (!fp) {
3738c2ecf20Sopenharmony_ci		warnx("jvmti: invalid fd in write_native_code");
3748c2ecf20Sopenharmony_ci		return -1;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	sym_len = strlen(sym) + 1;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	rec.p.id           = JIT_CODE_LOAD;
3808c2ecf20Sopenharmony_ci	rec.p.total_size   = sizeof(rec) + sym_len;
3818c2ecf20Sopenharmony_ci	rec.p.timestamp    = perf_get_timestamp();
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	rec.code_size  = size;
3848c2ecf20Sopenharmony_ci	rec.vma        = vma;
3858c2ecf20Sopenharmony_ci	rec.code_addr  = vma;
3868c2ecf20Sopenharmony_ci	rec.pid	       = getpid();
3878c2ecf20Sopenharmony_ci	rec.tid	       = gettid();
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (code)
3908c2ecf20Sopenharmony_ci		rec.p.total_size += size;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	/*
3938c2ecf20Sopenharmony_ci	 * If JVM is multi-threaded, nultiple concurrent calls to agent
3948c2ecf20Sopenharmony_ci	 * may be possible, so protect file writes
3958c2ecf20Sopenharmony_ci	 */
3968c2ecf20Sopenharmony_ci	flockfile(fp);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/*
3998c2ecf20Sopenharmony_ci	 * get code index inside lock to avoid race condition
4008c2ecf20Sopenharmony_ci	 */
4018c2ecf20Sopenharmony_ci	rec.code_index = code_generation++;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	ret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
4048c2ecf20Sopenharmony_ci	fwrite_unlocked(sym, sym_len, 1, fp);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (code)
4078c2ecf20Sopenharmony_ci		fwrite_unlocked(code, size, 1, fp);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	funlockfile(fp);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	ret = 0;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	return ret;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ciint
4178c2ecf20Sopenharmony_cijvmti_write_debug_info(void *agent, uint64_t code,
4188c2ecf20Sopenharmony_ci    int nr_lines, jvmti_line_info_t *li,
4198c2ecf20Sopenharmony_ci    const char * const * file_names)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	struct jr_code_debug_info rec;
4228c2ecf20Sopenharmony_ci	size_t sret, len, size, flen = 0;
4238c2ecf20Sopenharmony_ci	uint64_t addr;
4248c2ecf20Sopenharmony_ci	FILE *fp = agent;
4258c2ecf20Sopenharmony_ci	int i;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	/*
4288c2ecf20Sopenharmony_ci	 * no entry to write
4298c2ecf20Sopenharmony_ci	 */
4308c2ecf20Sopenharmony_ci	if (!nr_lines)
4318c2ecf20Sopenharmony_ci		return 0;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	if (!fp) {
4348c2ecf20Sopenharmony_ci		warnx("jvmti: invalid fd in write_debug_info");
4358c2ecf20Sopenharmony_ci		return -1;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	for (i = 0; i < nr_lines; ++i) {
4398c2ecf20Sopenharmony_ci	    flen += strlen(file_names[i]) + 1;
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	rec.p.id        = JIT_CODE_DEBUG_INFO;
4438c2ecf20Sopenharmony_ci	size            = sizeof(rec);
4448c2ecf20Sopenharmony_ci	rec.p.timestamp = perf_get_timestamp();
4458c2ecf20Sopenharmony_ci	rec.code_addr   = (uint64_t)(uintptr_t)code;
4468c2ecf20Sopenharmony_ci	rec.nr_entry    = nr_lines;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/*
4498c2ecf20Sopenharmony_ci	 * on disk source line info layout:
4508c2ecf20Sopenharmony_ci	 * uint64_t : addr
4518c2ecf20Sopenharmony_ci	 * int      : line number
4528c2ecf20Sopenharmony_ci	 * int      : column discriminator
4538c2ecf20Sopenharmony_ci	 * file[]   : source file name
4548c2ecf20Sopenharmony_ci	 */
4558c2ecf20Sopenharmony_ci	size += nr_lines * sizeof(struct debug_entry);
4568c2ecf20Sopenharmony_ci	size += flen;
4578c2ecf20Sopenharmony_ci	rec.p.total_size = size;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	/*
4608c2ecf20Sopenharmony_ci	 * If JVM is multi-threaded, nultiple concurrent calls to agent
4618c2ecf20Sopenharmony_ci	 * may be possible, so protect file writes
4628c2ecf20Sopenharmony_ci	 */
4638c2ecf20Sopenharmony_ci	flockfile(fp);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	sret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
4668c2ecf20Sopenharmony_ci	if (sret != 1)
4678c2ecf20Sopenharmony_ci		goto error;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	for (i = 0; i < nr_lines; i++) {
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		addr = (uint64_t)li[i].pc;
4728c2ecf20Sopenharmony_ci		len  = sizeof(addr);
4738c2ecf20Sopenharmony_ci		sret = fwrite_unlocked(&addr, len, 1, fp);
4748c2ecf20Sopenharmony_ci		if (sret != 1)
4758c2ecf20Sopenharmony_ci			goto error;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci		len  = sizeof(li[0].line_number);
4788c2ecf20Sopenharmony_ci		sret = fwrite_unlocked(&li[i].line_number, len, 1, fp);
4798c2ecf20Sopenharmony_ci		if (sret != 1)
4808c2ecf20Sopenharmony_ci			goto error;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci		len  = sizeof(li[0].discrim);
4838c2ecf20Sopenharmony_ci		sret = fwrite_unlocked(&li[i].discrim, len, 1, fp);
4848c2ecf20Sopenharmony_ci		if (sret != 1)
4858c2ecf20Sopenharmony_ci			goto error;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci		sret = fwrite_unlocked(file_names[i], strlen(file_names[i]) + 1, 1, fp);
4888c2ecf20Sopenharmony_ci		if (sret != 1)
4898c2ecf20Sopenharmony_ci			goto error;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci	funlockfile(fp);
4928c2ecf20Sopenharmony_ci	return 0;
4938c2ecf20Sopenharmony_cierror:
4948c2ecf20Sopenharmony_ci	funlockfile(fp);
4958c2ecf20Sopenharmony_ci	return -1;
4968c2ecf20Sopenharmony_ci}
497