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