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