blob: 08d61636839f34e698804440975e609262a72c3a [file] [log] [blame]
/*
* Copyright (c) 2003, 2016, 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 <jni.h>
#include <jvmti.h>
#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 "<init>"
#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/Module;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 */
const char * mJarfile; /* agent jar file name */
};
/*
* 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