xref: /openbmc/linux/tools/perf/jvmti/jvmti_agent.c (revision 293d5b43)
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