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