1 /*
2  * Copyright (c) 2003, 2019, 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. */
59 JPLISAgent *
60 allocateJPLISAgent(jvmtiEnv *       jvmtiEnv);
61 
62 /* Initializes an already-allocated JPLIS agent data structure. */
63 JPLISInitializationError
64 initializeJPLISAgent(   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  */
70 void
71 deallocateJPLISAgent(   jvmtiEnv *      jvmtienv,
72                         JPLISAgent *    agent);
73 
74 /* Does one-time work to interrogate the JVM about capabilities and cache the answers. */
75 void
76 checkCapabilities(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  */
86 jboolean
87 commandStringIntoJavaStrings(  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  */
100 jboolean
101 invokeJavaAgentMainMethod( 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  */
111 void
112 deallocateCommandLineData(JPLISAgent * agent);
113 
114 /*
115  *  Common support for various class list fetchers.
116  */
117 typedef 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  */
126 jvmtiError
127 getAllLoadedClassesClassListFetcher(    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  */
136 jvmtiError
137 getInitiatedClassesClassListFetcher(    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  */
148 jobjectArray
149 commonGetClassList( 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  */
163 jthrowable
164 redefineClassMapper(    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  */
170 jobjectArray
171 getObjectArrayFromClasses(JNIEnv* jnienv, jclass* classes, jint classCount);
172 
173 
174 JPLISEnvironment *
getJPLISEnvironment(jvmtiEnv * jvmtienv)175 getJPLISEnvironment(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  */
204 JPLISInitializationError
createNewJPLISAgent(JavaVM * vm,JPLISAgent ** agent_ptr)205 createNewJPLISAgent(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  */
245 JPLISAgent *
allocateJPLISAgent(jvmtiEnv * jvmtienv)246 allocateJPLISAgent(jvmtiEnv * jvmtienv) {
247   return (JPLISAgent *) allocate( jvmtienv,
248                                     sizeof(JPLISAgent));
249 }
250 
251 JPLISInitializationError
initializeJPLISAgent(JPLISAgent * agent,JavaVM * vm,jvmtiEnv * jvmtienv)252 initializeJPLISAgent(   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 
328 void
deallocateJPLISAgent(jvmtiEnv * jvmtienv,JPLISAgent * agent)329 deallocateJPLISAgent(jvmtiEnv * jvmtienv, JPLISAgent * agent) {
330     deallocate(jvmtienv, agent);
331 }
332 
333 
334 JPLISInitializationError
recordCommandLineData(JPLISAgent * agent,const char * agentClassName,const char * optionsString)335 recordCommandLineData(  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  */
382 jboolean
processJavaStart(JPLISAgent * agent,JNIEnv * jnienv)383 processJavaStart(   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 fallback InternalError throwable.
393      */
394     result = initializeFallbackError(jnienv);
395     jplis_assert_msg(result, "fallback init failed");
396 
397     /*
398      *  Now make the InstrumentationImpl instance.
399      */
400     if ( result ) {
401         result = createInstrumentationImpl(jnienv, agent);
402         jplis_assert_msg(result, "instrumentation instance creation failed");
403     }
404 
405 
406     /*
407      *  Register a handler for ClassFileLoadHook (without enabling this event).
408      *  Turn off the VMInit handler.
409      */
410     if ( result ) {
411         result = setLivePhaseEventHandlers(agent);
412         jplis_assert_msg(result, "setting of live phase VM handlers failed");
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         jplis_assert_msg(result, "agent load/premain call failed");
423     }
424 
425     /*
426      * Finally surrender all of the tracking data that we don't need any more.
427      * If something is wrong, skip it, we will be aborting the JVM anyway.
428      */
429     if ( result ) {
430         deallocateCommandLineData(agent);
431     }
432 
433     return result;
434 }
435 
436 jboolean
startJavaAgent(JPLISAgent * agent,JNIEnv * jnienv,const char * classname,const char * optionsString,jmethodID agentMainMethod)437 startJavaAgent( JPLISAgent *    agent,
438                 JNIEnv *        jnienv,
439                 const char *    classname,
440                 const char *    optionsString,
441                 jmethodID       agentMainMethod) {
442     jboolean    success = JNI_FALSE;
443     jstring classNameObject = NULL;
444     jstring optionsStringObject = NULL;
445 
446     success = commandStringIntoJavaStrings(    jnienv,
447                                                classname,
448                                                optionsString,
449                                                &classNameObject,
450                                                &optionsStringObject);
451 
452     if (success) {
453         success = invokeJavaAgentMainMethod(   jnienv,
454                                                agent->mInstrumentationImpl,
455                                                agentMainMethod,
456                                                classNameObject,
457                                                optionsStringObject);
458     }
459 
460     return success;
461 }
462 
463 void
deallocateCommandLineData(JPLISAgent * agent)464 deallocateCommandLineData( JPLISAgent * agent) {
465     deallocate(jvmti(agent), (void*)agent->mAgentClassName);
466     deallocate(jvmti(agent), (void*)agent->mOptionsString);
467 
468     /* zero things out so it is easier to see what is going on */
469     agent->mAgentClassName = NULL;
470     agent->mOptionsString = NULL;
471 }
472 
473 /*
474  * Create the java.lang.instrument.Instrumentation instance
475  * and access information for it (method IDs, etc)
476  */
477 jboolean
createInstrumentationImpl(JNIEnv * jnienv,JPLISAgent * agent)478 createInstrumentationImpl( JNIEnv *        jnienv,
479                            JPLISAgent *    agent) {
480     jclass      implClass               = NULL;
481     jboolean    errorOutstanding        = JNI_FALSE;
482     jobject     resultImpl              = NULL;
483     jmethodID   premainCallerMethodID   = NULL;
484     jmethodID   agentmainCallerMethodID = NULL;
485     jmethodID   transformMethodID       = NULL;
486     jmethodID   constructorID           = NULL;
487     jobject     localReference          = NULL;
488 
489     /* First find the class of our implementation */
490     implClass = (*jnienv)->FindClass(   jnienv,
491                                         JPLIS_INSTRUMENTIMPL_CLASSNAME);
492     errorOutstanding = checkForAndClearThrowable(jnienv);
493     errorOutstanding = errorOutstanding || (implClass == NULL);
494     jplis_assert_msg(!errorOutstanding, "find class on InstrumentationImpl failed");
495 
496     if ( !errorOutstanding ) {
497         constructorID = (*jnienv)->GetMethodID( jnienv,
498                                                 implClass,
499                                                 JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODNAME,
500                                                 JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODSIGNATURE);
501         errorOutstanding = checkForAndClearThrowable(jnienv);
502         errorOutstanding = errorOutstanding || (constructorID == NULL);
503         jplis_assert_msg(!errorOutstanding, "find constructor on InstrumentationImpl failed");
504         }
505 
506     if ( !errorOutstanding ) {
507         jlong   peerReferenceAsScalar = (jlong)(intptr_t) agent;
508         localReference = (*jnienv)->NewObject(  jnienv,
509                                                 implClass,
510                                                 constructorID,
511                                                 peerReferenceAsScalar,
512                                                 agent->mRedefineAdded,
513                                                 agent->mNativeMethodPrefixAdded);
514         errorOutstanding = checkForAndClearThrowable(jnienv);
515         errorOutstanding = errorOutstanding || (localReference == NULL);
516         jplis_assert_msg(!errorOutstanding, "call constructor on InstrumentationImpl failed");
517     }
518 
519     if ( !errorOutstanding ) {
520         resultImpl = (*jnienv)->NewGlobalRef(jnienv, localReference);
521         errorOutstanding = checkForAndClearThrowable(jnienv);
522         jplis_assert_msg(!errorOutstanding, "copy local ref to global ref");
523     }
524 
525     /* Now look up the method ID for the pre-main caller (we will need this more than once) */
526     if ( !errorOutstanding ) {
527         premainCallerMethodID = (*jnienv)->GetMethodID( jnienv,
528                                                         implClass,
529                                                         JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODNAME,
530                                                         JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODSIGNATURE);
531         errorOutstanding = checkForAndClearThrowable(jnienv);
532         errorOutstanding = errorOutstanding || (premainCallerMethodID == NULL);
533         jplis_assert_msg(!errorOutstanding, "can't find premain invoker methodID");
534     }
535 
536     /* Now look up the method ID for the agent-main caller */
537     if ( !errorOutstanding ) {
538         agentmainCallerMethodID = (*jnienv)->GetMethodID( jnienv,
539                                                           implClass,
540                                                           JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODNAME,
541                                                           JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODSIGNATURE);
542         errorOutstanding = checkForAndClearThrowable(jnienv);
543         errorOutstanding = errorOutstanding || (agentmainCallerMethodID == NULL);
544         jplis_assert_msg(!errorOutstanding, "can't find agentmain invoker methodID");
545     }
546 
547     /* Now look up the method ID for the transform method (we will need this constantly) */
548     if ( !errorOutstanding ) {
549         transformMethodID = (*jnienv)->GetMethodID( jnienv,
550                                                     implClass,
551                                                     JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODNAME,
552                                                     JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODSIGNATURE);
553         errorOutstanding = checkForAndClearThrowable(jnienv);
554         errorOutstanding = errorOutstanding || (transformMethodID == NULL);
555         jplis_assert_msg(!errorOutstanding, "can't find transform methodID");
556     }
557 
558     if ( !errorOutstanding ) {
559         agent->mInstrumentationImpl = resultImpl;
560         agent->mPremainCaller       = premainCallerMethodID;
561         agent->mAgentmainCaller     = agentmainCallerMethodID;
562         agent->mTransform           = transformMethodID;
563     }
564 
565     return !errorOutstanding;
566 }
567 
568 jboolean
commandStringIntoJavaStrings(JNIEnv * jnienv,const char * classname,const char * optionsString,jstring * outputClassname,jstring * outputOptionsString)569 commandStringIntoJavaStrings(  JNIEnv *        jnienv,
570                                const char *    classname,
571                                const char *    optionsString,
572                                jstring *       outputClassname,
573                                jstring *       outputOptionsString) {
574     jstring     classnameJavaString     = NULL;
575     jstring     optionsJavaString       = NULL;
576     jboolean    errorOutstanding        = JNI_TRUE;
577 
578     classnameJavaString = (*jnienv)->NewStringUTF(jnienv, classname);
579     errorOutstanding = checkForAndClearThrowable(jnienv);
580     jplis_assert_msg(!errorOutstanding, "can't create class name java string");
581 
582     if ( !errorOutstanding ) {
583         if ( optionsString != NULL) {
584             optionsJavaString = (*jnienv)->NewStringUTF(jnienv, optionsString);
585             errorOutstanding = checkForAndClearThrowable(jnienv);
586             jplis_assert_msg(!errorOutstanding, "can't create options java string");
587         }
588 
589         if ( !errorOutstanding ) {
590             *outputClassname        = classnameJavaString;
591             *outputOptionsString    = optionsJavaString;
592         }
593     }
594 
595     return !errorOutstanding;
596 }
597 
598 
599 jboolean
invokeJavaAgentMainMethod(JNIEnv * jnienv,jobject instrumentationImpl,jmethodID mainCallingMethod,jstring className,jstring optionsString)600 invokeJavaAgentMainMethod( JNIEnv *    jnienv,
601                            jobject     instrumentationImpl,
602                            jmethodID   mainCallingMethod,
603                            jstring     className,
604                            jstring     optionsString) {
605     jboolean errorOutstanding = JNI_FALSE;
606 
607     jplis_assert(mainCallingMethod != NULL);
608     if ( mainCallingMethod != NULL ) {
609         (*jnienv)->CallVoidMethod(  jnienv,
610                                     instrumentationImpl,
611                                     mainCallingMethod,
612                                     className,
613                                     optionsString);
614         errorOutstanding = checkForThrowable(jnienv);
615         if ( errorOutstanding ) {
616             logThrowable(jnienv);
617         }
618         checkForAndClearThrowable(jnienv);
619     }
620     return !errorOutstanding;
621 }
622 
623 jboolean
setLivePhaseEventHandlers(JPLISAgent * agent)624 setLivePhaseEventHandlers(  JPLISAgent * agent) {
625     jvmtiEventCallbacks callbacks;
626     jvmtiEnv *          jvmtienv = jvmti(agent);
627     jvmtiError          jvmtierror;
628 
629     /* first swap out the handlers (switch from the VMInit handler, which we do not need,
630      * to the ClassFileLoadHook handler, which is what the agents need from now on)
631      */
632     memset(&callbacks, 0, sizeof(callbacks));
633     callbacks.ClassFileLoadHook = &eventHandlerClassFileLoadHook;
634 
635     jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv,
636                                                  &callbacks,
637                                                  sizeof(callbacks));
638     check_phase_ret_false(jvmtierror);
639     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
640 
641 
642     if ( jvmtierror == JVMTI_ERROR_NONE ) {
643         /* turn off VMInit */
644         jvmtierror = (*jvmtienv)->SetEventNotificationMode(
645                                                     jvmtienv,
646                                                     JVMTI_DISABLE,
647                                                     JVMTI_EVENT_VM_INIT,
648                                                     NULL /* all threads */);
649         check_phase_ret_false(jvmtierror);
650         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
651     }
652 
653     return (jvmtierror == JVMTI_ERROR_NONE);
654 }
655 
656 /**
657  *  Check if the can_redefine_classes capability is available.
658  */
659 void
checkCapabilities(JPLISAgent * agent)660 checkCapabilities(JPLISAgent * agent) {
661     jvmtiEnv *          jvmtienv = jvmti(agent);
662     jvmtiCapabilities   potentialCapabilities;
663     jvmtiError          jvmtierror;
664 
665     memset(&potentialCapabilities, 0, sizeof(potentialCapabilities));
666 
667     jvmtierror = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &potentialCapabilities);
668     check_phase_ret(jvmtierror);
669     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
670 
671     if ( jvmtierror == JVMTI_ERROR_NONE ) {
672         if ( potentialCapabilities.can_redefine_classes == 1 ) {
673             agent->mRedefineAvailable = JNI_TRUE;
674         }
675         if ( potentialCapabilities.can_set_native_method_prefix == 1 ) {
676             agent->mNativeMethodPrefixAvailable = JNI_TRUE;
677         }
678     }
679 }
680 
681 /**
682  * Enable native method prefix in one JVM TI environment
683  */
684 void
enableNativeMethodPrefixCapability(jvmtiEnv * jvmtienv)685 enableNativeMethodPrefixCapability(jvmtiEnv * jvmtienv) {
686     jvmtiCapabilities   desiredCapabilities;
687     jvmtiError          jvmtierror;
688 
689         jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);
690         /* can be called from any phase */
691         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
692         desiredCapabilities.can_set_native_method_prefix = 1;
693         jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);
694         check_phase_ret(jvmtierror);
695         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
696 }
697 
698 
699 /**
700  * Add the can_set_native_method_prefix capability
701  */
702 void
addNativeMethodPrefixCapability(JPLISAgent * agent)703 addNativeMethodPrefixCapability(JPLISAgent * agent) {
704     if (agent->mNativeMethodPrefixAvailable && !agent->mNativeMethodPrefixAdded) {
705         jvmtiEnv * jvmtienv = agent->mNormalEnvironment.mJVMTIEnv;
706         enableNativeMethodPrefixCapability(jvmtienv);
707 
708         jvmtienv = agent->mRetransformEnvironment.mJVMTIEnv;
709         if (jvmtienv != NULL) {
710             enableNativeMethodPrefixCapability(jvmtienv);
711         }
712         agent->mNativeMethodPrefixAdded = JNI_TRUE;
713     }
714 }
715 
716 /**
717  * Add the can_maintain_original_method_order capability (for testing)
718  */
719 void
addOriginalMethodOrderCapability(JPLISAgent * agent)720 addOriginalMethodOrderCapability(JPLISAgent * agent) {
721     jvmtiEnv *          jvmtienv = jvmti(agent);
722     jvmtiCapabilities   desiredCapabilities;
723     jvmtiError          jvmtierror;
724 
725     jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);
726     /* can be called from any phase */
727     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
728     desiredCapabilities.can_maintain_original_method_order = 1;
729     jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);
730     check_phase_ret(jvmtierror);
731     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
732 }
733 
734 /**
735  * Add the can_redefine_classes capability
736  */
737 void
addRedefineClassesCapability(JPLISAgent * agent)738 addRedefineClassesCapability(JPLISAgent * agent) {
739     jvmtiEnv *          jvmtienv = jvmti(agent);
740     jvmtiCapabilities   desiredCapabilities;
741     jvmtiError          jvmtierror;
742 
743     if (agent->mRedefineAvailable && !agent->mRedefineAdded) {
744         jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);
745         /* can be called from any phase */
746         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
747         desiredCapabilities.can_redefine_classes = 1;
748         jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);
749         check_phase_ret(jvmtierror);
750 
751         /*
752          * With mixed premain/agentmain agents then it's possible that the
753          * capability was potentially available in the onload phase but
754          * subsequently unavailable in the live phase.
755          */
756         jplis_assert(jvmtierror == JVMTI_ERROR_NONE ||
757                      jvmtierror == JVMTI_ERROR_NOT_AVAILABLE);
758         if (jvmtierror == JVMTI_ERROR_NONE) {
759             agent->mRedefineAdded = JNI_TRUE;
760         }
761     }
762 }
763 
764 static jobject
getModuleObject(jvmtiEnv * jvmti,jobject loaderObject,const char * cname)765 getModuleObject(jvmtiEnv*               jvmti,
766                 jobject                 loaderObject,
767                 const char*             cname) {
768     jvmtiError err = JVMTI_ERROR_NONE;
769     jobject moduleObject = NULL;
770 
771     /* find last slash in the class name */
772     char* last_slash = (cname == NULL) ? NULL : strrchr(cname, '/');
773     int len = (last_slash == NULL) ? 0 : (int)(last_slash - cname);
774     char* pkg_name_buf = (char*)malloc(len + 1);
775 
776     if (pkg_name_buf == NULL) {
777         fprintf(stderr, "OOM error in native tmp buffer allocation");
778         return NULL;
779     }
780     if (last_slash != NULL) {
781         strncpy(pkg_name_buf, cname, len);
782     }
783     pkg_name_buf[len] = '\0';
784 
785     err = (*jvmti)->GetNamedModule(jvmti, loaderObject, pkg_name_buf, &moduleObject);
786     free((void*)pkg_name_buf);
787     check_phase_ret_blob(err, NULL);
788     jplis_assert_msg(err == JVMTI_ERROR_NONE, "error in the JVMTI GetNamedModule");
789 
790     return moduleObject;
791 }
792 
793 /*
794  *  Support for the JVMTI callbacks
795  */
796 
797 void
transformClassFile(JPLISAgent * agent,JNIEnv * jnienv,jobject loaderObject,const char * name,jclass classBeingRedefined,jobject protectionDomain,jint class_data_len,const unsigned char * class_data,jint * new_class_data_len,unsigned char ** new_class_data,jboolean is_retransformer)798 transformClassFile(             JPLISAgent *            agent,
799                                 JNIEnv *                jnienv,
800                                 jobject                 loaderObject,
801                                 const char*             name,
802                                 jclass                  classBeingRedefined,
803                                 jobject                 protectionDomain,
804                                 jint                    class_data_len,
805                                 const unsigned char*    class_data,
806                                 jint*                   new_class_data_len,
807                                 unsigned char**         new_class_data,
808                                 jboolean                is_retransformer) {
809     jboolean        errorOutstanding        = JNI_FALSE;
810     jstring         classNameStringObject   = NULL;
811     jarray          classFileBufferObject   = NULL;
812     jarray          transformedBufferObject = NULL;
813     jsize           transformedBufferSize   = 0;
814     unsigned char * resultBuffer            = NULL;
815     jboolean        shouldRun               = JNI_FALSE;
816 
817     /* only do this if we aren't already in the middle of processing a class on this thread */
818     shouldRun = tryToAcquireReentrancyToken(
819                                 jvmti(agent),
820                                 NULL);  /* this thread */
821 
822     if ( shouldRun ) {
823         /* first marshall all the parameters */
824         classNameStringObject = (*jnienv)->NewStringUTF(jnienv,
825                                                         name);
826         errorOutstanding = checkForAndClearThrowable(jnienv);
827         jplis_assert_msg(!errorOutstanding, "can't create name string");
828 
829         if ( !errorOutstanding ) {
830             classFileBufferObject = (*jnienv)->NewByteArray(jnienv,
831                                                             class_data_len);
832             errorOutstanding = checkForAndClearThrowable(jnienv);
833             jplis_assert_msg(!errorOutstanding, "can't create byte array");
834         }
835 
836         if ( !errorOutstanding ) {
837             jbyte * typedBuffer = (jbyte *) class_data; /* nasty cast, dumb JNI interface, const missing */
838                                                         /* The sign cast is safe. The const cast is dumb. */
839             (*jnienv)->SetByteArrayRegion(  jnienv,
840                                             classFileBufferObject,
841                                             0,
842                                             class_data_len,
843                                             typedBuffer);
844             errorOutstanding = checkForAndClearThrowable(jnienv);
845             jplis_assert_msg(!errorOutstanding, "can't set byte array region");
846         }
847 
848         /*  now call the JPL agents to do the transforming */
849         /*  potential future optimization: may want to skip this if there are none */
850         if ( !errorOutstanding ) {
851             jobject moduleObject = NULL;
852 
853             if (classBeingRedefined == NULL) {
854                 moduleObject = getModuleObject(jvmti(agent), loaderObject, name);
855             } else {
856                 // Redefine or retransform, InstrumentationImpl.transform() will use
857                 // classBeingRedefined.getModule() to get the module.
858             }
859             jplis_assert(agent->mInstrumentationImpl != NULL);
860             jplis_assert(agent->mTransform != NULL);
861             transformedBufferObject = (*jnienv)->CallObjectMethod(
862                                                 jnienv,
863                                                 agent->mInstrumentationImpl,
864                                                 agent->mTransform,
865                                                 moduleObject,
866                                                 loaderObject,
867                                                 classNameStringObject,
868                                                 classBeingRedefined,
869                                                 protectionDomain,
870                                                 classFileBufferObject,
871                                                 is_retransformer);
872             errorOutstanding = checkForAndClearThrowable(jnienv);
873             jplis_assert_msg(!errorOutstanding, "transform method call failed");
874         }
875 
876         /* Finally, unmarshall the parameters (if someone touched the buffer, tell the JVM) */
877         if ( !errorOutstanding ) {
878             if ( transformedBufferObject != NULL ) {
879                 transformedBufferSize = (*jnienv)->GetArrayLength(  jnienv,
880                                                                     transformedBufferObject);
881                 errorOutstanding = checkForAndClearThrowable(jnienv);
882                 jplis_assert_msg(!errorOutstanding, "can't get array length");
883 
884                 if ( !errorOutstanding ) {
885                     /* allocate the response buffer with the JVMTI allocate call.
886                      *  This is what the JVMTI spec says to do for Class File Load hook responses
887                      */
888                     jvmtiError  allocError = (*(jvmti(agent)))->Allocate(jvmti(agent),
889                                                                              transformedBufferSize,
890                                                                              &resultBuffer);
891                     errorOutstanding = (allocError != JVMTI_ERROR_NONE);
892                     jplis_assert_msg(!errorOutstanding, "can't allocate result buffer");
893                 }
894 
895                 if ( !errorOutstanding ) {
896                     (*jnienv)->GetByteArrayRegion(  jnienv,
897                                                     transformedBufferObject,
898                                                     0,
899                                                     transformedBufferSize,
900                                                     (jbyte *) resultBuffer);
901                     errorOutstanding = checkForAndClearThrowable(jnienv);
902                     jplis_assert_msg(!errorOutstanding, "can't get byte array region");
903 
904                     /* in this case, we will not return the buffer to the JVMTI,
905                      * so we need to deallocate it ourselves
906                      */
907                     if ( errorOutstanding ) {
908                         deallocate( jvmti(agent),
909                                    (void*)resultBuffer);
910                     }
911                 }
912 
913                 if ( !errorOutstanding ) {
914                     *new_class_data_len = (transformedBufferSize);
915                     *new_class_data     = resultBuffer;
916                 }
917             }
918         }
919 
920         /* release the token */
921         releaseReentrancyToken( jvmti(agent),
922                                 NULL);      /* this thread */
923 
924     }
925 
926     return;
927 }
928 
929 /*
930  *  Misc. internal utilities.
931  */
932 
933 /*
934  *  The only checked exceptions we can throw are ClassNotFoundException and
935  *  UnmodifiableClassException. All others map to InternalError.
936  */
937 jthrowable
redefineClassMapper(JNIEnv * jnienv,jthrowable throwableToMap)938 redefineClassMapper(    JNIEnv *    jnienv,
939                         jthrowable  throwableToMap) {
940     jthrowable  mappedThrowable = NULL;
941 
942     jplis_assert(isSafeForJNICalls(jnienv));
943     jplis_assert(!isUnchecked(jnienv, throwableToMap));
944 
945     if ( isInstanceofClassName( jnienv,
946                                 throwableToMap,
947                                 "java/lang/ClassNotFoundException") ) {
948         mappedThrowable = throwableToMap;
949     } else {
950         if ( isInstanceofClassName( jnienv,
951                                 throwableToMap,
952                                 "java/lang/instrument/UnmodifiableClassException")) {
953             mappedThrowable = throwableToMap;
954         } else {
955             jstring message = NULL;
956 
957             message = getMessageFromThrowable(jnienv, throwableToMap);
958             mappedThrowable = createInternalError(jnienv, message);
959         }
960     }
961 
962     jplis_assert(isSafeForJNICalls(jnienv));
963     return mappedThrowable;
964 }
965 
966 jobjectArray
getObjectArrayFromClasses(JNIEnv * jnienv,jclass * classes,jint classCount)967 getObjectArrayFromClasses(JNIEnv* jnienv, jclass* classes, jint classCount) {
968     jclass          classArrayClass = NULL;
969     jobjectArray    localArray      = NULL;
970     jint            classIndex      = 0;
971     jboolean        errorOccurred   = JNI_FALSE;
972 
973     /* get the class array class */
974     classArrayClass = (*jnienv)->FindClass(jnienv, "java/lang/Class");
975     errorOccurred = checkForThrowable(jnienv);
976 
977     if (!errorOccurred) {
978         jplis_assert_msg(classArrayClass != NULL, "FindClass returned null class");
979 
980         /* create the array for the classes */
981         localArray = (*jnienv)->NewObjectArray(jnienv, classCount, classArrayClass, NULL);
982         errorOccurred = checkForThrowable(jnienv);
983 
984         if (!errorOccurred) {
985             jplis_assert_msg(localArray != NULL, "NewObjectArray returned null array");
986 
987             /* now copy refs to all the classes and put them into the array */
988             for (classIndex = 0; classIndex < classCount; classIndex++) {
989                 /* put class into array */
990                 (*jnienv)->SetObjectArrayElement(jnienv, localArray, classIndex, classes[classIndex]);
991                 errorOccurred = checkForThrowable(jnienv);
992 
993                 if (errorOccurred) {
994                     localArray = NULL;
995                     break;
996                 }
997             }
998         }
999     }
1000 
1001     return localArray;
1002 }
1003 
1004 
1005 /* Return the environment with the retransformation capability.
1006  * Create it if it doesn't exist.
1007  * Return NULL if it can't be created.
1008  */
1009 jvmtiEnv *
retransformableEnvironment(JPLISAgent * agent)1010 retransformableEnvironment(JPLISAgent * agent) {
1011     jvmtiEnv *          retransformerEnv     = NULL;
1012     jint                jnierror             = JNI_OK;
1013     jvmtiCapabilities   desiredCapabilities;
1014     jvmtiEventCallbacks callbacks;
1015     jvmtiError          jvmtierror;
1016 
1017     if (agent->mRetransformEnvironment.mJVMTIEnv != NULL) {
1018         return agent->mRetransformEnvironment.mJVMTIEnv;
1019     }
1020     jnierror = (*agent->mJVM)->GetEnv(  agent->mJVM,
1021                                (void **) &retransformerEnv,
1022                                JVMTI_VERSION_1_1);
1023     if ( jnierror != JNI_OK ) {
1024         return NULL;
1025     }
1026     jvmtierror = (*retransformerEnv)->GetCapabilities(retransformerEnv, &desiredCapabilities);
1027     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1028     desiredCapabilities.can_retransform_classes = 1;
1029     if (agent->mNativeMethodPrefixAdded) {
1030         desiredCapabilities.can_set_native_method_prefix = 1;
1031     }
1032 
1033     jvmtierror = (*retransformerEnv)->AddCapabilities(retransformerEnv, &desiredCapabilities);
1034     if (jvmtierror != JVMTI_ERROR_NONE) {
1035          /* cannot get the capability, dispose of the retransforming environment */
1036         jvmtierror = (*retransformerEnv)->DisposeEnvironment(retransformerEnv);
1037         jplis_assert(jvmtierror == JVMTI_ERROR_NOT_AVAILABLE);
1038         return NULL;
1039     }
1040     memset(&callbacks, 0, sizeof(callbacks));
1041     callbacks.ClassFileLoadHook = &eventHandlerClassFileLoadHook;
1042 
1043     jvmtierror = (*retransformerEnv)->SetEventCallbacks(retransformerEnv,
1044                                                         &callbacks,
1045                                                         sizeof(callbacks));
1046     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1047     if (jvmtierror == JVMTI_ERROR_NONE) {
1048         // install the retransforming environment
1049         agent->mRetransformEnvironment.mJVMTIEnv = retransformerEnv;
1050         agent->mRetransformEnvironment.mIsRetransformer = JNI_TRUE;
1051 
1052         // Make it for ClassFileLoadHook handling
1053         jvmtierror = (*retransformerEnv)->SetEnvironmentLocalStorage(
1054                                                        retransformerEnv,
1055                                                        &(agent->mRetransformEnvironment));
1056         jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1057         if (jvmtierror == JVMTI_ERROR_NONE) {
1058             return retransformerEnv;
1059         }
1060     }
1061     return NULL;
1062 }
1063 
1064 
1065 /*
1066  *  Underpinnings for native methods
1067  */
1068 
1069 jboolean
isModifiableClass(JNIEnv * jnienv,JPLISAgent * agent,jclass clazz)1070 isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz) {
1071     jvmtiEnv *          jvmtienv = jvmti(agent);
1072     jvmtiError          jvmtierror;
1073     jboolean            is_modifiable = JNI_FALSE;
1074 
1075     jvmtierror = (*jvmtienv)->IsModifiableClass( jvmtienv,
1076                                                  clazz,
1077                                                  &is_modifiable);
1078     check_phase_ret_false(jvmtierror);
1079     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1080 
1081     return is_modifiable;
1082 }
1083 
1084 jboolean
isRetransformClassesSupported(JNIEnv * jnienv,JPLISAgent * agent)1085 isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent) {
1086     return agent->mRetransformEnvironment.mIsRetransformer;
1087 }
1088 
1089 void
setHasTransformers(JNIEnv * jnienv,JPLISAgent * agent,jboolean has)1090 setHasTransformers(JNIEnv * jnienv, JPLISAgent * agent, jboolean has) {
1091     jvmtiEnv *          jvmtienv = jvmti(agent);
1092     jvmtiError          jvmtierror;
1093 
1094     jplis_assert(jvmtienv != NULL);
1095     jvmtierror = (*jvmtienv)->SetEventNotificationMode(
1096                                             jvmtienv,
1097                                             has? JVMTI_ENABLE : JVMTI_DISABLE,
1098                                             JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
1099                                             NULL /* all threads */);
1100     check_phase_ret(jvmtierror);
1101     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1102 }
1103 
1104 void
setHasRetransformableTransformers(JNIEnv * jnienv,JPLISAgent * agent,jboolean has)1105 setHasRetransformableTransformers(JNIEnv * jnienv, JPLISAgent * agent, jboolean has) {
1106     jvmtiEnv *          retransformerEnv     = retransformableEnvironment(agent);
1107     jvmtiError          jvmtierror;
1108 
1109     jplis_assert(retransformerEnv != NULL);
1110     jvmtierror = (*retransformerEnv)->SetEventNotificationMode(
1111                                                     retransformerEnv,
1112                                                     has? JVMTI_ENABLE : JVMTI_DISABLE,
1113                                                     JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
1114                                                     NULL /* all threads */);
1115     check_phase_ret(jvmtierror);
1116     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1117 }
1118 
1119 void
retransformClasses(JNIEnv * jnienv,JPLISAgent * agent,jobjectArray classes)1120 retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes) {
1121     jvmtiEnv *  retransformerEnv     = retransformableEnvironment(agent);
1122     jboolean    errorOccurred        = JNI_FALSE;
1123     jvmtiError  errorCode            = JVMTI_ERROR_NONE;
1124     jsize       numClasses           = 0;
1125     jclass *    classArray           = NULL;
1126 
1127     /* This is supposed to be checked by caller, but just to be sure */
1128     if (retransformerEnv == NULL) {
1129         jplis_assert(retransformerEnv != NULL);
1130         errorOccurred = JNI_TRUE;
1131         errorCode = JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
1132     }
1133 
1134     /* This was supposed to be checked by caller too */
1135     if (!errorOccurred && classes == NULL) {
1136         jplis_assert(classes != NULL);
1137         errorOccurred = JNI_TRUE;
1138         errorCode = JVMTI_ERROR_NULL_POINTER;
1139     }
1140 
1141     if (!errorOccurred) {
1142         numClasses = (*jnienv)->GetArrayLength(jnienv, classes);
1143         errorOccurred = checkForThrowable(jnienv);
1144         jplis_assert(!errorOccurred);
1145 
1146         if (!errorOccurred && numClasses == 0) {
1147             jplis_assert(numClasses != 0);
1148             errorOccurred = JNI_TRUE;
1149             errorCode = JVMTI_ERROR_NULL_POINTER;
1150         }
1151     }
1152 
1153     if (!errorOccurred) {
1154         classArray = (jclass *) allocate(retransformerEnv,
1155                                          numClasses * sizeof(jclass));
1156         errorOccurred = (classArray == NULL);
1157         jplis_assert(!errorOccurred);
1158         if (errorOccurred) {
1159             errorCode = JVMTI_ERROR_OUT_OF_MEMORY;
1160         }
1161     }
1162 
1163     if (!errorOccurred) {
1164         jint index;
1165         for (index = 0; index < numClasses; index++) {
1166             classArray[index] = (*jnienv)->GetObjectArrayElement(jnienv, classes, index);
1167             errorOccurred = checkForThrowable(jnienv);
1168             jplis_assert(!errorOccurred);
1169             if (errorOccurred) {
1170                 break;
1171             }
1172 
1173             if (classArray[index] == NULL) {
1174                 jplis_assert(classArray[index] != NULL);
1175                 errorOccurred = JNI_TRUE;
1176                 errorCode = JVMTI_ERROR_NULL_POINTER;
1177                 break;
1178             }
1179         }
1180     }
1181 
1182     if (!errorOccurred) {
1183         errorCode = (*retransformerEnv)->RetransformClasses(retransformerEnv,
1184                                                             numClasses, classArray);
1185         errorOccurred = (errorCode != JVMTI_ERROR_NONE);
1186     }
1187 
1188     /* Give back the buffer if we allocated it.  Throw any exceptions after.
1189      */
1190     if (classArray != NULL) {
1191         deallocate(retransformerEnv, (void*)classArray);
1192     }
1193 
1194     /* Return back if we executed the JVMTI API in a wrong phase
1195      */
1196     check_phase_ret(errorCode);
1197 
1198     if (errorCode != JVMTI_ERROR_NONE) {
1199         createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode);
1200     }
1201 
1202     mapThrownThrowableIfNecessary(jnienv, redefineClassMapper);
1203 }
1204 
1205 /*
1206  *  Java code must not call this with a null list or a zero-length list.
1207  */
1208 void
redefineClasses(JNIEnv * jnienv,JPLISAgent * agent,jobjectArray classDefinitions)1209 redefineClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classDefinitions) {
1210     jvmtiEnv*   jvmtienv                        = jvmti(agent);
1211     jboolean    errorOccurred                   = JNI_FALSE;
1212     jclass      classDefClass                   = NULL;
1213     jmethodID   getDefinitionClassMethodID      = NULL;
1214     jmethodID   getDefinitionClassFileMethodID  = NULL;
1215     jvmtiClassDefinition* classDefs             = NULL;
1216     jbyteArray* targetFiles                     = NULL;
1217     jsize       numDefs                         = 0;
1218 
1219     jplis_assert(classDefinitions != NULL);
1220 
1221     numDefs = (*jnienv)->GetArrayLength(jnienv, classDefinitions);
1222     errorOccurred = checkForThrowable(jnienv);
1223     jplis_assert(!errorOccurred);
1224 
1225     if (!errorOccurred) {
1226         jplis_assert(numDefs > 0);
1227         /* get method IDs for methods to call on class definitions */
1228         classDefClass = (*jnienv)->FindClass(jnienv, "java/lang/instrument/ClassDefinition");
1229         errorOccurred = checkForThrowable(jnienv);
1230         jplis_assert(!errorOccurred);
1231     }
1232 
1233     if (!errorOccurred) {
1234         getDefinitionClassMethodID = (*jnienv)->GetMethodID(    jnienv,
1235                                                 classDefClass,
1236                                                 "getDefinitionClass",
1237                                                 "()Ljava/lang/Class;");
1238         errorOccurred = checkForThrowable(jnienv);
1239         jplis_assert(!errorOccurred);
1240     }
1241 
1242     if (!errorOccurred) {
1243         getDefinitionClassFileMethodID = (*jnienv)->GetMethodID(    jnienv,
1244                                                     classDefClass,
1245                                                     "getDefinitionClassFile",
1246                                                     "()[B");
1247         errorOccurred = checkForThrowable(jnienv);
1248         jplis_assert(!errorOccurred);
1249     }
1250 
1251     if (!errorOccurred) {
1252         classDefs = (jvmtiClassDefinition *) allocate(
1253                                                 jvmtienv,
1254                                                 numDefs * sizeof(jvmtiClassDefinition));
1255         errorOccurred = (classDefs == NULL);
1256         jplis_assert(!errorOccurred);
1257         if ( errorOccurred ) {
1258             createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY);
1259         }
1260 
1261         else {
1262             /*
1263              * We have to save the targetFile values that we compute so
1264              * that we can release the class_bytes arrays that are
1265              * returned by GetByteArrayElements(). In case of a JNI
1266              * error, we can't (easily) recompute the targetFile values
1267              * and we still want to free any memory we allocated.
1268              */
1269             targetFiles = (jbyteArray *) allocate(jvmtienv,
1270                                                   numDefs * sizeof(jbyteArray));
1271             errorOccurred = (targetFiles == NULL);
1272             jplis_assert(!errorOccurred);
1273             if ( errorOccurred ) {
1274                 deallocate(jvmtienv, (void*)classDefs);
1275                 createAndThrowThrowableFromJVMTIErrorCode(jnienv,
1276                     JVMTI_ERROR_OUT_OF_MEMORY);
1277             }
1278             else {
1279                 jint i, j;
1280 
1281                 // clear classDefs so we can correctly free memory during errors
1282                 memset(classDefs, 0, numDefs * sizeof(jvmtiClassDefinition));
1283 
1284                 for (i = 0; i < numDefs; i++) {
1285                     jclass      classDef    = NULL;
1286 
1287                     classDef = (*jnienv)->GetObjectArrayElement(jnienv, classDefinitions, i);
1288                     errorOccurred = checkForThrowable(jnienv);
1289                     jplis_assert(!errorOccurred);
1290                     if (errorOccurred) {
1291                         break;
1292                     }
1293 
1294                     classDefs[i].klass = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassMethodID);
1295                     errorOccurred = checkForThrowable(jnienv);
1296                     jplis_assert(!errorOccurred);
1297                     if (errorOccurred) {
1298                         break;
1299                     }
1300 
1301                     targetFiles[i] = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassFileMethodID);
1302                     errorOccurred = checkForThrowable(jnienv);
1303                     jplis_assert(!errorOccurred);
1304                     if (errorOccurred) {
1305                         break;
1306                     }
1307 
1308                     classDefs[i].class_byte_count = (*jnienv)->GetArrayLength(jnienv, targetFiles[i]);
1309                     errorOccurred = checkForThrowable(jnienv);
1310                     jplis_assert(!errorOccurred);
1311                     if (errorOccurred) {
1312                         break;
1313                     }
1314 
1315                     /*
1316                      * Allocate class_bytes last so we don't have to free
1317                      * memory on a partial row error.
1318                      */
1319                     classDefs[i].class_bytes = (unsigned char*)(*jnienv)->GetByteArrayElements(jnienv, targetFiles[i], NULL);
1320                     errorOccurred = checkForThrowable(jnienv);
1321                     jplis_assert(!errorOccurred);
1322                     if (errorOccurred) {
1323                         break;
1324                     }
1325                 }
1326 
1327                 if (!errorOccurred) {
1328                     jvmtiError  errorCode = JVMTI_ERROR_NONE;
1329                     errorCode = (*jvmtienv)->RedefineClasses(jvmtienv, numDefs, classDefs);
1330                     if (errorCode == JVMTI_ERROR_WRONG_PHASE) {
1331                         /* insulate caller from the wrong phase error */
1332                         errorCode = JVMTI_ERROR_NONE;
1333                     } else {
1334                         errorOccurred = (errorCode != JVMTI_ERROR_NONE);
1335                         if ( errorOccurred ) {
1336                             createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode);
1337                         }
1338                     }
1339                 }
1340 
1341                 /*
1342                  * Cleanup memory that we allocated above. If we had a
1343                  * JNI error, a JVM/TI error or no errors, index 'i'
1344                  * tracks how far we got in processing the classDefs
1345                  * array. Note:  ReleaseByteArrayElements() is safe to
1346                  * call with a JNI exception pending.
1347                  */
1348                 for (j = 0; j < i; j++) {
1349                     if ((jbyte *)classDefs[j].class_bytes != NULL) {
1350                         (*jnienv)->ReleaseByteArrayElements(jnienv,
1351                             targetFiles[j], (jbyte *)classDefs[j].class_bytes,
1352                             0 /* copy back and free */);
1353                         /*
1354                          * Only check for error if we didn't already have one
1355                          * so we don't overwrite errorOccurred.
1356                          */
1357                         if (!errorOccurred) {
1358                             errorOccurred = checkForThrowable(jnienv);
1359                             jplis_assert(!errorOccurred);
1360                         }
1361                     }
1362                 }
1363                 deallocate(jvmtienv, (void*)targetFiles);
1364                 deallocate(jvmtienv, (void*)classDefs);
1365             }
1366         }
1367     }
1368 
1369     mapThrownThrowableIfNecessary(jnienv, redefineClassMapper);
1370 }
1371 
1372 /* Cheesy sharing. ClassLoader may be null. */
1373 jobjectArray
commonGetClassList(JNIEnv * jnienv,JPLISAgent * agent,jobject classLoader,ClassListFetcher fetcher)1374 commonGetClassList( JNIEnv *            jnienv,
1375                     JPLISAgent *        agent,
1376                     jobject             classLoader,
1377                     ClassListFetcher    fetcher) {
1378     jvmtiEnv *      jvmtienv        = jvmti(agent);
1379     jboolean        errorOccurred   = JNI_FALSE;
1380     jvmtiError      jvmtierror      = JVMTI_ERROR_NONE;
1381     jint            classCount      = 0;
1382     jclass *        classes         = NULL;
1383     jobjectArray    localArray      = NULL;
1384 
1385     /* retrieve the classes from the JVMTI agent */
1386     jvmtierror = (*fetcher)( jvmtienv,
1387                         classLoader,
1388                         &classCount,
1389                         &classes);
1390     check_phase_ret_blob(jvmtierror, localArray);
1391     errorOccurred = (jvmtierror != JVMTI_ERROR_NONE);
1392     jplis_assert(!errorOccurred);
1393 
1394     if ( errorOccurred ) {
1395         createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);
1396     } else {
1397         localArray = getObjectArrayFromClasses( jnienv,
1398                                                 classes,
1399                                                 classCount);
1400         errorOccurred = checkForThrowable(jnienv);
1401         jplis_assert(!errorOccurred);
1402 
1403         /* do this whether or not we saw a problem */
1404         deallocate(jvmtienv, (void*)classes);
1405     }
1406 
1407     mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper);
1408     return localArray;
1409 
1410 }
1411 
1412 jvmtiError
getAllLoadedClassesClassListFetcher(jvmtiEnv * jvmtienv,jobject classLoader,jint * classCount,jclass ** classes)1413 getAllLoadedClassesClassListFetcher(    jvmtiEnv *  jvmtienv,
1414                                         jobject     classLoader,
1415                                         jint *      classCount,
1416                                         jclass **   classes) {
1417     return (*jvmtienv)->GetLoadedClasses(jvmtienv, classCount, classes);
1418 }
1419 
1420 jobjectArray
getAllLoadedClasses(JNIEnv * jnienv,JPLISAgent * agent)1421 getAllLoadedClasses(JNIEnv * jnienv, JPLISAgent * agent) {
1422     return commonGetClassList(  jnienv,
1423                                 agent,
1424                                 NULL,
1425                                 getAllLoadedClassesClassListFetcher);
1426 }
1427 
1428 jvmtiError
getInitiatedClassesClassListFetcher(jvmtiEnv * jvmtienv,jobject classLoader,jint * classCount,jclass ** classes)1429 getInitiatedClassesClassListFetcher(    jvmtiEnv *  jvmtienv,
1430                                         jobject     classLoader,
1431                                         jint *      classCount,
1432                                         jclass **   classes) {
1433     return (*jvmtienv)->GetClassLoaderClasses(jvmtienv, classLoader, classCount, classes);
1434 }
1435 
1436 
1437 jobjectArray
getInitiatedClasses(JNIEnv * jnienv,JPLISAgent * agent,jobject classLoader)1438 getInitiatedClasses(JNIEnv * jnienv, JPLISAgent * agent, jobject classLoader) {
1439     return commonGetClassList(  jnienv,
1440                                 agent,
1441                                 classLoader,
1442                                 getInitiatedClassesClassListFetcher);
1443 }
1444 
1445 jlong
getObjectSize(JNIEnv * jnienv,JPLISAgent * agent,jobject objectToSize)1446 getObjectSize(JNIEnv * jnienv, JPLISAgent * agent, jobject objectToSize) {
1447     jvmtiEnv *  jvmtienv    = jvmti(agent);
1448     jlong       objectSize  = -1;
1449     jvmtiError  jvmtierror  = JVMTI_ERROR_NONE;
1450 
1451     jvmtierror = (*jvmtienv)->GetObjectSize(jvmtienv, objectToSize, &objectSize);
1452     check_phase_ret_0(jvmtierror);
1453     jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
1454     if ( jvmtierror != JVMTI_ERROR_NONE ) {
1455         createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);
1456     }
1457 
1458     mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper);
1459     return objectSize;
1460 }
1461 
1462 void
appendToClassLoaderSearch(JNIEnv * jnienv,JPLISAgent * agent,jstring jarFile,jboolean isBootLoader)1463 appendToClassLoaderSearch(JNIEnv * jnienv, JPLISAgent * agent, jstring jarFile, jboolean isBootLoader)
1464 {
1465     jvmtiEnv *  jvmtienv    = jvmti(agent);
1466     jboolean    errorOutstanding;
1467     jvmtiError  jvmtierror;
1468     const char* utf8Chars;
1469     jsize       utf8Len;
1470     jboolean    isCopy;
1471     char        platformChars[MAXPATHLEN];
1472     int         platformLen;
1473 
1474     utf8Len = (*jnienv)->GetStringUTFLength(jnienv, jarFile);
1475     errorOutstanding = checkForAndClearThrowable(jnienv);
1476 
1477     if (!errorOutstanding) {
1478         utf8Chars = (*jnienv)->GetStringUTFChars(jnienv, jarFile, &isCopy);
1479         errorOutstanding = checkForAndClearThrowable(jnienv);
1480 
1481         if (!errorOutstanding && utf8Chars != NULL) {
1482             /*
1483              * JVMTI spec'ed to use modified UTF8. At this time this is not implemented
1484              * the platform encoding is used.
1485              */
1486             platformLen = convertUft8ToPlatformString((char*)utf8Chars, utf8Len, platformChars, MAXPATHLEN);
1487             if (platformLen < 0) {
1488                 createAndThrowInternalError(jnienv);
1489                 (*jnienv)->ReleaseStringUTFChars(jnienv, jarFile, utf8Chars);
1490                 return;
1491             }
1492 
1493             (*jnienv)->ReleaseStringUTFChars(jnienv, jarFile, utf8Chars);
1494             errorOutstanding = checkForAndClearThrowable(jnienv);
1495 
1496             if (!errorOutstanding) {
1497 
1498                 if (isBootLoader) {
1499                     jvmtierror = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, platformChars);
1500                 } else {
1501                     jvmtierror = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, platformChars);
1502                 }
1503                 check_phase_ret(jvmtierror);
1504 
1505                 if ( jvmtierror != JVMTI_ERROR_NONE ) {
1506                     createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);
1507                 }
1508             }
1509         }
1510     }
1511 
1512     mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper);
1513 }
1514 
1515 /*
1516  *  Set the prefixes used to wrap native methods (so they can be instrumented).
1517  *  Each transform can set a prefix, any that have been set come in as prefixArray.
1518  *  Convert them in native strings in a native array then call JVM TI.
1519  *  One a given call, this function handles either the prefixes for retransformable
1520  *  transforms or for normal transforms.
1521  */
1522 void
setNativeMethodPrefixes(JNIEnv * jnienv,JPLISAgent * agent,jobjectArray prefixArray,jboolean isRetransformable)1523 setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefixArray,
1524                         jboolean isRetransformable) {
1525     jvmtiEnv*   jvmtienv;
1526     jvmtiError  err                             = JVMTI_ERROR_NONE;
1527     jsize       arraySize;
1528     jboolean    errorOccurred                   = JNI_FALSE;
1529 
1530     jplis_assert(prefixArray != NULL);
1531 
1532     if (isRetransformable) {
1533         jvmtienv = agent->mRetransformEnvironment.mJVMTIEnv;
1534     } else {
1535         jvmtienv = agent->mNormalEnvironment.mJVMTIEnv;
1536     }
1537     arraySize = (*jnienv)->GetArrayLength(jnienv, prefixArray);
1538     errorOccurred = checkForThrowable(jnienv);
1539     jplis_assert(!errorOccurred);
1540 
1541     if (!errorOccurred) {
1542         /* allocate the native to hold the native prefixes */
1543         const char** prefixes = (const char**) allocate(jvmtienv,
1544                                                         arraySize * sizeof(char*));
1545         /* since JNI ReleaseStringUTFChars needs the jstring from which the native
1546          * string was allocated, we store them in a parallel array */
1547         jstring* originForRelease = (jstring*) allocate(jvmtienv,
1548                                                         arraySize * sizeof(jstring));
1549         errorOccurred = (prefixes == NULL || originForRelease == NULL);
1550         jplis_assert(!errorOccurred);
1551         if ( errorOccurred ) {
1552             createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY);
1553         }
1554         else {
1555             jint inx = 0;
1556             jint i;
1557             for (i = 0; i < arraySize; i++) {
1558                 jstring      prefixStr  = NULL;
1559                 const char*  prefix;
1560                 jsize        prefixLen;
1561                 jboolean     isCopy;
1562 
1563                 prefixStr = (jstring) ((*jnienv)->GetObjectArrayElement(jnienv,
1564                                                                         prefixArray, i));
1565                 errorOccurred = checkForThrowable(jnienv);
1566                 jplis_assert(!errorOccurred);
1567                 if (errorOccurred) {
1568                     break;
1569                 }
1570                 if (prefixStr == NULL) {
1571                     continue;
1572                 }
1573 
1574                 prefixLen = (*jnienv)->GetStringUTFLength(jnienv, prefixStr);
1575                 errorOccurred = checkForThrowable(jnienv);
1576                 jplis_assert(!errorOccurred);
1577                 if (errorOccurred) {
1578                     break;
1579                 }
1580 
1581                 if (prefixLen > 0) {
1582                     prefix = (*jnienv)->GetStringUTFChars(jnienv, prefixStr, &isCopy);
1583                     errorOccurred = checkForThrowable(jnienv);
1584                     jplis_assert(!errorOccurred);
1585                     if (!errorOccurred && prefix != NULL) {
1586                         prefixes[inx] = prefix;
1587                         originForRelease[inx] = prefixStr;
1588                         ++inx;
1589                     }
1590                 }
1591             }
1592 
1593             err = (*jvmtienv)->SetNativeMethodPrefixes(jvmtienv, inx, (char**)prefixes);
1594             /* can be called from any phase */
1595             jplis_assert(err == JVMTI_ERROR_NONE);
1596 
1597             for (i = 0; i < inx; i++) {
1598               (*jnienv)->ReleaseStringUTFChars(jnienv, originForRelease[i], prefixes[i]);
1599             }
1600         }
1601         deallocate(jvmtienv, (void*)prefixes);
1602         deallocate(jvmtienv, (void*)originForRelease);
1603     }
1604 }
1605