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