1 /*
   2  * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  * Copyright 2003 Wily Technology, Inc.
  28  */
  29 
  30 #include    <jni.h>
  31 #include    <jvmti.h>
  32 #include    <stdlib.h>
  33 #include    <string.h>
  34 #include    "JPLISAgent.h"
  35 #include    "JPLISAssert.h"
  36 #include    "Utilities.h"
  37 #include    "Reentrancy.h"
  38 #include    "JavaExceptions.h"
  39 
  40 #include    "EncodingSupport.h"
  41 #include    "FileSystemSupport.h"    /* For MAXPATHLEN & uintptr_t */
  42 
  43 #include    "sun_instrument_InstrumentationImpl.h"
  44 
  45 /*
  46  *  The JPLISAgent manages the initialization all of the Java programming language Agents.
  47  *  It also supports the native method bridge between the JPLIS and the JVMTI.
  48  *  It maintains a single JVMTI Env that all JPL agents share.
  49  *  It parses command line requests and creates individual Java agents.
  50  */
  51 
  52 
  53 /*
  54  *  private prototypes
  55  */
  56 
  57 /* Allocates an unformatted JPLIS agent data structure. Returns NULL if allocation fails. */
  58 JPLISAgent *
  59 allocateJPLISAgent(jvmtiEnv *       jvmtiEnv);
  60 
  61 /* Initializes an already-allocated JPLIS agent data structure. */
  62 JPLISInitializationError
  63 initializeJPLISAgent(   JPLISAgent *    agent,
  64                         JavaVM *        vm,
  65                         jvmtiEnv *      jvmtienv);
  66 /* De-allocates a JPLIS agent data structure. Only used in partial-failure cases at startup;
  67  * in normal usage the JPLIS agent lives forever
  68  */
  69 void
  70 deallocateJPLISAgent(   jvmtiEnv *      jvmtienv,
  71                         JPLISAgent *    agent);
  72 
  73 /* Does one-time work to interrogate the JVM about capabilities and cache the answers. */
  74 void
  75 checkCapabilities(JPLISAgent * agent);
  76 
  77 /* Takes the elements of the command string (agent class name and options string) and
  78  * create java strings for them.
  79  * Returns true if a classname was found. Makes no promises beyond the textual; says nothing about whether
  80  * the class exists or can be loaded.
  81  * If return value is true, sets outputClassname to a non-NULL local JNI reference.
  82  * If return value is true, sets outputOptionsString either to NULL or to a non-NULL local JNI reference.
  83  * If return value is false, neither output parameter is set.
  84  */
  85 jboolean
  86 commandStringIntoJavaStrings(  JNIEnv *        jnienv,
  87                                const char *    classname,
  88                                const char *    optionsString,
  89                                jstring *       outputClassname,
  90                                jstring *       outputOptionsString);
  91 
  92 /* Start one Java agent from the supplied parameters.
  93  * Most of the logic lives in a helper function that lives over in Java code--
  94  * we pass parameters out to Java and use our own Java helper to actually
  95  * load the agent and call the premain.
  96  * Returns true if the Java agent class is loaded and the premain/agentmain method completes
  97  * with no exceptions, false otherwise.
  98  */
  99 jboolean
 100 invokeJavaAgentMainMethod( JNIEnv *    jnienv,
 101                            jobject     instrumentationImpl,
 102                            jmethodID   agentMainMethod,
 103                            jstring     className,
 104                            jstring     optionsString);
 105 
 106 /* Once we have loaded the Java agent and called the premain,
 107  * we can release the copies we have been keeping of the command line
 108  * data (agent class name and option strings).
 109  */
 110 void
 111 deallocateCommandLineData(JPLISAgent * agent);
 112 
 113 /*
 114  *  Common support for various class list fetchers.
 115  */
 116 typedef jvmtiError (*ClassListFetcher)
 117     (   jvmtiEnv *  jvmtiEnv,
 118         jobject     classLoader,
 119         jint *      classCount,
 120         jclass **   classes);
 121 
 122 /* Fetcher that ignores the class loader parameter, and uses the JVMTI to get a list of all classes.
 123  * Returns a jvmtiError according to the underlying JVMTI service.
 124  */
 125 jvmtiError
 126 getAllLoadedClassesClassListFetcher(    jvmtiEnv *  jvmtiEnv,
 127                                         jobject     classLoader,
 128                                         jint *      classCount,
 129                                         jclass **   classes);
 130 
 131 /* Fetcher that uses the class loader parameter, and uses the JVMTI to get a list of all classes
 132  * for which the supplied loader is the initiating loader.
 133  * Returns a jvmtiError according to the underlying JVMTI service.
 134  */
 135 jvmtiError
 136 getInitiatedClassesClassListFetcher(    jvmtiEnv *  jvmtiEnv,
 137                                         jobject     classLoader,
 138                                         jint *      classCount,
 139                                         jclass **   classes);
 140 
 141 /*
 142  * Common guts for two native methods, which are the same except for the policy for fetching
 143  * the list of classes.
 144  * Either returns a local JNI reference to an array of references to java.lang.Class.
 145  * Can throw, if it does will alter the JNIEnv with an outstanding exception.
 146  */
 147 jobjectArray
 148 commonGetClassList( JNIEnv *            jnienv,
 149                     JPLISAgent *        agent,
 150                     jobject             classLoader,
 151                     ClassListFetcher    fetcher);
 152 
 153 
 154 /*
 155  *  Misc. utilities.
 156  */
 157 
 158 /* Checked exception mapper used by the redefine classes implementation.
 159  * Allows ClassNotFoundException or UnmodifiableClassException; maps others
 160  * to InternalError. Can return NULL in an error case.
 161  */
 162 jthrowable
 163 redefineClassMapper(    JNIEnv *    jnienv,
 164                         jthrowable  throwableToMap);
 165 
 166 /* Turns a buffer of jclass * into a Java array whose elements are java.lang.Class.
 167  * Can throw, if it does will alter the JNIEnv with an outstanding exception.
 168  */
 169 jobjectArray
 170 getObjectArrayFromClasses(JNIEnv* jnienv, jclass* classes, jint classCount);
 171 
 172 
 173 JPLISEnvironment *
 174 getJPLISEnvironment(jvmtiEnv * jvmtienv) {
 175     JPLISEnvironment * environment  = NULL;
 176     jvmtiError         jvmtierror   = JVMTI_ERROR_NONE;
 177 
 178     jvmtierror = (*jvmtienv)->GetEnvironmentLocalStorage(
 179                                             jvmtienv,
 180                                             (void**)&environment);
 181     /* can be called from any phase */
 182     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 183 
 184     if (jvmtierror == JVMTI_ERROR_NONE) {
 185         jplis_assert(environment != NULL);
 186         jplis_assert(environment->mJVMTIEnv == jvmtienv);
 187     } else {
 188         environment = NULL;
 189     }
 190     return environment;
 191 }
 192 
 193 /*
 194  *  OnLoad processing code.
 195  */
 196 
 197 /*
 198  *  Creates a new JPLISAgent.
 199  *  Returns error if the agent cannot be created and initialized.
 200  *  The JPLISAgent* pointed to by agent_ptr is set to the new broker,
 201  *  or NULL if an error has occurred.
 202  */
 203 JPLISInitializationError
 204 createNewJPLISAgent(JavaVM * vm, JPLISAgent **agent_ptr) {
 205     JPLISInitializationError initerror       = JPLIS_INIT_ERROR_NONE;
 206     jvmtiEnv *               jvmtienv        = NULL;
 207     jint                     jnierror        = JNI_OK;
 208 
 209     *agent_ptr = NULL;
 210     jnierror = (*vm)->GetEnv(  vm,
 211                                (void **) &jvmtienv,
 212                                JVMTI_VERSION_1_1);
 213     if ( jnierror != JNI_OK ) {
 214         initerror = JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT;
 215     } else {
 216         JPLISAgent * agent = allocateJPLISAgent(jvmtienv);
 217         if ( agent == NULL ) {
 218             initerror = JPLIS_INIT_ERROR_ALLOCATION_FAILURE;
 219         } else {
 220             initerror = initializeJPLISAgent(  agent,
 221                                                vm,
 222                                                jvmtienv);
 223             if ( initerror == JPLIS_INIT_ERROR_NONE ) {
 224                 *agent_ptr = agent;
 225             } else {
 226                 deallocateJPLISAgent(jvmtienv, agent);
 227             }
 228         }
 229 
 230         /* don't leak envs */
 231         if ( initerror != JPLIS_INIT_ERROR_NONE ) {
 232             jvmtiError jvmtierror = (*jvmtienv)->DisposeEnvironment(jvmtienv);
 233             /* can be called from any phase */
 234             jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 235         }
 236     }
 237 
 238     return initerror;
 239 }
 240 
 241 /*
 242  *  Allocates a JPLISAgent. Returns NULL if it cannot be allocated
 243  */
 244 JPLISAgent *
 245 allocateJPLISAgent(jvmtiEnv * jvmtienv) {
 246   return (JPLISAgent *) allocate( jvmtienv,
 247                                     sizeof(JPLISAgent));
 248 }
 249 
 250 JPLISInitializationError
 251 initializeJPLISAgent(   JPLISAgent *    agent,
 252                         JavaVM *        vm,
 253                         jvmtiEnv *      jvmtienv) {
 254     jvmtiError      jvmtierror = JVMTI_ERROR_NONE;
 255     jvmtiPhase      phase;
 256 
 257     agent->mJVM                                      = vm;
 258     agent->mNormalEnvironment.mJVMTIEnv              = jvmtienv;
 259     agent->mNormalEnvironment.mAgent                 = agent;
 260     agent->mNormalEnvironment.mIsRetransformer       = JNI_FALSE;
 261     agent->mRetransformEnvironment.mJVMTIEnv         = NULL;        /* NULL until needed */
 262     agent->mRetransformEnvironment.mAgent            = agent;
 263     agent->mRetransformEnvironment.mIsRetransformer  = JNI_FALSE;   /* JNI_FALSE until mJVMTIEnv is set */
 264     agent->mAgentmainCaller                          = NULL;
 265     agent->mInstrumentationImpl                      = NULL;
 266     agent->mPremainCaller                            = NULL;
 267     agent->mTransform                                = NULL;
 268     agent->mRedefineAvailable                        = JNI_FALSE;   /* assume no for now */
 269     agent->mRedefineAdded                            = JNI_FALSE;
 270     agent->mNativeMethodPrefixAvailable              = JNI_FALSE;   /* assume no for now */
 271     agent->mNativeMethodPrefixAdded                  = JNI_FALSE;
 272     agent->mAgentClassName                           = NULL;
 273     agent->mOptionsString                            = NULL;
 274 
 275     /* make sure we can recover either handle in either direction.
 276      * the agent has a ref to the jvmti; make it mutual
 277      */
 278     jvmtierror = (*jvmtienv)->SetEnvironmentLocalStorage(
 279                                             jvmtienv,
 280                                             &(agent->mNormalEnvironment));
 281     /* can be called from any phase */
 282     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 283 
 284     /* check what capabilities are available */
 285     checkCapabilities(agent);
 286 
 287     /* check phase - if live phase then we don't need the VMInit event */
 288     jvmtierror = (*jvmtienv)->GetPhase(jvmtienv, &phase);
 289     /* can be called from any phase */
 290     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 291     if (phase == JVMTI_PHASE_LIVE) {
 292         return JPLIS_INIT_ERROR_NONE;
 293     }
 294 
 295     if (phase != JVMTI_PHASE_ONLOAD) {
 296         /* called too early or called too late; either way bail out */
 297         return JPLIS_INIT_ERROR_FAILURE;
 298     }
 299 
 300     /* now turn on the VMInit event */
 301     if ( jvmtierror == JVMTI_ERROR_NONE ) {
 302         jvmtiEventCallbacks callbacks;
 303         memset(&callbacks, 0, sizeof(callbacks));
 304         callbacks.VMInit = &eventHandlerVMInit;
 305 
 306         jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv,
 307                                                      &callbacks,
 308                                                      sizeof(callbacks));
 309         check_phase_ret_blob(jvmtierror, JPLIS_INIT_ERROR_FAILURE);
 310         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 311     }
 312 
 313     if ( jvmtierror == JVMTI_ERROR_NONE ) {
 314         jvmtierror = (*jvmtienv)->SetEventNotificationMode(
 315                                                 jvmtienv,
 316                                                 JVMTI_ENABLE,
 317                                                 JVMTI_EVENT_VM_INIT,
 318                                                 NULL /* all threads */);
 319         check_phase_ret_blob(jvmtierror, JPLIS_INIT_ERROR_FAILURE);
 320         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 321     }
 322 
 323     return (jvmtierror == JVMTI_ERROR_NONE)? JPLIS_INIT_ERROR_NONE : JPLIS_INIT_ERROR_FAILURE;
 324 }
 325 
 326 void
 327 deallocateJPLISAgent(jvmtiEnv * jvmtienv, JPLISAgent * agent) {
 328     deallocate(jvmtienv, agent);
 329 }
 330 
 331 
 332 JPLISInitializationError
 333 recordCommandLineData(  JPLISAgent *    agent,
 334                         const char *    agentClassName,
 335                         const char *    optionsString ) {
 336     JPLISInitializationError    initerror   = JPLIS_INIT_ERROR_NONE;
 337     char *      ourCopyOfAgentClassName     = NULL;
 338     char *      ourCopyOfOptionsString      = NULL;
 339 
 340     /* if no actual params, bail out now */
 341     if ((agentClassName == NULL) || (*agentClassName == 0)) {
 342         initerror = JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED;
 343     } else {
 344         ourCopyOfAgentClassName = allocate(jvmti(agent), strlen(agentClassName)+1);
 345         if (ourCopyOfAgentClassName == NULL) {
 346             initerror = JPLIS_INIT_ERROR_ALLOCATION_FAILURE;
 347         } else {
 348             if (optionsString != NULL) {
 349                 ourCopyOfOptionsString = allocate(jvmti(agent), strlen(optionsString)+1);
 350                 if (ourCopyOfOptionsString == NULL) {
 351                     deallocate(jvmti(agent), ourCopyOfAgentClassName);
 352                     initerror = JPLIS_INIT_ERROR_ALLOCATION_FAILURE;
 353                 }
 354             }
 355         }
 356     }
 357 
 358     if (initerror == JPLIS_INIT_ERROR_NONE) {
 359         strcpy(ourCopyOfAgentClassName, agentClassName);
 360         if (optionsString != NULL) {
 361             strcpy(ourCopyOfOptionsString, optionsString);
 362         }
 363         agent->mAgentClassName = ourCopyOfAgentClassName;
 364         agent->mOptionsString = ourCopyOfOptionsString;
 365     }
 366 
 367     return initerror;
 368 }
 369 
 370 /*
 371  *  VMInit processing code.
 372  */
 373 
 374 
 375 /*
 376  * If this call fails, the JVM launch will ultimately be aborted,
 377  * so we don't have to be super-careful to clean up in partial failure
 378  * cases.
 379  */
 380 jboolean
 381 processJavaStart(   JPLISAgent *    agent,
 382                     JNIEnv *        jnienv) {
 383     jboolean    result;
 384 
 385     /*
 386      *  OK, Java is up now. We can start everything that needs Java.
 387      */
 388 
 389     /*
 390      *  First make our emergency fallback InternalError throwable.
 391      */
 392     result = initializeFallbackError(jnienv);
 393     jplis_assert(result);
 394 
 395     /*
 396      *  Now make the InstrumentationImpl instance.
 397      */
 398     if ( result ) {
 399         result = createInstrumentationImpl(jnienv, agent);
 400         jplis_assert(result);
 401     }
 402 
 403 
 404     /*
 405      *  Then turn off the VMInit handler and turn on the ClassFileLoadHook.
 406      *  This way it is on before anyone registers a transformer.
 407      */
 408     if ( result ) {
 409         result = setLivePhaseEventHandlers(agent);
 410         jplis_assert(result);
 411     }
 412 
 413     /*
 414      *  Load the Java agent, and call the premain.
 415      */
 416     if ( result ) {
 417         result = startJavaAgent(agent, jnienv,
 418                                 agent->mAgentClassName, agent->mOptionsString,
 419                                 agent->mPremainCaller);
 420     }
 421 
 422     /*
 423      * Finally surrender all of the tracking data that we don't need any more.
 424      * If something is wrong, skip it, we will be aborting the JVM anyway.
 425      */
 426     if ( result ) {
 427         deallocateCommandLineData(agent);
 428     }
 429 
 430     return result;
 431 }
 432 
 433 jboolean
 434 startJavaAgent( JPLISAgent *    agent,
 435                 JNIEnv *        jnienv,
 436                 const char *    classname,
 437                 const char *    optionsString,
 438                 jmethodID       agentMainMethod) {
 439     jboolean    success = JNI_FALSE;
 440     jstring classNameObject = NULL;
 441     jstring optionsStringObject = NULL;
 442 
 443     success = commandStringIntoJavaStrings(    jnienv,
 444                                                classname,
 445                                                optionsString,
 446                                                &classNameObject,
 447                                                &optionsStringObject);
 448 
 449     if (success) {
 450         success = invokeJavaAgentMainMethod(   jnienv,
 451                                                agent->mInstrumentationImpl,
 452                                                agentMainMethod,
 453                                                classNameObject,
 454                                                optionsStringObject);
 455     }
 456 
 457     return success;
 458 }
 459 
 460 void
 461 deallocateCommandLineData( JPLISAgent * agent) {
 462     deallocate(jvmti(agent), (void*)agent->mAgentClassName);
 463     deallocate(jvmti(agent), (void*)agent->mOptionsString);
 464 
 465     /* zero things out so it is easier to see what is going on */
 466     agent->mAgentClassName = NULL;
 467     agent->mOptionsString = NULL;
 468 }
 469 
 470 /*
 471  * Create the java.lang.instrument.Instrumentation instance
 472  * and access information for it (method IDs, etc)
 473  */
 474 jboolean
 475 createInstrumentationImpl( JNIEnv *        jnienv,
 476                            JPLISAgent *    agent) {
 477     jclass      implClass               = NULL;
 478     jboolean    errorOutstanding        = JNI_FALSE;
 479     jobject     resultImpl              = NULL;
 480     jmethodID   premainCallerMethodID   = NULL;
 481     jmethodID   agentmainCallerMethodID = NULL;
 482     jmethodID   transformMethodID       = NULL;
 483     jmethodID   constructorID           = NULL;
 484     jobject     localReference          = NULL;
 485 
 486     /* First find the class of our implementation */
 487     implClass = (*jnienv)->FindClass(   jnienv,
 488                                         JPLIS_INSTRUMENTIMPL_CLASSNAME);
 489     errorOutstanding = checkForAndClearThrowable(jnienv);
 490     errorOutstanding = errorOutstanding || (implClass == NULL);
 491     jplis_assert_msg(!errorOutstanding, "find class on InstrumentationImpl failed");
 492 
 493     if ( !errorOutstanding ) {
 494         constructorID = (*jnienv)->GetMethodID( jnienv,
 495                                                 implClass,
 496                                                 JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODNAME,
 497                                                 JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODSIGNATURE);
 498         errorOutstanding = checkForAndClearThrowable(jnienv);
 499         errorOutstanding = errorOutstanding || (constructorID == NULL);
 500         jplis_assert_msg(!errorOutstanding, "find constructor on InstrumentationImpl failed");
 501         }
 502 
 503     if ( !errorOutstanding ) {
 504         jlong   peerReferenceAsScalar = (jlong)(intptr_t) agent;
 505         localReference = (*jnienv)->NewObject(  jnienv,
 506                                                 implClass,
 507                                                 constructorID,
 508                                                 peerReferenceAsScalar,
 509                                                 agent->mRedefineAdded,
 510                                                 agent->mNativeMethodPrefixAdded);
 511         errorOutstanding = checkForAndClearThrowable(jnienv);
 512         errorOutstanding = errorOutstanding || (localReference == NULL);
 513         jplis_assert_msg(!errorOutstanding, "call constructor on InstrumentationImpl failed");
 514     }
 515 
 516     if ( !errorOutstanding ) {
 517         resultImpl = (*jnienv)->NewGlobalRef(jnienv, localReference);
 518         errorOutstanding = checkForAndClearThrowable(jnienv);
 519         jplis_assert_msg(!errorOutstanding, "copy local ref to global ref");
 520     }
 521 
 522     /* Now look up the method ID for the pre-main caller (we will need this more than once) */
 523     if ( !errorOutstanding ) {
 524         premainCallerMethodID = (*jnienv)->GetMethodID( jnienv,
 525                                                         implClass,
 526                                                         JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODNAME,
 527                                                         JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODSIGNATURE);
 528         errorOutstanding = checkForAndClearThrowable(jnienv);
 529         errorOutstanding = errorOutstanding || (premainCallerMethodID == NULL);
 530         jplis_assert_msg(!errorOutstanding, "can't find premain invoker methodID");
 531     }
 532 
 533     /* Now look up the method ID for the agent-main caller */
 534     if ( !errorOutstanding ) {
 535         agentmainCallerMethodID = (*jnienv)->GetMethodID( jnienv,
 536                                                           implClass,
 537                                                           JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODNAME,
 538                                                           JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODSIGNATURE);
 539         errorOutstanding = checkForAndClearThrowable(jnienv);
 540         errorOutstanding = errorOutstanding || (agentmainCallerMethodID == NULL);
 541         jplis_assert_msg(!errorOutstanding, "can't find agentmain invoker methodID");
 542     }
 543 
 544     /* Now look up the method ID for the transform method (we will need this constantly) */
 545     if ( !errorOutstanding ) {
 546         transformMethodID = (*jnienv)->GetMethodID( jnienv,
 547                                                     implClass,
 548                                                     JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODNAME,
 549                                                     JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODSIGNATURE);
 550         errorOutstanding = checkForAndClearThrowable(jnienv);
 551         errorOutstanding = errorOutstanding || (transformMethodID == NULL);
 552         jplis_assert_msg(!errorOutstanding, "can't find transform methodID");
 553     }
 554 
 555     if ( !errorOutstanding ) {
 556         agent->mInstrumentationImpl = resultImpl;
 557         agent->mPremainCaller       = premainCallerMethodID;
 558         agent->mAgentmainCaller     = agentmainCallerMethodID;
 559         agent->mTransform           = transformMethodID;
 560     }
 561 
 562     return !errorOutstanding;
 563 }
 564 
 565 jboolean
 566 commandStringIntoJavaStrings(  JNIEnv *        jnienv,
 567                                const char *    classname,
 568                                const char *    optionsString,
 569                                jstring *       outputClassname,
 570                                jstring *       outputOptionsString) {
 571     jstring     classnameJavaString     = NULL;
 572     jstring     optionsJavaString       = NULL;
 573     jboolean    errorOutstanding        = JNI_TRUE;
 574 
 575     classnameJavaString = (*jnienv)->NewStringUTF(jnienv, classname);
 576     errorOutstanding = checkForAndClearThrowable(jnienv);
 577     jplis_assert_msg(!errorOutstanding, "can't create class name java string");
 578 
 579     if ( !errorOutstanding ) {
 580         if ( optionsString != NULL) {
 581             optionsJavaString = (*jnienv)->NewStringUTF(jnienv, optionsString);
 582             errorOutstanding = checkForAndClearThrowable(jnienv);
 583             jplis_assert_msg(!errorOutstanding, "can't create options java string");
 584         }
 585 
 586         if ( !errorOutstanding ) {
 587             *outputClassname        = classnameJavaString;
 588             *outputOptionsString    = optionsJavaString;
 589         }
 590     }
 591 
 592     return !errorOutstanding;
 593 }
 594 
 595 
 596 jboolean
 597 invokeJavaAgentMainMethod( JNIEnv *    jnienv,
 598                            jobject     instrumentationImpl,
 599                            jmethodID   mainCallingMethod,
 600                            jstring     className,
 601                            jstring     optionsString) {
 602     jboolean errorOutstanding = JNI_FALSE;
 603 
 604     jplis_assert(mainCallingMethod != NULL);
 605     if ( mainCallingMethod != NULL ) {
 606         (*jnienv)->CallVoidMethod(  jnienv,
 607                                     instrumentationImpl,
 608                                     mainCallingMethod,
 609                                     className,
 610                                     optionsString);
 611         errorOutstanding = checkForThrowable(jnienv);
 612         if ( errorOutstanding ) {
 613             logThrowable(jnienv);
 614         }
 615         checkForAndClearThrowable(jnienv);
 616     }
 617     return !errorOutstanding;
 618 }
 619 
 620 jboolean
 621 setLivePhaseEventHandlers(  JPLISAgent * agent) {
 622     jvmtiEventCallbacks callbacks;
 623     jvmtiEnv *          jvmtienv = jvmti(agent);
 624     jvmtiError          jvmtierror;
 625 
 626     /* first swap out the handlers (switch from the VMInit handler, which we do not need,
 627      * to the ClassFileLoadHook handler, which is what the agents need from now on)
 628      */
 629     memset(&callbacks, 0, sizeof(callbacks));
 630     callbacks.ClassFileLoadHook = &eventHandlerClassFileLoadHook;
 631 
 632     jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv,
 633                                                  &callbacks,
 634                                                  sizeof(callbacks));
 635     check_phase_ret_false(jvmtierror);
 636     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 637 
 638 
 639     if ( jvmtierror == JVMTI_ERROR_NONE ) {
 640         /* turn off VMInit */
 641         jvmtierror = (*jvmtienv)->SetEventNotificationMode(
 642                                                     jvmtienv,
 643                                                     JVMTI_DISABLE,
 644                                                     JVMTI_EVENT_VM_INIT,
 645                                                     NULL /* all threads */);
 646         check_phase_ret_false(jvmtierror);
 647         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 648     }
 649 
 650     if ( jvmtierror == JVMTI_ERROR_NONE ) {
 651         /* turn on ClassFileLoadHook */
 652         jvmtierror = (*jvmtienv)->SetEventNotificationMode(
 653                                                     jvmtienv,
 654                                                     JVMTI_ENABLE,
 655                                                     JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
 656                                                     NULL /* all threads */);
 657         check_phase_ret_false(jvmtierror);
 658         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 659     }
 660 
 661     return (jvmtierror == JVMTI_ERROR_NONE);
 662 }
 663 
 664 /**
 665  *  Check if the can_redefine_classes capability is available.
 666  */
 667 void
 668 checkCapabilities(JPLISAgent * agent) {
 669     jvmtiEnv *          jvmtienv = jvmti(agent);
 670     jvmtiCapabilities   potentialCapabilities;
 671     jvmtiError          jvmtierror;
 672 
 673     memset(&potentialCapabilities, 0, sizeof(potentialCapabilities));
 674 
 675     jvmtierror = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &potentialCapabilities);
 676     check_phase_ret(jvmtierror);
 677     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 678 
 679     if ( jvmtierror == JVMTI_ERROR_NONE ) {
 680         if ( potentialCapabilities.can_redefine_classes == 1 ) {
 681             agent->mRedefineAvailable = JNI_TRUE;
 682         }
 683         if ( potentialCapabilities.can_set_native_method_prefix == 1 ) {
 684             agent->mNativeMethodPrefixAvailable = JNI_TRUE;
 685         }
 686     }
 687 }
 688 
 689 /**
 690  * Enable native method prefix in one JVM TI environment
 691  */
 692 void
 693 enableNativeMethodPrefixCapability(jvmtiEnv * jvmtienv) {
 694     jvmtiCapabilities   desiredCapabilities;
 695     jvmtiError          jvmtierror;
 696 
 697         jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);
 698         /* can be called from any phase */
 699         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 700         desiredCapabilities.can_set_native_method_prefix = 1;
 701         jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);
 702         check_phase_ret(jvmtierror);
 703         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 704 }
 705 
 706 
 707 /**
 708  * Add the can_set_native_method_prefix capability
 709  */
 710 void
 711 addNativeMethodPrefixCapability(JPLISAgent * agent) {
 712     if (agent->mNativeMethodPrefixAvailable && !agent->mNativeMethodPrefixAdded) {
 713         jvmtiEnv * jvmtienv = agent->mNormalEnvironment.mJVMTIEnv;
 714         enableNativeMethodPrefixCapability(jvmtienv);
 715 
 716         jvmtienv = agent->mRetransformEnvironment.mJVMTIEnv;
 717         if (jvmtienv != NULL) {
 718             enableNativeMethodPrefixCapability(jvmtienv);
 719         }
 720         agent->mNativeMethodPrefixAdded = JNI_TRUE;
 721     }
 722 }
 723 
 724 /**
 725  * Add the can_maintain_original_method_order capability (for testing)
 726  */
 727 void
 728 addOriginalMethodOrderCapability(JPLISAgent * agent) {
 729     jvmtiEnv *          jvmtienv = jvmti(agent);
 730     jvmtiCapabilities   desiredCapabilities;
 731     jvmtiError          jvmtierror;
 732 
 733     jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);
 734     /* can be called from any phase */
 735     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 736     desiredCapabilities.can_maintain_original_method_order = 1;
 737     jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);
 738     check_phase_ret(jvmtierror);
 739     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 740 }
 741 
 742 /**
 743  * Add the can_redefine_classes capability
 744  */
 745 void
 746 addRedefineClassesCapability(JPLISAgent * agent) {
 747     jvmtiEnv *          jvmtienv = jvmti(agent);
 748     jvmtiCapabilities   desiredCapabilities;
 749     jvmtiError          jvmtierror;
 750 
 751     if (agent->mRedefineAvailable && !agent->mRedefineAdded) {
 752         jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);
 753         /* can be called from any phase */
 754         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 755         desiredCapabilities.can_redefine_classes = 1;
 756         jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);
 757         check_phase_ret(jvmtierror);
 758 
 759         /*
 760          * With mixed premain/agentmain agents then it's possible that the
 761          * capability was potentially available in the onload phase but
 762          * subsequently unavailable in the live phase.
 763          */
 764         jplis_assert(jvmtierror == JVMTI_ERROR_NONE ||
 765                      jvmtierror == JVMTI_ERROR_NOT_AVAILABLE);
 766         if (jvmtierror == JVMTI_ERROR_NONE) {
 767             agent->mRedefineAdded = JNI_TRUE;
 768         }
 769     }
 770 }
 771 
 772 
 773 /*
 774  *  Support for the JVMTI callbacks
 775  */
 776 
 777 void
 778 transformClassFile(             JPLISAgent *            agent,
 779                                 JNIEnv *                jnienv,
 780                                 jobject                 loaderObject,
 781                                 const char*             name,
 782                                 jclass                  classBeingRedefined,
 783                                 jobject                 protectionDomain,
 784                                 jint                    class_data_len,
 785                                 const unsigned char*    class_data,
 786                                 jint*                   new_class_data_len,
 787                                 unsigned char**         new_class_data,
 788                                 jboolean                is_retransformer) {
 789     jboolean        errorOutstanding        = JNI_FALSE;
 790     jstring         classNameStringObject   = NULL;
 791     jarray          classFileBufferObject   = NULL;
 792     jarray          transformedBufferObject = NULL;
 793     jsize           transformedBufferSize   = 0;
 794     unsigned char * resultBuffer            = NULL;
 795     jboolean        shouldRun               = JNI_FALSE;
 796 
 797     /* only do this if we aren't already in the middle of processing a class on this thread */
 798     shouldRun = tryToAcquireReentrancyToken(
 799                                 jvmti(agent),
 800                                 NULL);  /* this thread */
 801 
 802     if ( shouldRun ) {
 803         /* first marshall all the parameters */
 804         classNameStringObject = (*jnienv)->NewStringUTF(jnienv,
 805                                                         name);
 806         errorOutstanding = checkForAndClearThrowable(jnienv);
 807         jplis_assert_msg(!errorOutstanding, "can't create name string");
 808 
 809         if ( !errorOutstanding ) {
 810             classFileBufferObject = (*jnienv)->NewByteArray(jnienv,
 811                                                             class_data_len);
 812             errorOutstanding = checkForAndClearThrowable(jnienv);
 813             jplis_assert_msg(!errorOutstanding, "can't create byte arrau");
 814         }
 815 
 816         if ( !errorOutstanding ) {
 817             jbyte * typedBuffer = (jbyte *) class_data; /* nasty cast, dumb JNI interface, const missing */
 818                                                         /* The sign cast is safe. The const cast is dumb. */
 819             (*jnienv)->SetByteArrayRegion(  jnienv,
 820                                             classFileBufferObject,
 821                                             0,
 822                                             class_data_len,
 823                                             typedBuffer);
 824             errorOutstanding = checkForAndClearThrowable(jnienv);
 825             jplis_assert_msg(!errorOutstanding, "can't set byte array region");
 826         }
 827 
 828         /*  now call the JPL agents to do the transforming */
 829         /*  potential future optimization: may want to skip this if there are none */
 830         if ( !errorOutstanding ) {
 831             jplis_assert(agent->mInstrumentationImpl != NULL);
 832             jplis_assert(agent->mTransform != NULL);
 833             transformedBufferObject = (*jnienv)->CallObjectMethod(
 834                                                 jnienv,
 835                                                 agent->mInstrumentationImpl,
 836                                                 agent->mTransform,
 837                                                 loaderObject,
 838                                                 classNameStringObject,
 839                                                 classBeingRedefined,
 840                                                 protectionDomain,
 841                                                 classFileBufferObject,
 842                                                 is_retransformer);
 843             errorOutstanding = checkForAndClearThrowable(jnienv);
 844             jplis_assert_msg(!errorOutstanding, "transform method call failed");
 845         }
 846 
 847         /* Finally, unmarshall the parameters (if someone touched the buffer, tell the JVM) */
 848         if ( !errorOutstanding ) {
 849             if ( transformedBufferObject != NULL ) {
 850                 transformedBufferSize = (*jnienv)->GetArrayLength(  jnienv,
 851                                                                     transformedBufferObject);
 852                 errorOutstanding = checkForAndClearThrowable(jnienv);
 853                 jplis_assert_msg(!errorOutstanding, "can't get array length");
 854 
 855                 if ( !errorOutstanding ) {
 856                     /* allocate the response buffer with the JVMTI allocate call.
 857                      *  This is what the JVMTI spec says to do for Class File Load hook responses
 858                      */
 859                     jvmtiError  allocError = (*(jvmti(agent)))->Allocate(jvmti(agent),
 860                                                                              transformedBufferSize,
 861                                                                              &resultBuffer);
 862                     errorOutstanding = (allocError != JVMTI_ERROR_NONE);
 863                     jplis_assert_msg(!errorOutstanding, "can't allocate result buffer");
 864                 }
 865 
 866                 if ( !errorOutstanding ) {
 867                     (*jnienv)->GetByteArrayRegion(  jnienv,
 868                                                     transformedBufferObject,
 869                                                     0,
 870                                                     transformedBufferSize,
 871                                                     (jbyte *) resultBuffer);
 872                     errorOutstanding = checkForAndClearThrowable(jnienv);
 873                     jplis_assert_msg(!errorOutstanding, "can't get byte array region");
 874 
 875                     /* in this case, we will not return the buffer to the JVMTI,
 876                      * so we need to deallocate it ourselves
 877                      */
 878                     if ( errorOutstanding ) {
 879                         deallocate( jvmti(agent),
 880                                    (void*)resultBuffer);
 881                     }
 882                 }
 883 
 884                 if ( !errorOutstanding ) {
 885                     *new_class_data_len = (transformedBufferSize);
 886                     *new_class_data     = resultBuffer;
 887                 }
 888             }
 889         }
 890 
 891         /* release the token */
 892         releaseReentrancyToken( jvmti(agent),
 893                                 NULL);      /* this thread */
 894 
 895     }
 896 
 897     return;
 898 }
 899 
 900 /*
 901  *  Misc. internal utilities.
 902  */
 903 
 904 /*
 905  *  The only checked exceptions we can throw are ClassNotFoundException and
 906  *  UnmodifiableClassException. All others map to InternalError.
 907  */
 908 jthrowable
 909 redefineClassMapper(    JNIEnv *    jnienv,
 910                         jthrowable  throwableToMap) {
 911     jthrowable  mappedThrowable = NULL;
 912 
 913     jplis_assert(isSafeForJNICalls(jnienv));
 914     jplis_assert(!isUnchecked(jnienv, throwableToMap));
 915 
 916     if ( isInstanceofClassName( jnienv,
 917                                 throwableToMap,
 918                                 "java/lang/ClassNotFoundException") ) {
 919         mappedThrowable = throwableToMap;
 920     } else {
 921         if ( isInstanceofClassName( jnienv,
 922                                 throwableToMap,
 923                                 "java/lang/instrument/UnmodifiableClassException")) {
 924             mappedThrowable = throwableToMap;
 925         } else {
 926             jstring message = NULL;
 927 
 928             message = getMessageFromThrowable(jnienv, throwableToMap);
 929             mappedThrowable = createInternalError(jnienv, message);
 930         }
 931     }
 932 
 933     jplis_assert(isSafeForJNICalls(jnienv));
 934     return mappedThrowable;
 935 }
 936 
 937 jobjectArray
 938 getObjectArrayFromClasses(JNIEnv* jnienv, jclass* classes, jint classCount) {
 939     jclass          classArrayClass = NULL;
 940     jobjectArray    localArray      = NULL;
 941     jint            classIndex      = 0;
 942     jboolean        errorOccurred   = JNI_FALSE;
 943 
 944     /* get the class array class */
 945     classArrayClass = (*jnienv)->FindClass(jnienv, "java/lang/Class");
 946     errorOccurred = checkForThrowable(jnienv);
 947 
 948     if (!errorOccurred) {
 949         jplis_assert_msg(classArrayClass != NULL, "FindClass returned null class");
 950 
 951         /* create the array for the classes */
 952         localArray = (*jnienv)->NewObjectArray(jnienv, classCount, classArrayClass, NULL);
 953         errorOccurred = checkForThrowable(jnienv);
 954 
 955         if (!errorOccurred) {
 956             jplis_assert_msg(localArray != NULL, "NewObjectArray returned null array");
 957 
 958             /* now copy refs to all the classes and put them into the array */
 959             for (classIndex = 0; classIndex < classCount; classIndex++) {
 960                 /* put class into array */
 961                 (*jnienv)->SetObjectArrayElement(jnienv, localArray, classIndex, classes[classIndex]);
 962                 errorOccurred = checkForThrowable(jnienv);
 963 
 964                 if (errorOccurred) {
 965                     localArray = NULL;
 966                     break;
 967                 }
 968             }
 969         }
 970     }
 971 
 972     return localArray;
 973 }
 974 
 975 
 976 /* Return the environment with the retransformation capability.
 977  * Create it if it doesn't exist.
 978  * Return NULL if it can't be created.
 979  */
 980 jvmtiEnv *
 981 retransformableEnvironment(JPLISAgent * agent) {
 982     jvmtiEnv *          retransformerEnv     = NULL;
 983     jint                jnierror             = JNI_OK;
 984     jvmtiCapabilities   desiredCapabilities;
 985     jvmtiEventCallbacks callbacks;
 986     jvmtiError          jvmtierror;
 987 
 988     if (agent->mRetransformEnvironment.mJVMTIEnv != NULL) {
 989         return agent->mRetransformEnvironment.mJVMTIEnv;
 990     }
 991     jnierror = (*agent->mJVM)->GetEnv(  agent->mJVM,
 992                                (void **) &retransformerEnv,
 993                                JVMTI_VERSION_1_1);
 994     if ( jnierror != JNI_OK ) {
 995         return NULL;
 996     }
 997     jvmtierror = (*retransformerEnv)->GetCapabilities(retransformerEnv, &desiredCapabilities);
 998     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
 999     desiredCapabilities.can_retransform_classes = 1;
1000     if (agent->mNativeMethodPrefixAdded) {
1001         desiredCapabilities.can_set_native_method_prefix = 1;
1002     }
1003 
1004     jvmtierror = (*retransformerEnv)->AddCapabilities(retransformerEnv, &desiredCapabilities);
1005     if (jvmtierror != JVMTI_ERROR_NONE) {
1006          /* cannot get the capability, dispose of the retransforming environment */
1007         jvmtierror = (*retransformerEnv)->DisposeEnvironment(retransformerEnv);
1008         jplis_assert(jvmtierror == JVMTI_ERROR_NOT_AVAILABLE);
1009         return NULL;
1010     }
1011     memset(&callbacks, 0, sizeof(callbacks));
1012     callbacks.ClassFileLoadHook = &eventHandlerClassFileLoadHook;
1013 
1014     jvmtierror = (*retransformerEnv)->SetEventCallbacks(retransformerEnv,
1015                                                         &callbacks,
1016                                                         sizeof(callbacks));
1017     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1018     if (jvmtierror == JVMTI_ERROR_NONE) {
1019         // install the retransforming environment
1020         agent->mRetransformEnvironment.mJVMTIEnv = retransformerEnv;
1021         agent->mRetransformEnvironment.mIsRetransformer = JNI_TRUE;
1022 
1023         // Make it for ClassFileLoadHook handling
1024         jvmtierror = (*retransformerEnv)->SetEnvironmentLocalStorage(
1025                                                        retransformerEnv,
1026                                                        &(agent->mRetransformEnvironment));
1027         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1028         if (jvmtierror == JVMTI_ERROR_NONE) {
1029             return retransformerEnv;
1030         }
1031     }
1032     return NULL;
1033 }
1034 
1035 
1036 /*
1037  *  Underpinnings for native methods
1038  */
1039 
1040 jboolean
1041 isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz) {
1042     jvmtiEnv *          jvmtienv = jvmti(agent);
1043     jvmtiError          jvmtierror;
1044     jboolean            is_modifiable = JNI_FALSE;
1045 
1046     jvmtierror = (*jvmtienv)->IsModifiableClass( jvmtienv,
1047                                                  clazz,
1048                                                  &is_modifiable);
1049     check_phase_ret_false(jvmtierror);
1050     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1051 
1052     return is_modifiable;
1053 }
1054 
1055 jboolean
1056 isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent) {
1057     return agent->mRetransformEnvironment.mIsRetransformer;
1058 }
1059 
1060 void
1061 setHasRetransformableTransformers(JNIEnv * jnienv, JPLISAgent * agent, jboolean has) {
1062     jvmtiEnv *          retransformerEnv     = retransformableEnvironment(agent);
1063     jvmtiError          jvmtierror;
1064 
1065     jplis_assert(retransformerEnv != NULL);
1066     jvmtierror = (*retransformerEnv)->SetEventNotificationMode(
1067                                                     retransformerEnv,
1068                                                     has? JVMTI_ENABLE : JVMTI_DISABLE,
1069                                                     JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
1070                                                     NULL /* all threads */);
1071     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1072 }
1073 
1074 void
1075 retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes) {
1076     jvmtiEnv *  retransformerEnv     = retransformableEnvironment(agent);
1077     jboolean    errorOccurred        = JNI_FALSE;
1078     jvmtiError  errorCode            = JVMTI_ERROR_NONE;
1079     jsize       numClasses           = 0;
1080     jclass *    classArray           = NULL;
1081 
1082     /* This is supposed to be checked by caller, but just to be sure */
1083     if (retransformerEnv == NULL) {
1084         jplis_assert(retransformerEnv != NULL);
1085         errorOccurred = JNI_TRUE;
1086         errorCode = JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
1087     }
1088 
1089     /* This was supposed to be checked by caller too */
1090     if (!errorOccurred && classes == NULL) {
1091         jplis_assert(classes != NULL);
1092         errorOccurred = JNI_TRUE;
1093         errorCode = JVMTI_ERROR_NULL_POINTER;
1094     }
1095 
1096     if (!errorOccurred) {
1097         numClasses = (*jnienv)->GetArrayLength(jnienv, classes);
1098         errorOccurred = checkForThrowable(jnienv);
1099         jplis_assert(!errorOccurred);
1100 
1101         if (!errorOccurred && numClasses == 0) {
1102             jplis_assert(numClasses != 0);
1103             errorOccurred = JNI_TRUE;
1104             errorCode = JVMTI_ERROR_NULL_POINTER;
1105         }
1106     }
1107 
1108     if (!errorOccurred) {
1109         classArray = (jclass *) allocate(retransformerEnv,
1110                                          numClasses * sizeof(jclass));
1111         errorOccurred = (classArray == NULL);
1112         jplis_assert(!errorOccurred);
1113         if (errorOccurred) {
1114             errorCode = JVMTI_ERROR_OUT_OF_MEMORY;
1115         }
1116     }
1117 
1118     if (!errorOccurred) {
1119         jint index;
1120         for (index = 0; index < numClasses; index++) {
1121             classArray[index] = (*jnienv)->GetObjectArrayElement(jnienv, classes, index);
1122             errorOccurred = checkForThrowable(jnienv);
1123             jplis_assert(!errorOccurred);
1124             if (errorOccurred) {
1125                 break;
1126             }
1127 
1128             if (classArray[index] == NULL) {
1129                 jplis_assert(classArray[index] != NULL);
1130                 errorOccurred = JNI_TRUE;
1131                 errorCode = JVMTI_ERROR_NULL_POINTER;
1132                 break;
1133             }
1134         }
1135     }
1136 
1137     if (!errorOccurred) {
1138         errorCode = (*retransformerEnv)->RetransformClasses(retransformerEnv,
1139                                                             numClasses, classArray);
1140         errorOccurred = (errorCode != JVMTI_ERROR_NONE);
1141     }
1142 
1143     /* Give back the buffer if we allocated it.  Throw any exceptions after.
1144      */
1145     if (classArray != NULL) {
1146         deallocate(retransformerEnv, (void*)classArray);
1147     }
1148 
1149     if (errorCode != JVMTI_ERROR_NONE) {
1150         createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode);
1151     }
1152 
1153     mapThrownThrowableIfNecessary(jnienv, redefineClassMapper);
1154 }
1155 
1156 /*
1157  *  Java code must not call this with a null list or a zero-length list.
1158  */
1159 void
1160 redefineClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classDefinitions) {
1161     jvmtiEnv*   jvmtienv                        = jvmti(agent);
1162     jboolean    errorOccurred                   = JNI_FALSE;
1163     jclass      classDefClass                   = NULL;
1164     jmethodID   getDefinitionClassMethodID      = NULL;
1165     jmethodID   getDefinitionClassFileMethodID  = NULL;
1166     jvmtiClassDefinition* classDefs             = NULL;
1167     jsize       numDefs                         = 0;
1168 
1169     jplis_assert(classDefinitions != NULL);
1170 
1171     numDefs = (*jnienv)->GetArrayLength(jnienv, classDefinitions);
1172     errorOccurred = checkForThrowable(jnienv);
1173     jplis_assert(!errorOccurred);
1174 
1175     if (!errorOccurred) {
1176         jplis_assert(numDefs > 0);
1177         /* get method IDs for methods to call on class definitions */
1178         classDefClass = (*jnienv)->FindClass(jnienv, "java/lang/instrument/ClassDefinition");
1179         errorOccurred = checkForThrowable(jnienv);
1180         jplis_assert(!errorOccurred);
1181     }
1182 
1183     if (!errorOccurred) {
1184         getDefinitionClassMethodID = (*jnienv)->GetMethodID(    jnienv,
1185                                                 classDefClass,
1186                                                 "getDefinitionClass",
1187                                                 "()Ljava/lang/Class;");
1188         errorOccurred = checkForThrowable(jnienv);
1189         jplis_assert(!errorOccurred);
1190     }
1191 
1192     if (!errorOccurred) {
1193         getDefinitionClassFileMethodID = (*jnienv)->GetMethodID(    jnienv,
1194                                                     classDefClass,
1195                                                     "getDefinitionClassFile",
1196                                                     "()[B");
1197         errorOccurred = checkForThrowable(jnienv);
1198         jplis_assert(!errorOccurred);
1199     }
1200 
1201     if (!errorOccurred) {
1202         classDefs = (jvmtiClassDefinition *) allocate(
1203                                                 jvmtienv,
1204                                                 numDefs * sizeof(jvmtiClassDefinition));
1205         errorOccurred = (classDefs == NULL);
1206         jplis_assert(!errorOccurred);
1207         if ( errorOccurred ) {
1208             createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY);
1209         }
1210         else {
1211             jint i;
1212             for (i = 0; i < numDefs; i++) {
1213                 jclass      classDef    = NULL;
1214                 jbyteArray  targetFile  = NULL;
1215 
1216                 classDef = (*jnienv)->GetObjectArrayElement(jnienv, classDefinitions, i);
1217                 errorOccurred = checkForThrowable(jnienv);
1218                 jplis_assert(!errorOccurred);
1219                 if (errorOccurred) {
1220                     break;
1221                 }
1222 
1223                 classDefs[i].klass = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassMethodID);
1224                 errorOccurred = checkForThrowable(jnienv);
1225                 jplis_assert(!errorOccurred);
1226                 if (errorOccurred) {
1227                     break;
1228                 }
1229 
1230                 targetFile = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassFileMethodID);
1231                 errorOccurred = checkForThrowable(jnienv);
1232                 jplis_assert(!errorOccurred);
1233                 if (errorOccurred) {
1234                     break;
1235                 }
1236 
1237                 classDefs[i].class_bytes = (unsigned char*)(*jnienv)->GetByteArrayElements(jnienv, targetFile, NULL);
1238                 errorOccurred = checkForThrowable(jnienv);
1239                 jplis_assert(!errorOccurred);
1240                 if (errorOccurred) {
1241                     break;
1242                 }
1243 
1244                 classDefs[i].class_byte_count = (*jnienv)->GetArrayLength(jnienv, targetFile);
1245                 errorOccurred = checkForThrowable(jnienv);
1246                 jplis_assert(!errorOccurred);
1247                 if (errorOccurred) {
1248                     break;
1249                 }
1250             }
1251 
1252             if (!errorOccurred) {
1253                 jvmtiError  errorCode = JVMTI_ERROR_NONE;
1254                 errorCode = (*jvmtienv)->RedefineClasses(jvmtienv, numDefs, classDefs);
1255                 check_phase_blob_ret(errorCode, deallocate(jvmtienv, (void*)classDefs));
1256                 errorOccurred = (errorCode != JVMTI_ERROR_NONE);
1257                 if ( errorOccurred ) {
1258                     createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode);
1259                 }
1260             }
1261 
1262             /* Give back the buffer if we allocated it.
1263              */
1264             deallocate(jvmtienv, (void*)classDefs);
1265         }
1266     }
1267 
1268     mapThrownThrowableIfNecessary(jnienv, redefineClassMapper);
1269 }
1270 
1271 /* Cheesy sharing. ClassLoader may be null. */
1272 jobjectArray
1273 commonGetClassList( JNIEnv *            jnienv,
1274                     JPLISAgent *        agent,
1275                     jobject             classLoader,
1276                     ClassListFetcher    fetcher) {
1277     jvmtiEnv *      jvmtienv        = jvmti(agent);
1278     jboolean        errorOccurred   = JNI_FALSE;
1279     jvmtiError      jvmtierror      = JVMTI_ERROR_NONE;
1280     jint            classCount      = 0;
1281     jclass *        classes         = NULL;
1282     jobjectArray    localArray      = NULL;
1283 
1284     /* retrieve the classes from the JVMTI agent */
1285     jvmtierror = (*fetcher)( jvmtienv,
1286                         classLoader,
1287                         &classCount,
1288                         &classes);
1289     check_phase_ret_blob(jvmtierror, localArray);
1290     errorOccurred = (jvmtierror != JVMTI_ERROR_NONE);
1291     jplis_assert(!errorOccurred);
1292 
1293     if ( errorOccurred ) {
1294         createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);
1295     } else {
1296         localArray = getObjectArrayFromClasses( jnienv,
1297                                                 classes,
1298                                                 classCount);
1299         errorOccurred = checkForThrowable(jnienv);
1300         jplis_assert(!errorOccurred);
1301 
1302         /* do this whether or not we saw a problem */
1303         deallocate(jvmtienv, (void*)classes);
1304     }
1305 
1306     mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper);
1307     return localArray;
1308 
1309 }
1310 
1311 jvmtiError
1312 getAllLoadedClassesClassListFetcher(    jvmtiEnv *  jvmtienv,
1313                                         jobject     classLoader,
1314                                         jint *      classCount,
1315                                         jclass **   classes) {
1316     return (*jvmtienv)->GetLoadedClasses(jvmtienv, classCount, classes);
1317 }
1318 
1319 jobjectArray
1320 getAllLoadedClasses(JNIEnv * jnienv, JPLISAgent * agent) {
1321     return commonGetClassList(  jnienv,
1322                                 agent,
1323                                 NULL,
1324                                 getAllLoadedClassesClassListFetcher);
1325 }
1326 
1327 jvmtiError
1328 getInitiatedClassesClassListFetcher(    jvmtiEnv *  jvmtienv,
1329                                         jobject     classLoader,
1330                                         jint *      classCount,
1331                                         jclass **   classes) {
1332     return (*jvmtienv)->GetClassLoaderClasses(jvmtienv, classLoader, classCount, classes);
1333 }
1334 
1335 
1336 jobjectArray
1337 getInitiatedClasses(JNIEnv * jnienv, JPLISAgent * agent, jobject classLoader) {
1338     return commonGetClassList(  jnienv,
1339                                 agent,
1340                                 classLoader,
1341                                 getInitiatedClassesClassListFetcher);
1342 }
1343 
1344 jlong
1345 getObjectSize(JNIEnv * jnienv, JPLISAgent * agent, jobject objectToSize) {
1346     jvmtiEnv *  jvmtienv    = jvmti(agent);
1347     jlong       objectSize  = -1;
1348     jvmtiError  jvmtierror  = JVMTI_ERROR_NONE;
1349 
1350     jvmtierror = (*jvmtienv)->GetObjectSize(jvmtienv, objectToSize, &objectSize);
1351     check_phase_ret_0(jvmtierror);
1352     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1353     if ( jvmtierror != JVMTI_ERROR_NONE ) {
1354         createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);
1355     }
1356 
1357     mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper);
1358     return objectSize;
1359 }
1360 
1361 void
1362 appendToClassLoaderSearch(JNIEnv * jnienv, JPLISAgent * agent, jstring jarFile, jboolean isBootLoader)
1363 {
1364     jvmtiEnv *  jvmtienv    = jvmti(agent);
1365     jboolean    errorOutstanding;
1366     jvmtiError  jvmtierror;
1367     const char* utf8Chars;
1368     jsize       utf8Len;
1369     jboolean    isCopy;
1370     char        platformChars[MAXPATHLEN];
1371     int         platformLen;
1372 
1373     utf8Len = (*jnienv)->GetStringUTFLength(jnienv, jarFile);
1374     errorOutstanding = checkForAndClearThrowable(jnienv);
1375 
1376     if (!errorOutstanding) {
1377         utf8Chars = (*jnienv)->GetStringUTFChars(jnienv, jarFile, &isCopy);
1378         errorOutstanding = checkForAndClearThrowable(jnienv);
1379 
1380         if (!errorOutstanding && utf8Chars != NULL) {
1381             /*
1382              * JVMTI spec'ed to use modified UTF8. At this time this is not implemented
1383              * the platform encoding is used.
1384              */
1385             platformLen = convertUft8ToPlatformString((char*)utf8Chars, utf8Len, platformChars, MAXPATHLEN);
1386             if (platformLen < 0) {
1387                 createAndThrowInternalError(jnienv);
1388                 return;
1389             }
1390 
1391             (*jnienv)->ReleaseStringUTFChars(jnienv, jarFile, utf8Chars);
1392             errorOutstanding = checkForAndClearThrowable(jnienv);
1393 
1394             if (!errorOutstanding) {
1395 
1396                 if (isBootLoader) {
1397                     jvmtierror = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, platformChars);
1398                 } else {
1399                     jvmtierror = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, platformChars);
1400                 }
1401                 check_phase_ret(jvmtierror);
1402 
1403                 if ( jvmtierror != JVMTI_ERROR_NONE ) {
1404                     createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);
1405                 }
1406             }
1407         }
1408     }
1409 
1410     mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper);
1411 }
1412 
1413 /*
1414  *  Set the prefixes used to wrap native methods (so they can be instrumented).
1415  *  Each transform can set a prefix, any that have been set come in as prefixArray.
1416  *  Convert them in native strings in a native array then call JVM TI.
1417  *  One a given call, this function handles either the prefixes for retransformable
1418  *  transforms or for normal transforms.
1419  */
1420 void
1421 setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefixArray,
1422                         jboolean isRetransformable) {
1423     jvmtiEnv*   jvmtienv;
1424     jvmtiError  err                             = JVMTI_ERROR_NONE;
1425     jsize       arraySize;
1426     jboolean    errorOccurred                   = JNI_FALSE;
1427 
1428     jplis_assert(prefixArray != NULL);
1429 
1430     if (isRetransformable) {
1431         jvmtienv = agent->mRetransformEnvironment.mJVMTIEnv;
1432     } else {
1433         jvmtienv = agent->mNormalEnvironment.mJVMTIEnv;
1434     }
1435     arraySize = (*jnienv)->GetArrayLength(jnienv, prefixArray);
1436     errorOccurred = checkForThrowable(jnienv);
1437     jplis_assert(!errorOccurred);
1438 
1439     if (!errorOccurred) {
1440         /* allocate the native to hold the native prefixes */
1441         const char** prefixes = (const char**) allocate(jvmtienv,
1442                                                         arraySize * sizeof(char*));
1443         /* since JNI ReleaseStringUTFChars needs the jstring from which the native
1444          * string was allocated, we store them in a parallel array */
1445         jstring* originForRelease = (jstring*) allocate(jvmtienv,
1446                                                         arraySize * sizeof(jstring));
1447         errorOccurred = (prefixes == NULL || originForRelease == NULL);
1448         jplis_assert(!errorOccurred);
1449         if ( errorOccurred ) {
1450             createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY);
1451         }
1452         else {
1453             jint inx = 0;
1454             jint i;
1455             for (i = 0; i < arraySize; i++) {
1456                 jstring      prefixStr  = NULL;
1457                 const char*  prefix;
1458                 jsize        prefixLen;
1459                 jboolean     isCopy;
1460 
1461                 prefixStr = (jstring) ((*jnienv)->GetObjectArrayElement(jnienv,
1462                                                                         prefixArray, i));
1463                 errorOccurred = checkForThrowable(jnienv);
1464                 jplis_assert(!errorOccurred);
1465                 if (errorOccurred) {
1466                     break;
1467                 }
1468                 if (prefixStr == NULL) {
1469                     continue;
1470                 }
1471 
1472                 prefixLen = (*jnienv)->GetStringUTFLength(jnienv, prefixStr);
1473                 errorOccurred = checkForThrowable(jnienv);
1474                 jplis_assert(!errorOccurred);
1475                 if (errorOccurred) {
1476                     break;
1477                 }
1478 
1479                 if (prefixLen > 0) {
1480                     prefix = (*jnienv)->GetStringUTFChars(jnienv, prefixStr, &isCopy);
1481                     errorOccurred = checkForThrowable(jnienv);
1482                     jplis_assert(!errorOccurred);
1483                     if (!errorOccurred && prefix != NULL) {
1484                         prefixes[inx] = prefix;
1485                         originForRelease[inx] = prefixStr;
1486                         ++inx;
1487                     }
1488                 }
1489             }
1490 
1491             err = (*jvmtienv)->SetNativeMethodPrefixes(jvmtienv, inx, (char**)prefixes);
1492             /* can be called from any phase */
1493             jplis_assert(err == JVMTI_ERROR_NONE);
1494 
1495             for (i = 0; i < inx; i++) {
1496               (*jnienv)->ReleaseStringUTFChars(jnienv, originForRelease[i], prefixes[i]);
1497             }
1498         }
1499         deallocate(jvmtienv, (void*)prefixes);
1500         deallocate(jvmtienv, (void*)originForRelease);
1501     }
1502 }