1 /* 2 * jvmti_agent.c: JVMTI agent interface 3 * 4 * Adapted from the Oprofile code in opagent.c: 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 * Copyright 2007 OProfile authors 20 * Jens Wilke 21 * Daniel Hansel 22 * Copyright IBM Corporation 2007 23 */ 24 #include <sys/types.h> 25 #include <sys/stat.h> /* for mkdir() */ 26 #include <stdio.h> 27 #include <errno.h> 28 #include <string.h> 29 #include <stdlib.h> 30 #include <stdint.h> 31 #include <limits.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <time.h> 35 #include <sys/mman.h> 36 #include <syscall.h> /* for gettid() */ 37 #include <err.h> 38 39 #include "jvmti_agent.h" 40 #include "../util/jitdump.h" 41 42 #define JIT_LANG "java" 43 44 static char jit_path[PATH_MAX]; 45 static void *marker_addr; 46 47 /* 48 * padding buffer 49 */ 50 static const char pad_bytes[7]; 51 52 static inline pid_t gettid(void) 53 { 54 return (pid_t)syscall(__NR_gettid); 55 } 56 57 static int get_e_machine(struct jitheader *hdr) 58 { 59 ssize_t sret; 60 char id[16]; 61 int fd, ret = -1; 62 int m = -1; 63 struct { 64 uint16_t e_type; 65 uint16_t e_machine; 66 } info; 67 68 fd = open("/proc/self/exe", O_RDONLY); 69 if (fd == -1) 70 return -1; 71 72 sret = read(fd, id, sizeof(id)); 73 if (sret != sizeof(id)) 74 goto error; 75 76 /* check ELF signature */ 77 if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F') 78 goto error; 79 80 sret = read(fd, &info, sizeof(info)); 81 if (sret != sizeof(info)) 82 goto error; 83 84 m = info.e_machine; 85 if (m < 0) 86 m = 0; /* ELF EM_NONE */ 87 88 hdr->elf_mach = m; 89 ret = 0; 90 error: 91 close(fd); 92 return ret; 93 } 94 95 static int use_arch_timestamp; 96 97 static inline uint64_t 98 get_arch_timestamp(void) 99 { 100 #if defined(__i386__) || defined(__x86_64__) 101 unsigned int low, high; 102 103 asm volatile("rdtsc" : "=a" (low), "=d" (high)); 104 105 return low | ((uint64_t)high) << 32; 106 #else 107 return 0; 108 #endif 109 } 110 111 #define NSEC_PER_SEC 1000000000 112 static int perf_clk_id = CLOCK_MONOTONIC; 113 114 static inline uint64_t 115 timespec_to_ns(const struct timespec *ts) 116 { 117 return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec; 118 } 119 120 static inline uint64_t 121 perf_get_timestamp(void) 122 { 123 struct timespec ts; 124 int ret; 125 126 if (use_arch_timestamp) 127 return get_arch_timestamp(); 128 129 ret = clock_gettime(perf_clk_id, &ts); 130 if (ret) 131 return 0; 132 133 return timespec_to_ns(&ts); 134 } 135 136 static int 137 debug_cache_init(void) 138 { 139 char str[32]; 140 char *base, *p; 141 struct tm tm; 142 time_t t; 143 int ret; 144 145 time(&t); 146 localtime_r(&t, &tm); 147 148 base = getenv("JITDUMPDIR"); 149 if (!base) 150 base = getenv("HOME"); 151 if (!base) 152 base = "."; 153 154 strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm); 155 156 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/", base); 157 158 ret = mkdir(jit_path, 0755); 159 if (ret == -1) { 160 if (errno != EEXIST) { 161 warn("jvmti: cannot create jit cache dir %s", jit_path); 162 return -1; 163 } 164 } 165 166 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit", base); 167 ret = mkdir(jit_path, 0755); 168 if (ret == -1) { 169 if (errno != EEXIST) { 170 warn("cannot create jit cache dir %s", jit_path); 171 return -1; 172 } 173 } 174 175 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit/%s.XXXXXXXX", base, str); 176 177 p = mkdtemp(jit_path); 178 if (p != jit_path) { 179 warn("cannot create jit cache dir %s", jit_path); 180 return -1; 181 } 182 183 return 0; 184 } 185 186 static int 187 perf_open_marker_file(int fd) 188 { 189 long pgsz; 190 191 pgsz = sysconf(_SC_PAGESIZE); 192 if (pgsz == -1) 193 return -1; 194 195 /* 196 * we mmap the jitdump to create an MMAP RECORD in perf.data file. 197 * The mmap is captured either live (perf record running when we mmap) 198 * or in deferred mode, via /proc/PID/maps 199 * the MMAP record is used as a marker of a jitdump file for more meta 200 * data info about the jitted code. Perf report/annotate detect this 201 * special filename and process the jitdump file. 202 * 203 * mapping must be PROT_EXEC to ensure it is captured by perf record 204 * even when not using -d option 205 */ 206 marker_addr = mmap(NULL, pgsz, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0); 207 return (marker_addr == MAP_FAILED) ? -1 : 0; 208 } 209 210 static void 211 perf_close_marker_file(void) 212 { 213 long pgsz; 214 215 if (!marker_addr) 216 return; 217 218 pgsz = sysconf(_SC_PAGESIZE); 219 if (pgsz == -1) 220 return; 221 222 munmap(marker_addr, pgsz); 223 } 224 225 static void 226 init_arch_timestamp(void) 227 { 228 char *str = getenv("JITDUMP_USE_ARCH_TIMESTAMP"); 229 230 if (!str || !*str || !strcmp(str, "0")) 231 return; 232 233 use_arch_timestamp = 1; 234 } 235 236 void *jvmti_open(void) 237 { 238 int pad_cnt; 239 char dump_path[PATH_MAX]; 240 struct jitheader header; 241 int fd; 242 FILE *fp; 243 244 init_arch_timestamp(); 245 246 /* 247 * check if clockid is supported 248 */ 249 if (!perf_get_timestamp()) { 250 if (use_arch_timestamp) 251 warnx("jvmti: arch timestamp not supported"); 252 else 253 warnx("jvmti: kernel does not support %d clock id", perf_clk_id); 254 } 255 256 memset(&header, 0, sizeof(header)); 257 258 debug_cache_init(); 259 260 /* 261 * jitdump file name 262 */ 263 snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid()); 264 265 fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666); 266 if (fd == -1) 267 return NULL; 268 269 /* 270 * create perf.data maker for the jitdump file 271 */ 272 if (perf_open_marker_file(fd)) { 273 warnx("jvmti: failed to create marker file"); 274 return NULL; 275 } 276 277 fp = fdopen(fd, "w+"); 278 if (!fp) { 279 warn("jvmti: cannot create %s", dump_path); 280 close(fd); 281 goto error; 282 } 283 284 warnx("jvmti: jitdump in %s", dump_path); 285 286 if (get_e_machine(&header)) { 287 warn("get_e_machine failed\n"); 288 goto error; 289 } 290 291 header.magic = JITHEADER_MAGIC; 292 header.version = JITHEADER_VERSION; 293 header.total_size = sizeof(header); 294 header.pid = getpid(); 295 296 /* calculate amount of padding '\0' */ 297 pad_cnt = PADDING_8ALIGNED(header.total_size); 298 header.total_size += pad_cnt; 299 300 header.timestamp = perf_get_timestamp(); 301 302 if (use_arch_timestamp) 303 header.flags |= JITDUMP_FLAGS_ARCH_TIMESTAMP; 304 305 if (!fwrite(&header, sizeof(header), 1, fp)) { 306 warn("jvmti: cannot write dumpfile header"); 307 goto error; 308 } 309 310 /* write padding '\0' if necessary */ 311 if (pad_cnt && !fwrite(pad_bytes, pad_cnt, 1, fp)) { 312 warn("jvmti: cannot write dumpfile header padding"); 313 goto error; 314 } 315 316 return fp; 317 error: 318 fclose(fp); 319 return NULL; 320 } 321 322 int 323 jvmti_close(void *agent) 324 { 325 struct jr_code_close rec; 326 FILE *fp = agent; 327 328 if (!fp) { 329 warnx("jvmti: incalid fd in close_agent"); 330 return -1; 331 } 332 333 rec.p.id = JIT_CODE_CLOSE; 334 rec.p.total_size = sizeof(rec); 335 336 rec.p.timestamp = perf_get_timestamp(); 337 338 if (!fwrite(&rec, sizeof(rec), 1, fp)) 339 return -1; 340 341 fclose(fp); 342 343 fp = NULL; 344 345 perf_close_marker_file(); 346 347 return 0; 348 } 349 350 int 351 jvmti_write_code(void *agent, char const *sym, 352 uint64_t vma, void const *code, unsigned int const size) 353 { 354 static int code_generation = 1; 355 struct jr_code_load rec; 356 size_t sym_len; 357 size_t padding_count; 358 FILE *fp = agent; 359 int ret = -1; 360 361 /* don't care about 0 length function, no samples */ 362 if (size == 0) 363 return 0; 364 365 if (!fp) { 366 warnx("jvmti: invalid fd in write_native_code"); 367 return -1; 368 } 369 370 sym_len = strlen(sym) + 1; 371 372 rec.p.id = JIT_CODE_LOAD; 373 rec.p.total_size = sizeof(rec) + sym_len; 374 padding_count = PADDING_8ALIGNED(rec.p.total_size); 375 rec.p. total_size += padding_count; 376 rec.p.timestamp = perf_get_timestamp(); 377 378 rec.code_size = size; 379 rec.vma = vma; 380 rec.code_addr = vma; 381 rec.pid = getpid(); 382 rec.tid = gettid(); 383 384 if (code) 385 rec.p.total_size += size; 386 387 /* 388 * If JVM is multi-threaded, nultiple concurrent calls to agent 389 * may be possible, so protect file writes 390 */ 391 flockfile(fp); 392 393 /* 394 * get code index inside lock to avoid race condition 395 */ 396 rec.code_index = code_generation++; 397 398 ret = fwrite_unlocked(&rec, sizeof(rec), 1, fp); 399 fwrite_unlocked(sym, sym_len, 1, fp); 400 401 if (padding_count) 402 fwrite_unlocked(pad_bytes, padding_count, 1, fp); 403 404 if (code) 405 fwrite_unlocked(code, size, 1, fp); 406 407 funlockfile(fp); 408 409 ret = 0; 410 411 return ret; 412 } 413 414 int 415 jvmti_write_debug_info(void *agent, uint64_t code, const char *file, 416 jvmti_line_info_t *li, int nr_lines) 417 { 418 struct jr_code_debug_info rec; 419 size_t sret, len, size, flen; 420 size_t padding_count; 421 uint64_t addr; 422 const char *fn = file; 423 FILE *fp = agent; 424 int i; 425 426 /* 427 * no entry to write 428 */ 429 if (!nr_lines) 430 return 0; 431 432 if (!fp) { 433 warnx("jvmti: invalid fd in write_debug_info"); 434 return -1; 435 } 436 437 flen = strlen(file) + 1; 438 439 rec.p.id = JIT_CODE_DEBUG_INFO; 440 size = sizeof(rec); 441 rec.p.timestamp = perf_get_timestamp(); 442 rec.code_addr = (uint64_t)(uintptr_t)code; 443 rec.nr_entry = nr_lines; 444 445 /* 446 * on disk source line info layout: 447 * uint64_t : addr 448 * int : line number 449 * int : column discriminator 450 * file[] : source file name 451 * padding : pad to multiple of 8 bytes 452 */ 453 size += nr_lines * sizeof(struct debug_entry); 454 size += flen * nr_lines; 455 /* 456 * pad to 8 bytes 457 */ 458 padding_count = PADDING_8ALIGNED(size); 459 460 rec.p.total_size = size + padding_count; 461 462 /* 463 * If JVM is multi-threaded, nultiple concurrent calls to agent 464 * may be possible, so protect file writes 465 */ 466 flockfile(fp); 467 468 sret = fwrite_unlocked(&rec, sizeof(rec), 1, fp); 469 if (sret != 1) 470 goto error; 471 472 for (i = 0; i < nr_lines; i++) { 473 474 addr = (uint64_t)li[i].pc; 475 len = sizeof(addr); 476 sret = fwrite_unlocked(&addr, len, 1, fp); 477 if (sret != 1) 478 goto error; 479 480 len = sizeof(li[0].line_number); 481 sret = fwrite_unlocked(&li[i].line_number, len, 1, fp); 482 if (sret != 1) 483 goto error; 484 485 len = sizeof(li[0].discrim); 486 sret = fwrite_unlocked(&li[i].discrim, len, 1, fp); 487 if (sret != 1) 488 goto error; 489 490 sret = fwrite_unlocked(fn, flen, 1, fp); 491 if (sret != 1) 492 goto error; 493 } 494 if (padding_count) 495 sret = fwrite_unlocked(pad_bytes, padding_count, 1, fp); 496 if (sret != 1) 497 goto error; 498 499 funlockfile(fp); 500 return 0; 501 error: 502 funlockfile(fp); 503 return -1; 504 } 505