/* * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * Copyright 2003 Wily Technology, Inc. */ #ifndef _JPLISAGENT_H_ #define _JPLISAGENT_H_ #include #include #ifdef __cplusplus extern "C" { #endif /* * The JPLISAgent manages the initialization all of the Java programming language Agents. * It also supports the native method bridge between the JPLIS and the JVMTI. * It maintains a single JVMTI Env that all JPL agents share. * It parses command line requests and creates individual Java agents. */ /* * Forward definitions */ struct _JPLISAgent; typedef struct _JPLISAgent JPLISAgent; typedef struct _JPLISEnvironment JPLISEnvironment; /* constants for class names and methods names and such these all must stay in sync with Java code & interfaces */ #define JPLIS_INSTRUMENTIMPL_CLASSNAME "sun/instrument/InstrumentationImpl" #define JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODNAME "" #define JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODSIGNATURE "(JZZ)V" #define JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODNAME "loadClassAndCallPremain" #define JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODSIGNATURE "(Ljava/lang/String;Ljava/lang/String;)V" #define JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODNAME "loadClassAndCallAgentmain" #define JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODSIGNATURE "(Ljava/lang/String;Ljava/lang/String;)V" #define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODNAME "transform" #define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODSIGNATURE \ "(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/Class;Ljava/security/ProtectionDomain;[BZ)[B" /* * Error messages */ #define JPLIS_ERRORMESSAGE_CANNOTSTART "processing of -javaagent failed" /* * Our initialization errors */ typedef enum { JPLIS_INIT_ERROR_NONE, JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT, JPLIS_INIT_ERROR_FAILURE, JPLIS_INIT_ERROR_ALLOCATION_FAILURE, JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED } JPLISInitializationError; struct _JPLISEnvironment { jvmtiEnv * mJVMTIEnv; /* the JVM TI environment */ JPLISAgent * mAgent; /* corresponding agent */ jboolean mIsRetransformer; /* indicates if special environment */ }; struct _JPLISAgent { JavaVM * mJVM; /* handle to the JVM */ JPLISEnvironment mNormalEnvironment; /* for every thing but retransform stuff */ JPLISEnvironment mRetransformEnvironment;/* for retransform stuff only */ jobject mInstrumentationImpl; /* handle to the Instrumentation instance */ jmethodID mPremainCaller; /* method on the InstrumentationImpl that does the premain stuff (cached to save lots of lookups) */ jmethodID mAgentmainCaller; /* method on the InstrumentationImpl for agents loaded via attach mechanism */ jmethodID mTransform; /* method on the InstrumentationImpl that does the class file transform */ jboolean mRedefineAvailable; /* cached answer to "does this agent support redefine" */ jboolean mRedefineAdded; /* indicates if can_redefine_classes capability has been added */ jboolean mNativeMethodPrefixAvailable; /* cached answer to "does this agent support prefixing" */ jboolean mNativeMethodPrefixAdded; /* indicates if can_set_native_method_prefix capability has been added */ char const * mAgentClassName; /* agent class name */ char const * mOptionsString; /* -javaagent options string */ }; /* * JVMTI event handlers */ /* VMInit event handler. Installed during OnLoad, then removed during VMInit. */ extern void JNICALL eventHandlerVMInit( jvmtiEnv * jvmtienv, JNIEnv * jnienv, jthread thread); /* ClassFileLoadHook event handler. Installed during VMInit, then left in place forever. */ extern void JNICALL eventHandlerClassFileLoadHook( jvmtiEnv * jvmtienv, JNIEnv * jnienv, jclass class_being_redefined, jobject loader, const char* name, jobject protectionDomain, jint class_data_len, const unsigned char* class_data, jint* new_class_data_len, unsigned char** new_class_data); /* * Main entry points for the JPLIS JVMTI agent code */ /* looks up the environment instance. returns null if there isn't one */ extern JPLISEnvironment * getJPLISEnvironment(jvmtiEnv * jvmtienv); /* Creates a new JPLIS agent. * Returns error if the agent cannot be created and initialized. * The JPLISAgent* pointed to by agent_ptr is set to the new broker, * or NULL if an error has occurred. */ extern JPLISInitializationError createNewJPLISAgent(JavaVM * vm, JPLISAgent **agent_ptr); /* Adds can_redefine_classes capability */ extern void addRedefineClassesCapability(JPLISAgent * agent); /* Add the can_set_native_method_prefix capability */ extern void addNativeMethodPrefixCapability(JPLISAgent * agent); /* Add the can_maintain_original_method_order capability (for testing) */ extern void addOriginalMethodOrderCapability(JPLISAgent * agent); /* Our JPLIS agent is paralleled by a Java InstrumentationImpl instance. * This routine uses JNI to create and initialized the Java instance. * Returns true if it succeeds, false otherwise. */ extern jboolean createInstrumentationImpl( JNIEnv * jnienv, JPLISAgent * agent); /* during OnLoad phase (command line parsing) * record the parameters of -javaagent */ extern JPLISInitializationError recordCommandLineData( JPLISAgent * agent, const char * agentClass, const char * optionsString ); /* Swaps the start phase event handlers out and the live phase event handlers in. * Also used in attach to enabled live phase event handlers. * Returns true if it succeeds, false otherwise. */ extern jboolean setLivePhaseEventHandlers( JPLISAgent * agent); /* Loads the Java agent according to the already processed command line. For each, * loads the Java agent class, then calls the premain method. * Returns true if all Java agent classes are loaded and all premain methods complete with no exceptions, * false otherwise. */ extern jboolean startJavaAgent( JPLISAgent * agent, JNIEnv * jnienv, const char * classname, const char * optionsString, jmethodID agentMainMethod); /* during VMInit processing * this is how the invocation engine (callback wrapper) tells us to start up all the javaagents */ extern jboolean processJavaStart( JPLISAgent * agent, JNIEnv * jnienv); /* on an ongoing basis, * this is how the invocation engine (callback wrapper) tells us to process a class file */ extern void transformClassFile( JPLISAgent * agent, JNIEnv * jnienv, jobject loader, const char* name, jclass classBeingRedefined, jobject protectionDomain, jint class_data_len, const unsigned char* class_data, jint* new_class_data_len, unsigned char** new_class_data, jboolean is_retransformer); /* on an ongoing basis, * Return the environment with the retransformation capability. * Create it if it doesn't exist. */ extern jvmtiEnv * retransformableEnvironment(JPLISAgent * agent); /* on an ongoing basis, * these are implementations of the Instrumentation services. * Most are simple covers for JVMTI access services. These are the guts of the InstrumentationImpl * native methods. */ extern jboolean isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz); extern jboolean isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent); extern void setHasRetransformableTransformers(JNIEnv * jnienv, JPLISAgent * agent, jboolean has); extern void retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes); extern void redefineClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classDefinitions); extern jobjectArray getAllLoadedClasses(JNIEnv * jnienv, JPLISAgent * agent); extern jobjectArray getInitiatedClasses(JNIEnv * jnienv, JPLISAgent * agent, jobject classLoader); extern jlong getObjectSize(JNIEnv * jnienv, JPLISAgent * agent, jobject objectToSize); extern void appendToClassLoaderSearch(JNIEnv * jnienv, JPLISAgent * agent, jstring jarFile, jboolean isBootLoader); extern void setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefixArray, jboolean isRetransformable); #define jvmti(a) a->mNormalEnvironment.mJVMTIEnv /* * A set of macros for insulating the JLI method callers from * JVMTI_ERROR_WRONG_PHASE return codes. */ /* for a JLI method where "blob" is executed before simply returning */ #define check_phase_blob_ret(ret, blob) \ if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ blob; \ return; \ } /* for a JLI method where simply returning is benign */ #define check_phase_ret(ret) \ if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ return; \ } /* for a JLI method where returning zero (0) is benign */ #define check_phase_ret_0(ret) \ if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ return 0; \ } /* for a JLI method where returning one (1) is benign */ #define check_phase_ret_1(ret) \ if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ return 1; \ } /* for a case where a specific "blob" must be returned */ #define check_phase_ret_blob(ret, blob) \ if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ return (blob); \ } /* for a JLI method where returning false is benign */ #define check_phase_ret_false(ret) \ if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ return (jboolean) 0; \ } #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif