Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/instrument/JPLISAgent.c
38767 views
/*1* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* Copyright 2003 Wily Technology, Inc.27*/2829#include <jni.h>30#include <jvmti.h>31#include <stdlib.h>32#include <string.h>33#include "JPLISAgent.h"34#include "JPLISAssert.h"35#include "Utilities.h"36#include "Reentrancy.h"37#include "JavaExceptions.h"3839#include "EncodingSupport.h"40#include "FileSystemSupport.h" /* For MAXPATHLEN & uintptr_t */4142#include "sun_instrument_InstrumentationImpl.h"4344/*45* The JPLISAgent manages the initialization all of the Java programming language Agents.46* It also supports the native method bridge between the JPLIS and the JVMTI.47* It maintains a single JVMTI Env that all JPL agents share.48* It parses command line requests and creates individual Java agents.49*/505152/*53* private prototypes54*/5556/* Allocates an unformatted JPLIS agent data structure. Returns NULL if allocation fails. */57JPLISAgent *58allocateJPLISAgent(jvmtiEnv * jvmtiEnv);5960/* Initializes an already-allocated JPLIS agent data structure. */61JPLISInitializationError62initializeJPLISAgent( JPLISAgent * agent,63JavaVM * vm,64jvmtiEnv * jvmtienv);65/* De-allocates a JPLIS agent data structure. Only used in partial-failure cases at startup;66* in normal usage the JPLIS agent lives forever67*/68void69deallocateJPLISAgent( jvmtiEnv * jvmtienv,70JPLISAgent * agent);7172/* Does one-time work to interrogate the JVM about capabilities and cache the answers. */73void74checkCapabilities(JPLISAgent * agent);7576/* Takes the elements of the command string (agent class name and options string) and77* create java strings for them.78* Returns true if a classname was found. Makes no promises beyond the textual; says nothing about whether79* the class exists or can be loaded.80* If return value is true, sets outputClassname to a non-NULL local JNI reference.81* If return value is true, sets outputOptionsString either to NULL or to a non-NULL local JNI reference.82* If return value is false, neither output parameter is set.83*/84jboolean85commandStringIntoJavaStrings( JNIEnv * jnienv,86const char * classname,87const char * optionsString,88jstring * outputClassname,89jstring * outputOptionsString);9091/* Start one Java agent from the supplied parameters.92* Most of the logic lives in a helper function that lives over in Java code--93* we pass parameters out to Java and use our own Java helper to actually94* load the agent and call the premain.95* Returns true if the Java agent class is loaded and the premain/agentmain method completes96* with no exceptions, false otherwise.97*/98jboolean99invokeJavaAgentMainMethod( JNIEnv * jnienv,100jobject instrumentationImpl,101jmethodID agentMainMethod,102jstring className,103jstring optionsString);104105/* Once we have loaded the Java agent and called the premain,106* we can release the copies we have been keeping of the command line107* data (agent class name and option strings).108*/109void110deallocateCommandLineData(JPLISAgent * agent);111112/*113* Common support for various class list fetchers.114*/115typedef jvmtiError (*ClassListFetcher)116( jvmtiEnv * jvmtiEnv,117jobject classLoader,118jint * classCount,119jclass ** classes);120121/* Fetcher that ignores the class loader parameter, and uses the JVMTI to get a list of all classes.122* Returns a jvmtiError according to the underlying JVMTI service.123*/124jvmtiError125getAllLoadedClassesClassListFetcher( jvmtiEnv * jvmtiEnv,126jobject classLoader,127jint * classCount,128jclass ** classes);129130/* Fetcher that uses the class loader parameter, and uses the JVMTI to get a list of all classes131* for which the supplied loader is the initiating loader.132* Returns a jvmtiError according to the underlying JVMTI service.133*/134jvmtiError135getInitiatedClassesClassListFetcher( jvmtiEnv * jvmtiEnv,136jobject classLoader,137jint * classCount,138jclass ** classes);139140/*141* Common guts for two native methods, which are the same except for the policy for fetching142* the list of classes.143* Either returns a local JNI reference to an array of references to java.lang.Class.144* Can throw, if it does will alter the JNIEnv with an outstanding exception.145*/146jobjectArray147commonGetClassList( JNIEnv * jnienv,148JPLISAgent * agent,149jobject classLoader,150ClassListFetcher fetcher);151152153/*154* Misc. utilities.155*/156157/* Checked exception mapper used by the redefine classes implementation.158* Allows ClassNotFoundException or UnmodifiableClassException; maps others159* to InternalError. Can return NULL in an error case.160*/161jthrowable162redefineClassMapper( JNIEnv * jnienv,163jthrowable throwableToMap);164165/* Turns a buffer of jclass * into a Java array whose elements are java.lang.Class.166* Can throw, if it does will alter the JNIEnv with an outstanding exception.167*/168jobjectArray169getObjectArrayFromClasses(JNIEnv* jnienv, jclass* classes, jint classCount);170171172JPLISEnvironment *173getJPLISEnvironment(jvmtiEnv * jvmtienv) {174JPLISEnvironment * environment = NULL;175jvmtiError jvmtierror = JVMTI_ERROR_NONE;176177jvmtierror = (*jvmtienv)->GetEnvironmentLocalStorage(178jvmtienv,179(void**)&environment);180/* can be called from any phase */181jplis_assert(jvmtierror == JVMTI_ERROR_NONE);182183if (jvmtierror == JVMTI_ERROR_NONE) {184jplis_assert(environment != NULL);185jplis_assert(environment->mJVMTIEnv == jvmtienv);186} else {187environment = NULL;188}189return environment;190}191192/*193* OnLoad processing code.194*/195196/*197* Creates a new JPLISAgent.198* Returns error if the agent cannot be created and initialized.199* The JPLISAgent* pointed to by agent_ptr is set to the new broker,200* or NULL if an error has occurred.201*/202JPLISInitializationError203createNewJPLISAgent(JavaVM * vm, JPLISAgent **agent_ptr) {204JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE;205jvmtiEnv * jvmtienv = NULL;206jint jnierror = JNI_OK;207208*agent_ptr = NULL;209jnierror = (*vm)->GetEnv( vm,210(void **) &jvmtienv,211JVMTI_VERSION_1_1);212if ( jnierror != JNI_OK ) {213initerror = JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT;214} else {215JPLISAgent * agent = allocateJPLISAgent(jvmtienv);216if ( agent == NULL ) {217initerror = JPLIS_INIT_ERROR_ALLOCATION_FAILURE;218} else {219initerror = initializeJPLISAgent( agent,220vm,221jvmtienv);222if ( initerror == JPLIS_INIT_ERROR_NONE ) {223*agent_ptr = agent;224} else {225deallocateJPLISAgent(jvmtienv, agent);226}227}228229/* don't leak envs */230if ( initerror != JPLIS_INIT_ERROR_NONE ) {231jvmtiError jvmtierror = (*jvmtienv)->DisposeEnvironment(jvmtienv);232/* can be called from any phase */233jplis_assert(jvmtierror == JVMTI_ERROR_NONE);234}235}236237return initerror;238}239240/*241* Allocates a JPLISAgent. Returns NULL if it cannot be allocated242*/243JPLISAgent *244allocateJPLISAgent(jvmtiEnv * jvmtienv) {245return (JPLISAgent *) allocate( jvmtienv,246sizeof(JPLISAgent));247}248249JPLISInitializationError250initializeJPLISAgent( JPLISAgent * agent,251JavaVM * vm,252jvmtiEnv * jvmtienv) {253jvmtiError jvmtierror = JVMTI_ERROR_NONE;254jvmtiPhase phase;255256agent->mJVM = vm;257agent->mNormalEnvironment.mJVMTIEnv = jvmtienv;258agent->mNormalEnvironment.mAgent = agent;259agent->mNormalEnvironment.mIsRetransformer = JNI_FALSE;260agent->mRetransformEnvironment.mJVMTIEnv = NULL; /* NULL until needed */261agent->mRetransformEnvironment.mAgent = agent;262agent->mRetransformEnvironment.mIsRetransformer = JNI_FALSE; /* JNI_FALSE until mJVMTIEnv is set */263agent->mAgentmainCaller = NULL;264agent->mInstrumentationImpl = NULL;265agent->mPremainCaller = NULL;266agent->mTransform = NULL;267agent->mRedefineAvailable = JNI_FALSE; /* assume no for now */268agent->mRedefineAdded = JNI_FALSE;269agent->mNativeMethodPrefixAvailable = JNI_FALSE; /* assume no for now */270agent->mNativeMethodPrefixAdded = JNI_FALSE;271agent->mAgentClassName = NULL;272agent->mOptionsString = NULL;273274/* make sure we can recover either handle in either direction.275* the agent has a ref to the jvmti; make it mutual276*/277jvmtierror = (*jvmtienv)->SetEnvironmentLocalStorage(278jvmtienv,279&(agent->mNormalEnvironment));280/* can be called from any phase */281jplis_assert(jvmtierror == JVMTI_ERROR_NONE);282283/* check what capabilities are available */284checkCapabilities(agent);285286/* check phase - if live phase then we don't need the VMInit event */287jvmtierror = (*jvmtienv)->GetPhase(jvmtienv, &phase);288/* can be called from any phase */289jplis_assert(jvmtierror == JVMTI_ERROR_NONE);290if (phase == JVMTI_PHASE_LIVE) {291return JPLIS_INIT_ERROR_NONE;292}293294if (phase != JVMTI_PHASE_ONLOAD) {295/* called too early or called too late; either way bail out */296return JPLIS_INIT_ERROR_FAILURE;297}298299/* now turn on the VMInit event */300if ( jvmtierror == JVMTI_ERROR_NONE ) {301jvmtiEventCallbacks callbacks;302memset(&callbacks, 0, sizeof(callbacks));303callbacks.VMInit = &eventHandlerVMInit;304305jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv,306&callbacks,307sizeof(callbacks));308check_phase_ret_blob(jvmtierror, JPLIS_INIT_ERROR_FAILURE);309jplis_assert(jvmtierror == JVMTI_ERROR_NONE);310}311312if ( jvmtierror == JVMTI_ERROR_NONE ) {313jvmtierror = (*jvmtienv)->SetEventNotificationMode(314jvmtienv,315JVMTI_ENABLE,316JVMTI_EVENT_VM_INIT,317NULL /* all threads */);318check_phase_ret_blob(jvmtierror, JPLIS_INIT_ERROR_FAILURE);319jplis_assert(jvmtierror == JVMTI_ERROR_NONE);320}321322return (jvmtierror == JVMTI_ERROR_NONE)? JPLIS_INIT_ERROR_NONE : JPLIS_INIT_ERROR_FAILURE;323}324325void326deallocateJPLISAgent(jvmtiEnv * jvmtienv, JPLISAgent * agent) {327deallocate(jvmtienv, agent);328}329330331JPLISInitializationError332recordCommandLineData( JPLISAgent * agent,333const char * agentClassName,334const char * optionsString ) {335JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE;336char * ourCopyOfAgentClassName = NULL;337char * ourCopyOfOptionsString = NULL;338339/* if no actual params, bail out now */340if ((agentClassName == NULL) || (*agentClassName == 0)) {341initerror = JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED;342} else {343ourCopyOfAgentClassName = allocate(jvmti(agent), strlen(agentClassName)+1);344if (ourCopyOfAgentClassName == NULL) {345initerror = JPLIS_INIT_ERROR_ALLOCATION_FAILURE;346} else {347if (optionsString != NULL) {348ourCopyOfOptionsString = allocate(jvmti(agent), strlen(optionsString)+1);349if (ourCopyOfOptionsString == NULL) {350deallocate(jvmti(agent), ourCopyOfAgentClassName);351initerror = JPLIS_INIT_ERROR_ALLOCATION_FAILURE;352}353}354}355}356357if (initerror == JPLIS_INIT_ERROR_NONE) {358strcpy(ourCopyOfAgentClassName, agentClassName);359if (optionsString != NULL) {360strcpy(ourCopyOfOptionsString, optionsString);361}362agent->mAgentClassName = ourCopyOfAgentClassName;363agent->mOptionsString = ourCopyOfOptionsString;364}365366return initerror;367}368369/*370* VMInit processing code.371*/372373374/*375* If this call fails, the JVM launch will ultimately be aborted,376* so we don't have to be super-careful to clean up in partial failure377* cases.378*/379jboolean380processJavaStart( JPLISAgent * agent,381JNIEnv * jnienv) {382jboolean result;383384/*385* OK, Java is up now. We can start everything that needs Java.386*/387388/*389* First make our emergency fallback InternalError throwable.390*/391result = initializeFallbackError(jnienv);392jplis_assert(result);393394/*395* Now make the InstrumentationImpl instance.396*/397if ( result ) {398result = createInstrumentationImpl(jnienv, agent);399jplis_assert(result);400}401402403/*404* Then turn off the VMInit handler and turn on the ClassFileLoadHook.405* This way it is on before anyone registers a transformer.406*/407if ( result ) {408result = setLivePhaseEventHandlers(agent);409jplis_assert(result);410}411412/*413* Load the Java agent, and call the premain.414*/415if ( result ) {416result = startJavaAgent(agent, jnienv,417agent->mAgentClassName, agent->mOptionsString,418agent->mPremainCaller);419}420421/*422* Finally surrender all of the tracking data that we don't need any more.423* If something is wrong, skip it, we will be aborting the JVM anyway.424*/425if ( result ) {426deallocateCommandLineData(agent);427}428429return result;430}431432jboolean433startJavaAgent( JPLISAgent * agent,434JNIEnv * jnienv,435const char * classname,436const char * optionsString,437jmethodID agentMainMethod) {438jboolean success = JNI_FALSE;439jstring classNameObject = NULL;440jstring optionsStringObject = NULL;441442success = commandStringIntoJavaStrings( jnienv,443classname,444optionsString,445&classNameObject,446&optionsStringObject);447448if (success) {449success = invokeJavaAgentMainMethod( jnienv,450agent->mInstrumentationImpl,451agentMainMethod,452classNameObject,453optionsStringObject);454}455456return success;457}458459void460deallocateCommandLineData( JPLISAgent * agent) {461deallocate(jvmti(agent), (void*)agent->mAgentClassName);462deallocate(jvmti(agent), (void*)agent->mOptionsString);463464/* zero things out so it is easier to see what is going on */465agent->mAgentClassName = NULL;466agent->mOptionsString = NULL;467}468469/*470* Create the java.lang.instrument.Instrumentation instance471* and access information for it (method IDs, etc)472*/473jboolean474createInstrumentationImpl( JNIEnv * jnienv,475JPLISAgent * agent) {476jclass implClass = NULL;477jboolean errorOutstanding = JNI_FALSE;478jobject resultImpl = NULL;479jmethodID premainCallerMethodID = NULL;480jmethodID agentmainCallerMethodID = NULL;481jmethodID transformMethodID = NULL;482jmethodID constructorID = NULL;483jobject localReference = NULL;484485/* First find the class of our implementation */486implClass = (*jnienv)->FindClass( jnienv,487JPLIS_INSTRUMENTIMPL_CLASSNAME);488errorOutstanding = checkForAndClearThrowable(jnienv);489errorOutstanding = errorOutstanding || (implClass == NULL);490jplis_assert_msg(!errorOutstanding, "find class on InstrumentationImpl failed");491492if ( !errorOutstanding ) {493constructorID = (*jnienv)->GetMethodID( jnienv,494implClass,495JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODNAME,496JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODSIGNATURE);497errorOutstanding = checkForAndClearThrowable(jnienv);498errorOutstanding = errorOutstanding || (constructorID == NULL);499jplis_assert_msg(!errorOutstanding, "find constructor on InstrumentationImpl failed");500}501502if ( !errorOutstanding ) {503jlong peerReferenceAsScalar = (jlong)(intptr_t) agent;504localReference = (*jnienv)->NewObject( jnienv,505implClass,506constructorID,507peerReferenceAsScalar,508agent->mRedefineAdded,509agent->mNativeMethodPrefixAdded);510errorOutstanding = checkForAndClearThrowable(jnienv);511errorOutstanding = errorOutstanding || (localReference == NULL);512jplis_assert_msg(!errorOutstanding, "call constructor on InstrumentationImpl failed");513}514515if ( !errorOutstanding ) {516resultImpl = (*jnienv)->NewGlobalRef(jnienv, localReference);517errorOutstanding = checkForAndClearThrowable(jnienv);518jplis_assert_msg(!errorOutstanding, "copy local ref to global ref");519}520521/* Now look up the method ID for the pre-main caller (we will need this more than once) */522if ( !errorOutstanding ) {523premainCallerMethodID = (*jnienv)->GetMethodID( jnienv,524implClass,525JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODNAME,526JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODSIGNATURE);527errorOutstanding = checkForAndClearThrowable(jnienv);528errorOutstanding = errorOutstanding || (premainCallerMethodID == NULL);529jplis_assert_msg(!errorOutstanding, "can't find premain invoker methodID");530}531532/* Now look up the method ID for the agent-main caller */533if ( !errorOutstanding ) {534agentmainCallerMethodID = (*jnienv)->GetMethodID( jnienv,535implClass,536JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODNAME,537JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODSIGNATURE);538errorOutstanding = checkForAndClearThrowable(jnienv);539errorOutstanding = errorOutstanding || (agentmainCallerMethodID == NULL);540jplis_assert_msg(!errorOutstanding, "can't find agentmain invoker methodID");541}542543/* Now look up the method ID for the transform method (we will need this constantly) */544if ( !errorOutstanding ) {545transformMethodID = (*jnienv)->GetMethodID( jnienv,546implClass,547JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODNAME,548JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODSIGNATURE);549errorOutstanding = checkForAndClearThrowable(jnienv);550errorOutstanding = errorOutstanding || (transformMethodID == NULL);551jplis_assert_msg(!errorOutstanding, "can't find transform methodID");552}553554if ( !errorOutstanding ) {555agent->mInstrumentationImpl = resultImpl;556agent->mPremainCaller = premainCallerMethodID;557agent->mAgentmainCaller = agentmainCallerMethodID;558agent->mTransform = transformMethodID;559}560561return !errorOutstanding;562}563564jboolean565commandStringIntoJavaStrings( JNIEnv * jnienv,566const char * classname,567const char * optionsString,568jstring * outputClassname,569jstring * outputOptionsString) {570jstring classnameJavaString = NULL;571jstring optionsJavaString = NULL;572jboolean errorOutstanding = JNI_TRUE;573574classnameJavaString = (*jnienv)->NewStringUTF(jnienv, classname);575errorOutstanding = checkForAndClearThrowable(jnienv);576jplis_assert_msg(!errorOutstanding, "can't create class name java string");577578if ( !errorOutstanding ) {579if ( optionsString != NULL) {580optionsJavaString = (*jnienv)->NewStringUTF(jnienv, optionsString);581errorOutstanding = checkForAndClearThrowable(jnienv);582jplis_assert_msg(!errorOutstanding, "can't create options java string");583}584585if ( !errorOutstanding ) {586*outputClassname = classnameJavaString;587*outputOptionsString = optionsJavaString;588}589}590591return !errorOutstanding;592}593594595jboolean596invokeJavaAgentMainMethod( JNIEnv * jnienv,597jobject instrumentationImpl,598jmethodID mainCallingMethod,599jstring className,600jstring optionsString) {601jboolean errorOutstanding = JNI_FALSE;602603jplis_assert(mainCallingMethod != NULL);604if ( mainCallingMethod != NULL ) {605(*jnienv)->CallVoidMethod( jnienv,606instrumentationImpl,607mainCallingMethod,608className,609optionsString);610errorOutstanding = checkForThrowable(jnienv);611if ( errorOutstanding ) {612logThrowable(jnienv);613}614checkForAndClearThrowable(jnienv);615}616return !errorOutstanding;617}618619jboolean620setLivePhaseEventHandlers( JPLISAgent * agent) {621jvmtiEventCallbacks callbacks;622jvmtiEnv * jvmtienv = jvmti(agent);623jvmtiError jvmtierror;624625/* first swap out the handlers (switch from the VMInit handler, which we do not need,626* to the ClassFileLoadHook handler, which is what the agents need from now on)627*/628memset(&callbacks, 0, sizeof(callbacks));629callbacks.ClassFileLoadHook = &eventHandlerClassFileLoadHook;630631jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv,632&callbacks,633sizeof(callbacks));634check_phase_ret_false(jvmtierror);635jplis_assert(jvmtierror == JVMTI_ERROR_NONE);636637638if ( jvmtierror == JVMTI_ERROR_NONE ) {639/* turn off VMInit */640jvmtierror = (*jvmtienv)->SetEventNotificationMode(641jvmtienv,642JVMTI_DISABLE,643JVMTI_EVENT_VM_INIT,644NULL /* all threads */);645check_phase_ret_false(jvmtierror);646jplis_assert(jvmtierror == JVMTI_ERROR_NONE);647}648649if ( jvmtierror == JVMTI_ERROR_NONE ) {650/* turn on ClassFileLoadHook */651jvmtierror = (*jvmtienv)->SetEventNotificationMode(652jvmtienv,653JVMTI_ENABLE,654JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,655NULL /* all threads */);656check_phase_ret_false(jvmtierror);657jplis_assert(jvmtierror == JVMTI_ERROR_NONE);658}659660return (jvmtierror == JVMTI_ERROR_NONE);661}662663/**664* Check if the can_redefine_classes capability is available.665*/666void667checkCapabilities(JPLISAgent * agent) {668jvmtiEnv * jvmtienv = jvmti(agent);669jvmtiCapabilities potentialCapabilities;670jvmtiError jvmtierror;671672memset(&potentialCapabilities, 0, sizeof(potentialCapabilities));673674jvmtierror = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &potentialCapabilities);675check_phase_ret(jvmtierror);676jplis_assert(jvmtierror == JVMTI_ERROR_NONE);677678if ( jvmtierror == JVMTI_ERROR_NONE ) {679if ( potentialCapabilities.can_redefine_classes == 1 ) {680agent->mRedefineAvailable = JNI_TRUE;681}682if ( potentialCapabilities.can_set_native_method_prefix == 1 ) {683agent->mNativeMethodPrefixAvailable = JNI_TRUE;684}685}686}687688/**689* Enable native method prefix in one JVM TI environment690*/691void692enableNativeMethodPrefixCapability(jvmtiEnv * jvmtienv) {693jvmtiCapabilities desiredCapabilities;694jvmtiError jvmtierror;695696jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);697/* can be called from any phase */698jplis_assert(jvmtierror == JVMTI_ERROR_NONE);699desiredCapabilities.can_set_native_method_prefix = 1;700jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);701check_phase_ret(jvmtierror);702jplis_assert(jvmtierror == JVMTI_ERROR_NONE);703}704705706/**707* Add the can_set_native_method_prefix capability708*/709void710addNativeMethodPrefixCapability(JPLISAgent * agent) {711if (agent->mNativeMethodPrefixAvailable && !agent->mNativeMethodPrefixAdded) {712jvmtiEnv * jvmtienv = agent->mNormalEnvironment.mJVMTIEnv;713enableNativeMethodPrefixCapability(jvmtienv);714715jvmtienv = agent->mRetransformEnvironment.mJVMTIEnv;716if (jvmtienv != NULL) {717enableNativeMethodPrefixCapability(jvmtienv);718}719agent->mNativeMethodPrefixAdded = JNI_TRUE;720}721}722723/**724* Add the can_maintain_original_method_order capability (for testing)725*/726void727addOriginalMethodOrderCapability(JPLISAgent * agent) {728jvmtiEnv * jvmtienv = jvmti(agent);729jvmtiCapabilities desiredCapabilities;730jvmtiError jvmtierror;731732jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);733/* can be called from any phase */734jplis_assert(jvmtierror == JVMTI_ERROR_NONE);735desiredCapabilities.can_maintain_original_method_order = 1;736jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);737check_phase_ret(jvmtierror);738jplis_assert(jvmtierror == JVMTI_ERROR_NONE);739}740741/**742* Add the can_redefine_classes capability743*/744void745addRedefineClassesCapability(JPLISAgent * agent) {746jvmtiEnv * jvmtienv = jvmti(agent);747jvmtiCapabilities desiredCapabilities;748jvmtiError jvmtierror;749750if (agent->mRedefineAvailable && !agent->mRedefineAdded) {751jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);752/* can be called from any phase */753jplis_assert(jvmtierror == JVMTI_ERROR_NONE);754desiredCapabilities.can_redefine_classes = 1;755jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);756check_phase_ret(jvmtierror);757758/*759* With mixed premain/agentmain agents then it's possible that the760* capability was potentially available in the onload phase but761* subsequently unavailable in the live phase.762*/763jplis_assert(jvmtierror == JVMTI_ERROR_NONE ||764jvmtierror == JVMTI_ERROR_NOT_AVAILABLE);765if (jvmtierror == JVMTI_ERROR_NONE) {766agent->mRedefineAdded = JNI_TRUE;767}768}769}770771772/*773* Support for the JVMTI callbacks774*/775776void777transformClassFile( JPLISAgent * agent,778JNIEnv * jnienv,779jobject loaderObject,780const char* name,781jclass classBeingRedefined,782jobject protectionDomain,783jint class_data_len,784const unsigned char* class_data,785jint* new_class_data_len,786unsigned char** new_class_data,787jboolean is_retransformer) {788jboolean errorOutstanding = JNI_FALSE;789jstring classNameStringObject = NULL;790jarray classFileBufferObject = NULL;791jarray transformedBufferObject = NULL;792jsize transformedBufferSize = 0;793unsigned char * resultBuffer = NULL;794jboolean shouldRun = JNI_FALSE;795796/* only do this if we aren't already in the middle of processing a class on this thread */797shouldRun = tryToAcquireReentrancyToken(798jvmti(agent),799NULL); /* this thread */800801if ( shouldRun ) {802/* first marshall all the parameters */803classNameStringObject = (*jnienv)->NewStringUTF(jnienv,804name);805errorOutstanding = checkForAndClearThrowable(jnienv);806jplis_assert_msg(!errorOutstanding, "can't create name string");807808if ( !errorOutstanding ) {809classFileBufferObject = (*jnienv)->NewByteArray(jnienv,810class_data_len);811errorOutstanding = checkForAndClearThrowable(jnienv);812jplis_assert_msg(!errorOutstanding, "can't create byte arrau");813}814815if ( !errorOutstanding ) {816jbyte * typedBuffer = (jbyte *) class_data; /* nasty cast, dumb JNI interface, const missing */817/* The sign cast is safe. The const cast is dumb. */818(*jnienv)->SetByteArrayRegion( jnienv,819classFileBufferObject,8200,821class_data_len,822typedBuffer);823errorOutstanding = checkForAndClearThrowable(jnienv);824jplis_assert_msg(!errorOutstanding, "can't set byte array region");825}826827/* now call the JPL agents to do the transforming */828/* potential future optimization: may want to skip this if there are none */829if ( !errorOutstanding ) {830jplis_assert(agent->mInstrumentationImpl != NULL);831jplis_assert(agent->mTransform != NULL);832transformedBufferObject = (*jnienv)->CallObjectMethod(833jnienv,834agent->mInstrumentationImpl,835agent->mTransform,836loaderObject,837classNameStringObject,838classBeingRedefined,839protectionDomain,840classFileBufferObject,841is_retransformer);842errorOutstanding = checkForAndClearThrowable(jnienv);843jplis_assert_msg(!errorOutstanding, "transform method call failed");844}845846/* Finally, unmarshall the parameters (if someone touched the buffer, tell the JVM) */847if ( !errorOutstanding ) {848if ( transformedBufferObject != NULL ) {849transformedBufferSize = (*jnienv)->GetArrayLength( jnienv,850transformedBufferObject);851errorOutstanding = checkForAndClearThrowable(jnienv);852jplis_assert_msg(!errorOutstanding, "can't get array length");853854if ( !errorOutstanding ) {855/* allocate the response buffer with the JVMTI allocate call.856* This is what the JVMTI spec says to do for Class File Load hook responses857*/858jvmtiError allocError = (*(jvmti(agent)))->Allocate(jvmti(agent),859transformedBufferSize,860&resultBuffer);861errorOutstanding = (allocError != JVMTI_ERROR_NONE);862jplis_assert_msg(!errorOutstanding, "can't allocate result buffer");863}864865if ( !errorOutstanding ) {866(*jnienv)->GetByteArrayRegion( jnienv,867transformedBufferObject,8680,869transformedBufferSize,870(jbyte *) resultBuffer);871errorOutstanding = checkForAndClearThrowable(jnienv);872jplis_assert_msg(!errorOutstanding, "can't get byte array region");873874/* in this case, we will not return the buffer to the JVMTI,875* so we need to deallocate it ourselves876*/877if ( errorOutstanding ) {878deallocate( jvmti(agent),879(void*)resultBuffer);880}881}882883if ( !errorOutstanding ) {884*new_class_data_len = (transformedBufferSize);885*new_class_data = resultBuffer;886}887}888}889890/* release the token */891releaseReentrancyToken( jvmti(agent),892NULL); /* this thread */893894}895896return;897}898899/*900* Misc. internal utilities.901*/902903/*904* The only checked exceptions we can throw are ClassNotFoundException and905* UnmodifiableClassException. All others map to InternalError.906*/907jthrowable908redefineClassMapper( JNIEnv * jnienv,909jthrowable throwableToMap) {910jthrowable mappedThrowable = NULL;911912jplis_assert(isSafeForJNICalls(jnienv));913jplis_assert(!isUnchecked(jnienv, throwableToMap));914915if ( isInstanceofClassName( jnienv,916throwableToMap,917"java/lang/ClassNotFoundException") ) {918mappedThrowable = throwableToMap;919} else {920if ( isInstanceofClassName( jnienv,921throwableToMap,922"java/lang/instrument/UnmodifiableClassException")) {923mappedThrowable = throwableToMap;924} else {925jstring message = NULL;926927message = getMessageFromThrowable(jnienv, throwableToMap);928mappedThrowable = createInternalError(jnienv, message);929}930}931932jplis_assert(isSafeForJNICalls(jnienv));933return mappedThrowable;934}935936jobjectArray937getObjectArrayFromClasses(JNIEnv* jnienv, jclass* classes, jint classCount) {938jclass classArrayClass = NULL;939jobjectArray localArray = NULL;940jint classIndex = 0;941jboolean errorOccurred = JNI_FALSE;942943/* get the class array class */944classArrayClass = (*jnienv)->FindClass(jnienv, "java/lang/Class");945errorOccurred = checkForThrowable(jnienv);946947if (!errorOccurred) {948jplis_assert_msg(classArrayClass != NULL, "FindClass returned null class");949950/* create the array for the classes */951localArray = (*jnienv)->NewObjectArray(jnienv, classCount, classArrayClass, NULL);952errorOccurred = checkForThrowable(jnienv);953954if (!errorOccurred) {955jplis_assert_msg(localArray != NULL, "NewObjectArray returned null array");956957/* now copy refs to all the classes and put them into the array */958for (classIndex = 0; classIndex < classCount; classIndex++) {959/* put class into array */960(*jnienv)->SetObjectArrayElement(jnienv, localArray, classIndex, classes[classIndex]);961errorOccurred = checkForThrowable(jnienv);962963if (errorOccurred) {964localArray = NULL;965break;966}967}968}969}970971return localArray;972}973974975/* Return the environment with the retransformation capability.976* Create it if it doesn't exist.977* Return NULL if it can't be created.978*/979jvmtiEnv *980retransformableEnvironment(JPLISAgent * agent) {981jvmtiEnv * retransformerEnv = NULL;982jint jnierror = JNI_OK;983jvmtiCapabilities desiredCapabilities;984jvmtiEventCallbacks callbacks;985jvmtiError jvmtierror;986987if (agent->mRetransformEnvironment.mJVMTIEnv != NULL) {988return agent->mRetransformEnvironment.mJVMTIEnv;989}990jnierror = (*agent->mJVM)->GetEnv( agent->mJVM,991(void **) &retransformerEnv,992JVMTI_VERSION_1_1);993if ( jnierror != JNI_OK ) {994return NULL;995}996jvmtierror = (*retransformerEnv)->GetCapabilities(retransformerEnv, &desiredCapabilities);997jplis_assert(jvmtierror == JVMTI_ERROR_NONE);998desiredCapabilities.can_retransform_classes = 1;999if (agent->mNativeMethodPrefixAdded) {1000desiredCapabilities.can_set_native_method_prefix = 1;1001}10021003jvmtierror = (*retransformerEnv)->AddCapabilities(retransformerEnv, &desiredCapabilities);1004if (jvmtierror != JVMTI_ERROR_NONE) {1005/* cannot get the capability, dispose of the retransforming environment */1006jvmtierror = (*retransformerEnv)->DisposeEnvironment(retransformerEnv);1007jplis_assert(jvmtierror == JVMTI_ERROR_NOT_AVAILABLE);1008return NULL;1009}1010memset(&callbacks, 0, sizeof(callbacks));1011callbacks.ClassFileLoadHook = &eventHandlerClassFileLoadHook;10121013jvmtierror = (*retransformerEnv)->SetEventCallbacks(retransformerEnv,1014&callbacks,1015sizeof(callbacks));1016jplis_assert(jvmtierror == JVMTI_ERROR_NONE);1017if (jvmtierror == JVMTI_ERROR_NONE) {1018// install the retransforming environment1019agent->mRetransformEnvironment.mJVMTIEnv = retransformerEnv;1020agent->mRetransformEnvironment.mIsRetransformer = JNI_TRUE;10211022// Make it for ClassFileLoadHook handling1023jvmtierror = (*retransformerEnv)->SetEnvironmentLocalStorage(1024retransformerEnv,1025&(agent->mRetransformEnvironment));1026jplis_assert(jvmtierror == JVMTI_ERROR_NONE);1027if (jvmtierror == JVMTI_ERROR_NONE) {1028return retransformerEnv;1029}1030}1031return NULL;1032}103310341035/*1036* Underpinnings for native methods1037*/10381039jboolean1040isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz) {1041jvmtiEnv * jvmtienv = jvmti(agent);1042jvmtiError jvmtierror;1043jboolean is_modifiable = JNI_FALSE;10441045jvmtierror = (*jvmtienv)->IsModifiableClass( jvmtienv,1046clazz,1047&is_modifiable);1048check_phase_ret_false(jvmtierror);1049jplis_assert(jvmtierror == JVMTI_ERROR_NONE);10501051return is_modifiable;1052}10531054jboolean1055isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent) {1056return agent->mRetransformEnvironment.mIsRetransformer;1057}10581059void1060setHasRetransformableTransformers(JNIEnv * jnienv, JPLISAgent * agent, jboolean has) {1061jvmtiEnv * retransformerEnv = retransformableEnvironment(agent);1062jvmtiError jvmtierror;10631064jplis_assert(retransformerEnv != NULL);1065jvmtierror = (*retransformerEnv)->SetEventNotificationMode(1066retransformerEnv,1067has? JVMTI_ENABLE : JVMTI_DISABLE,1068JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,1069NULL /* all threads */);1070jplis_assert(jvmtierror == JVMTI_ERROR_NONE);1071}10721073void1074retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes) {1075jvmtiEnv * retransformerEnv = retransformableEnvironment(agent);1076jboolean errorOccurred = JNI_FALSE;1077jvmtiError errorCode = JVMTI_ERROR_NONE;1078jsize numClasses = 0;1079jclass * classArray = NULL;10801081/* This is supposed to be checked by caller, but just to be sure */1082if (retransformerEnv == NULL) {1083jplis_assert(retransformerEnv != NULL);1084errorOccurred = JNI_TRUE;1085errorCode = JVMTI_ERROR_MUST_POSSESS_CAPABILITY;1086}10871088/* This was supposed to be checked by caller too */1089if (!errorOccurred && classes == NULL) {1090jplis_assert(classes != NULL);1091errorOccurred = JNI_TRUE;1092errorCode = JVMTI_ERROR_NULL_POINTER;1093}10941095if (!errorOccurred) {1096numClasses = (*jnienv)->GetArrayLength(jnienv, classes);1097errorOccurred = checkForThrowable(jnienv);1098jplis_assert(!errorOccurred);10991100if (!errorOccurred && numClasses == 0) {1101jplis_assert(numClasses != 0);1102errorOccurred = JNI_TRUE;1103errorCode = JVMTI_ERROR_NULL_POINTER;1104}1105}11061107if (!errorOccurred) {1108classArray = (jclass *) allocate(retransformerEnv,1109numClasses * sizeof(jclass));1110errorOccurred = (classArray == NULL);1111jplis_assert(!errorOccurred);1112if (errorOccurred) {1113errorCode = JVMTI_ERROR_OUT_OF_MEMORY;1114}1115}11161117if (!errorOccurred) {1118jint index;1119for (index = 0; index < numClasses; index++) {1120classArray[index] = (*jnienv)->GetObjectArrayElement(jnienv, classes, index);1121errorOccurred = checkForThrowable(jnienv);1122jplis_assert(!errorOccurred);1123if (errorOccurred) {1124break;1125}11261127if (classArray[index] == NULL) {1128jplis_assert(classArray[index] != NULL);1129errorOccurred = JNI_TRUE;1130errorCode = JVMTI_ERROR_NULL_POINTER;1131break;1132}1133}1134}11351136if (!errorOccurred) {1137errorCode = (*retransformerEnv)->RetransformClasses(retransformerEnv,1138numClasses, classArray);1139errorOccurred = (errorCode != JVMTI_ERROR_NONE);1140}11411142/* Give back the buffer if we allocated it. Throw any exceptions after.1143*/1144if (classArray != NULL) {1145deallocate(retransformerEnv, (void*)classArray);1146}11471148if (errorCode != JVMTI_ERROR_NONE) {1149createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode);1150}11511152mapThrownThrowableIfNecessary(jnienv, redefineClassMapper);1153}11541155/*1156* Java code must not call this with a null list or a zero-length list.1157*/1158void1159redefineClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classDefinitions) {1160jvmtiEnv* jvmtienv = jvmti(agent);1161jboolean errorOccurred = JNI_FALSE;1162jclass classDefClass = NULL;1163jmethodID getDefinitionClassMethodID = NULL;1164jmethodID getDefinitionClassFileMethodID = NULL;1165jvmtiClassDefinition* classDefs = NULL;1166jbyteArray* targetFiles = NULL;1167jsize numDefs = 0;11681169jplis_assert(classDefinitions != NULL);11701171numDefs = (*jnienv)->GetArrayLength(jnienv, classDefinitions);1172errorOccurred = checkForThrowable(jnienv);1173jplis_assert(!errorOccurred);11741175if (!errorOccurred) {1176jplis_assert(numDefs > 0);1177/* get method IDs for methods to call on class definitions */1178classDefClass = (*jnienv)->FindClass(jnienv, "java/lang/instrument/ClassDefinition");1179errorOccurred = checkForThrowable(jnienv);1180jplis_assert(!errorOccurred);1181}11821183if (!errorOccurred) {1184getDefinitionClassMethodID = (*jnienv)->GetMethodID( jnienv,1185classDefClass,1186"getDefinitionClass",1187"()Ljava/lang/Class;");1188errorOccurred = checkForThrowable(jnienv);1189jplis_assert(!errorOccurred);1190}11911192if (!errorOccurred) {1193getDefinitionClassFileMethodID = (*jnienv)->GetMethodID( jnienv,1194classDefClass,1195"getDefinitionClassFile",1196"()[B");1197errorOccurred = checkForThrowable(jnienv);1198jplis_assert(!errorOccurred);1199}12001201if (!errorOccurred) {1202classDefs = (jvmtiClassDefinition *) allocate(1203jvmtienv,1204numDefs * sizeof(jvmtiClassDefinition));1205errorOccurred = (classDefs == NULL);1206jplis_assert(!errorOccurred);1207if ( errorOccurred ) {1208createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY);1209}12101211else {1212/*1213* We have to save the targetFile values that we compute so1214* that we can release the class_bytes arrays that are1215* returned by GetByteArrayElements(). In case of a JNI1216* error, we can't (easily) recompute the targetFile values1217* and we still want to free any memory we allocated.1218*/1219targetFiles = (jbyteArray *) allocate(jvmtienv,1220numDefs * sizeof(jbyteArray));1221errorOccurred = (targetFiles == NULL);1222jplis_assert(!errorOccurred);1223if ( errorOccurred ) {1224deallocate(jvmtienv, (void*)classDefs);1225createAndThrowThrowableFromJVMTIErrorCode(jnienv,1226JVMTI_ERROR_OUT_OF_MEMORY);1227}1228else {1229jint i, j;12301231// clear classDefs so we can correctly free memory during errors1232memset(classDefs, 0, numDefs * sizeof(jvmtiClassDefinition));12331234for (i = 0; i < numDefs; i++) {1235jclass classDef = NULL;12361237classDef = (*jnienv)->GetObjectArrayElement(jnienv, classDefinitions, i);1238errorOccurred = checkForThrowable(jnienv);1239jplis_assert(!errorOccurred);1240if (errorOccurred) {1241break;1242}12431244classDefs[i].klass = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassMethodID);1245errorOccurred = checkForThrowable(jnienv);1246jplis_assert(!errorOccurred);1247if (errorOccurred) {1248break;1249}12501251targetFiles[i] = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassFileMethodID);1252errorOccurred = checkForThrowable(jnienv);1253jplis_assert(!errorOccurred);1254if (errorOccurred) {1255break;1256}12571258classDefs[i].class_byte_count = (*jnienv)->GetArrayLength(jnienv, targetFiles[i]);1259errorOccurred = checkForThrowable(jnienv);1260jplis_assert(!errorOccurred);1261if (errorOccurred) {1262break;1263}12641265/*1266* Allocate class_bytes last so we don't have to free1267* memory on a partial row error.1268*/1269classDefs[i].class_bytes = (unsigned char*)(*jnienv)->GetByteArrayElements(jnienv, targetFiles[i], NULL);1270errorOccurred = checkForThrowable(jnienv);1271jplis_assert(!errorOccurred);1272if (errorOccurred) {1273break;1274}1275}12761277if (!errorOccurred) {1278jvmtiError errorCode = JVMTI_ERROR_NONE;1279errorCode = (*jvmtienv)->RedefineClasses(jvmtienv, numDefs, classDefs);1280if (errorCode == JVMTI_ERROR_WRONG_PHASE) {1281/* insulate caller from the wrong phase error */1282errorCode = JVMTI_ERROR_NONE;1283} else {1284errorOccurred = (errorCode != JVMTI_ERROR_NONE);1285if ( errorOccurred ) {1286createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode);1287}1288}1289}12901291/*1292* Cleanup memory that we allocated above. If we had a1293* JNI error, a JVM/TI error or no errors, index 'i'1294* tracks how far we got in processing the classDefs1295* array. Note: ReleaseByteArrayElements() is safe to1296* call with a JNI exception pending.1297*/1298for (j = 0; j < i; j++) {1299if ((jbyte *)classDefs[j].class_bytes != NULL) {1300(*jnienv)->ReleaseByteArrayElements(jnienv,1301targetFiles[j], (jbyte *)classDefs[j].class_bytes,13020 /* copy back and free */);1303/*1304* Only check for error if we didn't already have one1305* so we don't overwrite errorOccurred.1306*/1307if (!errorOccurred) {1308errorOccurred = checkForThrowable(jnienv);1309jplis_assert(!errorOccurred);1310}1311}1312}1313deallocate(jvmtienv, (void*)targetFiles);1314deallocate(jvmtienv, (void*)classDefs);1315}1316}1317}13181319mapThrownThrowableIfNecessary(jnienv, redefineClassMapper);1320}13211322/* Cheesy sharing. ClassLoader may be null. */1323jobjectArray1324commonGetClassList( JNIEnv * jnienv,1325JPLISAgent * agent,1326jobject classLoader,1327ClassListFetcher fetcher) {1328jvmtiEnv * jvmtienv = jvmti(agent);1329jboolean errorOccurred = JNI_FALSE;1330jvmtiError jvmtierror = JVMTI_ERROR_NONE;1331jint classCount = 0;1332jclass * classes = NULL;1333jobjectArray localArray = NULL;13341335/* retrieve the classes from the JVMTI agent */1336jvmtierror = (*fetcher)( jvmtienv,1337classLoader,1338&classCount,1339&classes);1340check_phase_ret_blob(jvmtierror, localArray);1341errorOccurred = (jvmtierror != JVMTI_ERROR_NONE);1342jplis_assert(!errorOccurred);13431344if ( errorOccurred ) {1345createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);1346} else {1347localArray = getObjectArrayFromClasses( jnienv,1348classes,1349classCount);1350errorOccurred = checkForThrowable(jnienv);1351jplis_assert(!errorOccurred);13521353/* do this whether or not we saw a problem */1354deallocate(jvmtienv, (void*)classes);1355}13561357mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper);1358return localArray;13591360}13611362jvmtiError1363getAllLoadedClassesClassListFetcher( jvmtiEnv * jvmtienv,1364jobject classLoader,1365jint * classCount,1366jclass ** classes) {1367return (*jvmtienv)->GetLoadedClasses(jvmtienv, classCount, classes);1368}13691370jobjectArray1371getAllLoadedClasses(JNIEnv * jnienv, JPLISAgent * agent) {1372return commonGetClassList( jnienv,1373agent,1374NULL,1375getAllLoadedClassesClassListFetcher);1376}13771378jvmtiError1379getInitiatedClassesClassListFetcher( jvmtiEnv * jvmtienv,1380jobject classLoader,1381jint * classCount,1382jclass ** classes) {1383return (*jvmtienv)->GetClassLoaderClasses(jvmtienv, classLoader, classCount, classes);1384}138513861387jobjectArray1388getInitiatedClasses(JNIEnv * jnienv, JPLISAgent * agent, jobject classLoader) {1389return commonGetClassList( jnienv,1390agent,1391classLoader,1392getInitiatedClassesClassListFetcher);1393}13941395jlong1396getObjectSize(JNIEnv * jnienv, JPLISAgent * agent, jobject objectToSize) {1397jvmtiEnv * jvmtienv = jvmti(agent);1398jlong objectSize = -1;1399jvmtiError jvmtierror = JVMTI_ERROR_NONE;14001401jvmtierror = (*jvmtienv)->GetObjectSize(jvmtienv, objectToSize, &objectSize);1402check_phase_ret_0(jvmtierror);1403jplis_assert(jvmtierror == JVMTI_ERROR_NONE);1404if ( jvmtierror != JVMTI_ERROR_NONE ) {1405createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);1406}14071408mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper);1409return objectSize;1410}14111412void1413appendToClassLoaderSearch(JNIEnv * jnienv, JPLISAgent * agent, jstring jarFile, jboolean isBootLoader)1414{1415jvmtiEnv * jvmtienv = jvmti(agent);1416jboolean errorOutstanding;1417jvmtiError jvmtierror;1418const char* utf8Chars;1419jsize utf8Len;1420jboolean isCopy;1421char platformChars[MAXPATHLEN];1422int platformLen;14231424utf8Len = (*jnienv)->GetStringUTFLength(jnienv, jarFile);1425errorOutstanding = checkForAndClearThrowable(jnienv);14261427if (!errorOutstanding) {1428utf8Chars = (*jnienv)->GetStringUTFChars(jnienv, jarFile, &isCopy);1429errorOutstanding = checkForAndClearThrowable(jnienv);14301431if (!errorOutstanding && utf8Chars != NULL) {1432/*1433* JVMTI spec'ed to use modified UTF8. At this time this is not implemented1434* the platform encoding is used.1435*/1436platformLen = convertUft8ToPlatformString((char*)utf8Chars, utf8Len, platformChars, MAXPATHLEN);1437if (platformLen < 0) {1438createAndThrowInternalError(jnienv);1439return;1440}14411442(*jnienv)->ReleaseStringUTFChars(jnienv, jarFile, utf8Chars);1443errorOutstanding = checkForAndClearThrowable(jnienv);14441445if (!errorOutstanding) {14461447if (isBootLoader) {1448jvmtierror = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, platformChars);1449} else {1450jvmtierror = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, platformChars);1451}1452check_phase_ret(jvmtierror);14531454if ( jvmtierror != JVMTI_ERROR_NONE ) {1455createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);1456}1457}1458}1459}14601461mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper);1462}14631464/*1465* Set the prefixes used to wrap native methods (so they can be instrumented).1466* Each transform can set a prefix, any that have been set come in as prefixArray.1467* Convert them in native strings in a native array then call JVM TI.1468* One a given call, this function handles either the prefixes for retransformable1469* transforms or for normal transforms.1470*/1471void1472setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefixArray,1473jboolean isRetransformable) {1474jvmtiEnv* jvmtienv;1475jvmtiError err = JVMTI_ERROR_NONE;1476jsize arraySize;1477jboolean errorOccurred = JNI_FALSE;14781479jplis_assert(prefixArray != NULL);14801481if (isRetransformable) {1482jvmtienv = agent->mRetransformEnvironment.mJVMTIEnv;1483} else {1484jvmtienv = agent->mNormalEnvironment.mJVMTIEnv;1485}1486arraySize = (*jnienv)->GetArrayLength(jnienv, prefixArray);1487errorOccurred = checkForThrowable(jnienv);1488jplis_assert(!errorOccurred);14891490if (!errorOccurred) {1491/* allocate the native to hold the native prefixes */1492const char** prefixes = (const char**) allocate(jvmtienv,1493arraySize * sizeof(char*));1494/* since JNI ReleaseStringUTFChars needs the jstring from which the native1495* string was allocated, we store them in a parallel array */1496jstring* originForRelease = (jstring*) allocate(jvmtienv,1497arraySize * sizeof(jstring));1498errorOccurred = (prefixes == NULL || originForRelease == NULL);1499jplis_assert(!errorOccurred);1500if ( errorOccurred ) {1501createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY);1502}1503else {1504jint inx = 0;1505jint i;1506for (i = 0; i < arraySize; i++) {1507jstring prefixStr = NULL;1508const char* prefix;1509jsize prefixLen;1510jboolean isCopy;15111512prefixStr = (jstring) ((*jnienv)->GetObjectArrayElement(jnienv,1513prefixArray, i));1514errorOccurred = checkForThrowable(jnienv);1515jplis_assert(!errorOccurred);1516if (errorOccurred) {1517break;1518}1519if (prefixStr == NULL) {1520continue;1521}15221523prefixLen = (*jnienv)->GetStringUTFLength(jnienv, prefixStr);1524errorOccurred = checkForThrowable(jnienv);1525jplis_assert(!errorOccurred);1526if (errorOccurred) {1527break;1528}15291530if (prefixLen > 0) {1531prefix = (*jnienv)->GetStringUTFChars(jnienv, prefixStr, &isCopy);1532errorOccurred = checkForThrowable(jnienv);1533jplis_assert(!errorOccurred);1534if (!errorOccurred && prefix != NULL) {1535prefixes[inx] = prefix;1536originForRelease[inx] = prefixStr;1537++inx;1538}1539}1540}15411542err = (*jvmtienv)->SetNativeMethodPrefixes(jvmtienv, inx, (char**)prefixes);1543/* can be called from any phase */1544jplis_assert(err == JVMTI_ERROR_NONE);15451546for (i = 0; i < inx; i++) {1547(*jnienv)->ReleaseStringUTFChars(jnienv, originForRelease[i], prefixes[i]);1548}1549}1550deallocate(jvmtienv, (void*)prefixes);1551deallocate(jvmtienv, (void*)originForRelease);1552}1553}155415551556