lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 16 Feb 2015 15:22:18 -0500
From:	Stephane Eranian <eranian@...gle.com>
To:	Adrian Hunter <adrian.hunter@...el.com>
Cc:	LKML <linux-kernel@...r.kernel.org>,
	Arnaldo Carvalho de Melo <acme@...hat.com>,
	Peter Zijlstra <peterz@...radead.org>,
	"mingo@...e.hu" <mingo@...e.hu>,
	"ak@...ux.intel.com" <ak@...ux.intel.com>,
	Jiri Olsa <jolsa@...hat.com>,
	Namhyung Kim <namhyung@...nel.org>,
	Rose Belcher <cel@...ibm.com>,
	Sukadev Bhattiprolu <sukadev@...ux.vnet.ibm.com>,
	Sonny Rao <sonnyrao@...omium.org>,
	John Mccutchan <johnmccutchan@...gle.com>
Subject: Re: [PATCH 4/4] perf tools: add JVMTI agent library

On Mon, Feb 16, 2015 at 2:01 AM, Adrian Hunter <adrian.hunter@...el.com> wrote:
> On 11/02/15 01:42, Stephane Eranian wrote:
>> This is a standalone JVMTI library to help  profile Java jitted
>> code with perf record/perf report. The library is not installed
>> or compiled automatically by perf Makefile. It is not used
>> directly by perf. It is arch agnostic and has been tested on
>> X86 and ARM. It needs to be used with a Java runtime, such
>> as OpenJDK, as follows:
>>
>> $ java -agentpath:libjvmti.so .......
>>
>> When used this way, java will generate a jitdump binary file in
>> $HOME/.debug/java/jit/java-jit-*
>>
>> This binary dump file contains information to help symbolize and
>> annotate jitted code.
>>
>> The next step is to inject the jitdump information into the
>> perf.data file:
>> $ perf inject -j $HOME/.debug/java/jit/java-jit-XXXX/jit-ZZZ.dump \
>>               -i perf.data -o perf.data.jitted
>>
>> This injects the MMAP records to cover the jitted code and also generates
>> one ELF image for each jitted function. The ELF images are created in the
>> same subdir as the jitdump file. The MMAP records point there too.
>>
>> Then to visualize the function or asm profile, simply use the regular
>> perf commands:
>> $ perf report -i perf.data.jitted
>> or
>> $ perf annotate -i perf.data.jitted
>>
>> JVMTI agent code adapted from OProfile's opagent code.
>>
>> Signed-off-by: Stephane Eranian <eranian@...gle.com>
>> ---
>>  tools/perf/jvmti/Makefile      |  70 +++++++++
>>  tools/perf/jvmti/jvmti_agent.c | 349 +++++++++++++++++++++++++++++++++++++++++
>>  tools/perf/jvmti/jvmti_agent.h |  23 +++
>>  tools/perf/jvmti/libjvmti.c    | 149 ++++++++++++++++++
>>  4 files changed, 591 insertions(+)
>>  create mode 100644 tools/perf/jvmti/Makefile
>>  create mode 100644 tools/perf/jvmti/jvmti_agent.c
>>  create mode 100644 tools/perf/jvmti/jvmti_agent.h
>>  create mode 100644 tools/perf/jvmti/libjvmti.c
>>
>> diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile
>> new file mode 100644
>> index 0000000..9eda64b
>> --- /dev/null
>> +++ b/tools/perf/jvmti/Makefile
>> @@ -0,0 +1,70 @@
>> +ARCH=$(shell uname -m)
>> +
>> +ifeq ($(ARCH), x86_64)
>> +JARCH=amd64
>> +endif
>> +ifeq ($(ARCH), armv7l)
>> +JARCH=armhf
>> +endif
>> +ifeq ($(ARCH), armv6l)
>> +JARCH=armhf
>> +endif
>> +ifeq ($(ARCH), ppc64)
>> +JARCH=powerpc
>> +endif
>> +ifeq ($(ARCH), ppc64le)
>> +JARCH=powerpc
>> +endif
>> +
>> +DESTDIR=/usr/local
>> +
>> +VERSION=1
>> +REVISION=0
>> +AGE=0
>> +
>> +LN=ln -sf
>> +RM=rm
>> +
>> +SJVMTI=libjvmti.so.$(VERSION).$(REVISION).$(AGE)
>> +VJVMTI=libjvmti.so.$(VERSION)
>> +SLDFLAGS=-shared -Wl,-soname -Wl,$(VLIBPFM)
>> +SOLIBEXT=so
>> +
>> +JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
>> +# -lrt required in 32-bit mode for clock_gettime()
>> +LIBS=-lelf -lrt
>> +INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux
>> +
>> +TARGETS=$(SJVMTI)
>> +
>> +SRCS=libjvmti.c jvmti_agent.c
>> +OBJS=$(SRCS:.c=.o)
>> +SOBJS=$(OBJS:.o=.lo)
>> +OPT=-O2 -g -Werror -Wall
>> +
>> +CFLAGS=$(INCDIR) $(OPT)
>> +
>> +all: $(TARGETS)
>> +
>> +.c.o:
>> +     $(CC) $(CFLAGS) -c $*.c
>> +.c.lo:
>> +     $(CC) -fPIC -DPIC $(CFLAGS) -c $*.c -o $*.lo
>> +
>> +$(OBJS) $(SOBJS): Makefile jvmti_agent.h ../util/jitdump.h
>> +
>> +$(SJVMTI):  $(SOBJS)
>> +     $(CC) $(CFLAGS) $(SLDFLAGS)  -o $@ $(SOBJS) $(LIBS)
>> +     $(LN) $@ libjvmti.$(SOLIBEXT)
>> +
>> +clean:
>> +     $(RM) -f *.o *.so.* *.so *.lo
>> +
>> +install:
>> +     -mkdir -p $(DESTDIR)/lib
>> +     install -m 755 $(SJVMTI) $(DESTDIR)/lib/
>> +     (cd $(DESTDIR)/lib; $(LN) $(SJVMTI) $(VJVMTI))
>> +     (cd $(DESTDIR)/lib; $(LN) $(SJVMTI) libjvmti.$(SOLIBEXT))
>> +     ldconfig
>> +
>> +.SUFFIXES: .c .S .o .lo
>> diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c
>> new file mode 100644
>> index 0000000..d2d5215
>> --- /dev/null
>> +++ b/tools/perf/jvmti/jvmti_agent.c
>> @@ -0,0 +1,349 @@
>> +/*
>> + * jvmti_agent.c: JVMTI agent interface
>> + *
>> + * Adapted from the Oprofile code in opagent.c:
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.1 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
>> + *
>> + * Copyright 2007 OProfile authors
>> + * Jens Wilke
>> + * Daniel Hansel
>> + * Copyright IBM Corporation 2007
>> + */
>> +#include <sys/types.h>
>> +#include <sys/stat.h> /* for mkdir() */
>> +#include <stdio.h>
>> +#include <errno.h>
>> +#include <string.h>
>> +#include <stdlib.h>
>> +#include <stdint.h>
>> +#include <limits.h>
>> +#include <fcntl.h>
>> +#include <unistd.h>
>> +#include <time.h>
>> +#include <syscall.h> /* for gettid() */
>> +#include <err.h>
>> +
>> +#include "jvmti_agent.h"
>> +#include "../util/jitdump.h"
>> +
>> +#define JIT_LANG "java"
>> +
>> +static char jit_path[PATH_MAX];
>> +
>> +/*
>> + * padding buffer
>> + */
>> +static const char pad_bytes[7];
>> +
>> +/*
>> + * perf_events event fd
>> + */
>> +static int perf_fd;
>> +
>> +static inline pid_t gettid(void)
>> +{
>> +     return (pid_t)syscall(__NR_gettid);
>> +}
>> +
>> +static int get_e_machine(struct jitheader *hdr)
>> +{
>> +     ssize_t sret;
>> +     char id[16];
>> +     int fd, ret = -1;
>> +     int m = -1;
>> +     struct {
>> +             uint16_t e_type;
>> +             uint16_t e_machine;
>> +     } info;
>> +
>> +     fd = open("/proc/self/exe", O_RDONLY);
>> +     if (fd == -1)
>> +             return -1;
>> +
>> +     sret = read(fd, id, sizeof(id));
>> +     if (sret != sizeof(id))
>> +             goto error;
>> +
>> +     /* check ELF signature */
>> +     if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F')
>> +             goto error;
>> +
>> +     sret = read(fd, &info, sizeof(info));
>> +     if (sret != sizeof(info))
>> +             goto error;
>> +
>> +     m = info.e_machine;
>> +     if (m < 0)
>> +             m = 0; /* ELF EM_NONE */
>> +
>> +     hdr->elf_mach = m;
>> +     ret = 0;
>> +error:
>> +     close(fd);
>> +     return ret;
>> +}
>> +
>> +#define CLOCK_DEVICE "/dev/trace_clock"
>> +#define CLOCKFD 3
>> +#define FD_TO_CLOCKID(fd)    ((~(clockid_t) (fd) << 3) | CLOCKFD)
>> +#define CLOCKID_TO_FD(id)    ((~(int) (id) >> 3) & ~CLOCKFD)
>> +
>> +#define NSEC_PER_SEC 1000000000
>> +
>> +#ifndef CLOCK_INVALID
>> +#define CLOCK_INVALID -1
>> +#endif
>> +
>> +static inline clockid_t get_clockid(int fd)
>> +{
>> +     return FD_TO_CLOCKID(fd);
>> +}
>> +
>> +static int
>> +perf_open_timestamp(void)
>> +{
>> +     int fd, id;
>> +
>> +     fd = open(CLOCK_DEVICE, O_RDONLY);
>> +     if (fd == -1) {
>> +             if (errno == ENOENT)
>> +                     warnx("jvmti: %s not present, check your kernel for trace_clock module", CLOCK_DEVICE);
>> +             if (errno == EPERM)
>> +                     warnx("jvmti: %s has wrong permissions, suggesting chmod 644 %s", CLOCK_DEVICE, CLOCK_DEVICE);
>> +     }
>> +
>> +     id = get_clockid(fd);
>> +     if (CLOCK_INVALID == id)
>> +             return CLOCK_INVALID;
>> +
>> +     return get_clockid(fd);
>> +}
>> +
>> +static inline void
>> +perf_close_timestamp(int id)
>> +{
>> +        close(CLOCKID_TO_FD(id));
>> +}
>> +
>> +
>> +static inline uint64_t
>> +timespec_to_ns(const struct timespec *ts)
>> +{
>> +        return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
>> +}
>> +
>> +static inline uint64_t
>> +perf_get_timestamp(int id)
>> +{
>> +     struct timespec ts;
>> +
>> +     clock_gettime(id, &ts);
>> +     return timespec_to_ns(&ts);
>> +}
>> +
>> +static int
>> +debug_cache_init(void)
>> +{
>> +     char str[32];
>> +     char *base, *p;
>> +     struct tm tm;
>> +     time_t t;
>> +     int ret;
>> +
>> +     time(&t);
>> +     localtime_r(&t, &tm);
>> +
>> +     base = getenv("JITDUMPDIR");
>> +     if (!base)
>> +             base = getenv("HOME");
>> +     if (!base)
>> +             base = ".";
>> +
>> +     strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm);
>> +
>> +     snprintf(jit_path, PATH_MAX - 1, "%s/.debug/", base);
>> +
>> +     ret = mkdir(jit_path, 0755);
>> +     if (ret == -1) {
>> +             if (errno != EEXIST) {
>> +                     warn("jvmti: cannot create jit cache dir %s", jit_path);
>> +                     return -1;
>> +             }
>> +     }
>> +
>> +     snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit", base);
>> +     ret = mkdir(jit_path, 0755);
>> +     if (ret == -1) {
>> +             if (errno != EEXIST) {
>> +                     warn("cannot create jit cache dir %s", jit_path);
>> +                     return -1;
>> +             }
>> +     }
>> +
>> +     snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit/%s.XXXXXXXX", base, str);
>> +
>> +     p = mkdtemp(jit_path);
>> +     if (p != jit_path) {
>> +             warn("cannot create jit cache dir %s", jit_path);
>> +             return -1;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +void *jvmti_open(void)
>> +{
>> +     int pad_cnt;
>> +     char dump_path[PATH_MAX];
>> +     struct jitheader header;
>> +     FILE *fp;
>> +
>> +     perf_fd = perf_open_timestamp();
>> +     if (perf_fd == -1)
>> +             warnx("jvmti: kernel does not support /dev/trace_clock or permissions are wrong on that device");
>> +
>> +     memset(&header, 0, sizeof(header));
>> +
>> +     debug_cache_init();
>> +
>> +     snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid());
>> +
>> +     fp = fopen(dump_path, "w");
>> +     if (!fp) {
>> +             warn("jvmti: cannot create %s", dump_path);
>> +             goto error;
>> +     }
>> +
>> +     warnx("jvmti: jitdump in %s", dump_path);
>> +
>> +     if (get_e_machine(&header)) {
>> +             warn("get_e_machine failed\n");
>> +             goto error;
>> +     }
>> +
>> +     header.magic      = JITHEADER_MAGIC;
>> +     header.version    = JITHEADER_VERSION;
>> +     header.total_size = sizeof(header);
>> +     header.pid        = getpid();
>> +
>> +     /* calculate amount of padding '\0' */
>> +     pad_cnt = PADDING_8ALIGNED(header.total_size);
>> +     header.total_size += pad_cnt;
>> +
>> +     header.timestamp = perf_get_timestamp(perf_fd);
>> +
>> +     if (!fwrite(&header, sizeof(header), 1, fp)) {
>> +             warn("jvmti: cannot write dumpfile header");
>> +             goto error;
>> +     }
>> +
>> +     /* write padding '\0' if necessary */
>> +     if (pad_cnt && !fwrite(pad_bytes, pad_cnt, 1, fp)) {
>> +             warn("jvmti: cannot write dumpfile header padding");
>> +             goto error;
>> +     }
>> +
>> +     return fp;
>> +error:
>> +     fclose(fp);
>> +     perf_close_timestamp(perf_fd);
>> +     return NULL;
>> +}
>> +
>> +int
>> +jvmti_close(void *agent)
>> +{
>> +     struct jr_code_close rec;
>> +     FILE *fp = agent;
>> +
>> +     if (!fp) {
>> +             warnx("jvmti: incalid fd in close_agent");
>> +             return -1;
>> +     }
>> +
>> +     rec.p.id = JIT_CODE_CLOSE;
>> +     rec.p.total_size = sizeof(rec);
>> +
>> +     rec.p.timestamp = perf_get_timestamp(perf_fd);
>> +
>> +     if (!fwrite(&rec, sizeof(rec), 1, fp))
>> +             return -1;
>> +
>> +     fclose(fp);
>> +
>> +     perf_close_timestamp(perf_fd);
>> +
>> +     fp = NULL;
>> +
>> +     return 0;
>> +}
>> +
>> +int jvmti_write_code(void *agent, char const *sym,
>> +     uint64_t vma, void const *code, unsigned int const size)
>> +{
>> +     static int code_generation = 1;
>> +     struct jr_code_load rec;
>> +     size_t sym_len;
>> +     size_t padding_count;
>> +     FILE *fp = agent;
>> +     int ret = -1;
>> +
>> +     /* don't care about 0 length function, no samples */
>> +     if (size == 0)
>> +             return 0;
>> +
>> +     if (!fp) {
>> +             warnx("jvmti: invalid fd in write_native_code");
>> +             return -1;
>> +     }
>> +
>> +     sym_len = strlen(sym) + 1;
>> +
>> +     rec.p.id           = JIT_CODE_LOAD;
>> +     rec.p.total_size   = sizeof(rec) + sym_len;
>> +     padding_count      = PADDING_8ALIGNED(rec.p.total_size);
>> +     rec.p. total_size += padding_count;
>> +     rec.p.timestamp    = perf_get_timestamp(perf_fd);
>
> Do you know whether the JVM is guaranteed not to start executing the
> generated code before the return of compiled_method_load_cb(), otherwise the
> timestamp will be too late?
>
I don't know that. I did not check.
But are you saying the callback may be asynchronous with the JIT compiler?
The callback need to happen only after the code is jitted for obvious reasons.

>> +
>> +     rec.code_size  = size;
>> +     rec.vma        = vma;
>> +     rec.code_addr  = vma;
>> +     rec.pid        = getpid();
>> +     rec.tid        = gettid();
>> +     rec.code_index = code_generation++;
>> +
>> +     if (code)
>> +             rec.p.total_size += size;
>> +
>> +     /*
>> +      * If JVM is multi-threaded, nultiple concurrent calls to agent
>> +      * may be possible, so protect file writes
>> +      */
>> +     flockfile(fp);
>> +
>> +     ret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
>> +     fwrite_unlocked(sym, sym_len, 1, fp);
>> +     if (code)
>> +             fwrite_unlocked(code, size, 1, fp);
>> +
>> +     if (padding_count)
>> +             fwrite_unlocked(pad_bytes, padding_count, 1, fp);
>> +
>> +     funlockfile(fp);
>> +
>> +     ret = 0;
>> +
>> +     return ret;
>> +}
>> diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h
>> new file mode 100644
>> index 0000000..54e5c5e
>> --- /dev/null
>> +++ b/tools/perf/jvmti/jvmti_agent.h
>> @@ -0,0 +1,23 @@
>> +#ifndef __JVMTI_AGENT_H__
>> +#define __JVMTI_AGENT_H__
>> +
>> +#include <sys/types.h>
>> +#include <stdint.h>
>> +
>> +#define __unused __attribute__((unused))
>> +
>> +#if defined(__cplusplus)
>> +extern "C" {
>> +#endif
>> +
>> +void *jvmti_open(void);
>> +int   jvmti_close(void *agent);
>> +int   jvmti_write_code(void *agent, char const *symbol_name,
>> +                    uint64_t vma, void const *code,
>> +                    const unsigned int code_size);
>> +
>> +#if defined(__cplusplus)
>> +}
>> +
>> +#endif
>> +#endif /* __JVMTI_H__ */
>> diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
>> new file mode 100644
>> index 0000000..8b8d782
>> --- /dev/null
>> +++ b/tools/perf/jvmti/libjvmti.c
>> @@ -0,0 +1,149 @@
>> +#include <sys/types.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <stdlib.h>
>> +#include <err.h>
>> +#include <jvmti.h>
>> +
>> +#include "jvmti_agent.h"
>> +
>> +void *jvmti_agent;
>> +
>> +static void JNICALL
>> +compiled_method_load_cb(jvmtiEnv *jvmti,
>> +                     jmethodID method,
>> +                     jint code_size,
>> +                     void const *code_addr,
>> +                     jint map_length,
>> +                     jvmtiAddrLocationMap const *map,
>> +                     void const *compile_info __unused)
>> +{
>> +     jclass decl_class;
>> +     char *class_sign = NULL;
>> +     char *func_name = NULL;
>> +     char *func_sign = NULL;
>> +     jvmtiError ret;
>> +     size_t len;
>> +
>> +     ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
>> +                                             &decl_class);
>> +     if (ret != JVMTI_ERROR_NONE) {
>> +             warnx("jvmti: getmethoddeclaringclass failed");
>> +             return;
>> +     }
>> +
>> +     ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
>> +                                       &class_sign, NULL);
>> +     if (ret != JVMTI_ERROR_NONE) {
>> +             warnx("jvmti: getclassignature failed");
>> +             goto error;
>> +     }
>> +
>> +     ret = (*jvmti)->GetMethodName(jvmti, method, &func_name,
>> +                                   &func_sign, NULL);
>> +     if (ret != JVMTI_ERROR_NONE) {
>> +             warnx("jvmti: failed getmethodname");
>> +             goto error;
>> +     }
>> +
>> +     len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;
>> +
>> +     {
>> +             char str[len];
>> +             uint64_t addr = (uint64_t)(unsigned long)code_addr;
>> +             snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign);
>> +             ret = jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size);
>> +             if (ret)
>> +                     warnx("jvmti: write_code() failed");
>> +     }
>> +error:
>> +     (*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
>> +     (*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
>> +     (*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
>> +}
>> +
>> +static void JNICALL
>> +code_generated_cb(jvmtiEnv *jvmti,
>> +               char const *name,
>> +               void const *code_addr,
>> +               jint code_size)
>> +{
>> +     uint64_t addr = (uint64_t)(unsigned long)code_addr;
>> +     int ret;
>> +
>> +     ret = jvmti_write_code(jvmti_agent, name, addr, code_addr, code_size);
>> +     if (ret)
>> +             warnx("jvmti: write_code() failed for code_generated");
>> +}
>> +
>> +JNIEXPORT jint JNICALL
>> +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused)
>> +{
>> +     jvmtiEventCallbacks cb;
>> +     jvmtiCapabilities caps1;
>> +     jvmtiEnv *jvmti = NULL;
>> +     jint ret;
>> +
>> +     jvmti_agent = jvmti_open();
>> +     if (!jvmti_agent) {
>> +             warnx("jvmti: open_agent failed");
>> +             return -1;
>> +     }
>> +
>> +     /*
>> +      * Request a JVMTI interface version 1 environment
>> +      */
>> +     ret = (*jvm)->GetEnv(jvm, (void *)&jvmti, JVMTI_VERSION_1);
>> +     if (ret != JNI_OK) {
>> +             warnx("jvmti: jvmti version 1 not supported");
>> +             return -1;
>> +     }
>> +
>> +     /*
>> +      * acquire method_load capability, we require it
>> +      */
>> +     memset(&caps1, 0, sizeof(caps1));
>> +     caps1.can_generate_compiled_method_load_events = 1;
>> +
>> +     ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
>> +     if (ret != JVMTI_ERROR_NONE) {
>> +             warnx("jvmti: acquire compiled_method capability failed");
>> +             return -1;
>> +     }
>> +
>> +     memset(&cb, 0, sizeof(cb));
>> +
>> +     cb.CompiledMethodLoad   = compiled_method_load_cb;
>> +     cb.DynamicCodeGenerated = code_generated_cb;
>> +
>> +     ret = (*jvmti)->SetEventCallbacks(jvmti, &cb, sizeof(cb));
>> +     if (ret != JVMTI_ERROR_NONE) {
>> +             warnx("jvmti: cannot set event callbacks");
>> +             return -1;
>> +     }
>> +
>> +     ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
>> +                     JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
>> +     if (ret != JVMTI_ERROR_NONE) {
>> +             warnx("jvmti: setnotification failed for method_load");
>> +             return -1;
>> +     }
>> +
>> +     ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
>> +                     JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
>> +     if (ret != JVMTI_ERROR_NONE) {
>> +             warnx("jvmti: setnotification failed on code_generated");
>> +             return -1;
>> +     }
>> +     return 0;
>> +}
>> +
>> +JNIEXPORT void JNICALL
>> +Agent_OnUnload(JavaVM *jvm __unused)
>> +{
>> +     int ret;
>> +
>> +     ret = jvmti_close(jvmti_agent);
>> +     if (ret)
>> +             errx(1, "Error: op_close_agent()");
>> +}
>>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ