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. */
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 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
436jboolean
437startJavaAgent( 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
463void
464deallocateCommandLineData( 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 */
477jboolean
478createInstrumentationImpl( 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
568jboolean
569commandStringIntoJavaStrings( 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
599jboolean
600invokeJavaAgentMainMethod( 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
623jboolean
624setLivePhaseEventHandlers( 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 */
659void
660checkCapabilities(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 */
684void
685enableNativeMethodPrefixCapability(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 */
702void
703addNativeMethodPrefixCapability(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 */
719void
720addOriginalMethodOrderCapability(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 */
737void
738addRedefineClassesCapability(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
764static jobject
765getModuleObject(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
797void
798transformClassFile( 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 */
937jthrowable
938redefineClassMapper( 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
966jobjectArray
967getObjectArrayFromClasses(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 */
1009jvmtiEnv *
1010retransformableEnvironment(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
1069jboolean
1070isModifiableClass(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
1084jboolean
1085isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent) {
1086 return agent->mRetransformEnvironment.mIsRetransformer;
1087}
1088
1089void
1090setHasTransformers(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
1104void
1105setHasRetransformableTransformers(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
1119void
1120retransformClasses(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 */
1208void
1209redefineClasses(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. */
1373jobjectArray
1374commonGetClassList( 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
1412jvmtiError
1413getAllLoadedClassesClassListFetcher( jvmtiEnv * jvmtienv,
1414 jobject classLoader,
1415 jint * classCount,
1416 jclass ** classes) {
1417 return (*jvmtienv)->GetLoadedClasses(jvmtienv, classCount, classes);
1418}
1419
1420jobjectArray
1421getAllLoadedClasses(JNIEnv * jnienv, JPLISAgent * agent) {
1422 return commonGetClassList( jnienv,
1423 agent,
1424 NULL,
1425 getAllLoadedClassesClassListFetcher);
1426}
1427
1428jvmtiError
1429getInitiatedClassesClassListFetcher( jvmtiEnv * jvmtienv,
1430 jobject classLoader,
1431 jint * classCount,
1432 jclass ** classes) {
1433 return (*jvmtienv)->GetClassLoaderClasses(jvmtienv, classLoader, classCount, classes);
1434}
1435
1436
1437jobjectArray
1438getInitiatedClasses(JNIEnv * jnienv, JPLISAgent * agent, jobject classLoader) {
1439 return commonGetClassList( jnienv,
1440 agent,
1441 classLoader,
1442 getInitiatedClassesClassListFetcher);
1443}
1444
1445jlong
1446getObjectSize(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
1462void
1463appendToClassLoaderSearch(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 return;
1490 }
1491
1492 (*jnienv)->ReleaseStringUTFChars(jnienv, jarFile, utf8Chars);
1493 errorOutstanding = checkForAndClearThrowable(jnienv);
1494
1495 if (!errorOutstanding) {
1496
1497 if (isBootLoader) {
1498 jvmtierror = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, platformChars);
1499 } else {
1500 jvmtierror = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, platformChars);
1501 }
1502 check_phase_ret(jvmtierror);
1503
1504 if ( jvmtierror != JVMTI_ERROR_NONE ) {
1505 createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);
1506 }
1507 }
1508 }
1509 }
1510
1511 mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper);
1512}
1513
1514/*
1515 * Set the prefixes used to wrap native methods (so they can be instrumented).
1516 * Each transform can set a prefix, any that have been set come in as prefixArray.
1517 * Convert them in native strings in a native array then call JVM TI.
1518 * One a given call, this function handles either the prefixes for retransformable
1519 * transforms or for normal transforms.
1520 */
1521void
1522setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefixArray,
1523 jboolean isRetransformable) {
1524 jvmtiEnv* jvmtienv;
1525 jvmtiError err = JVMTI_ERROR_NONE;
1526 jsize arraySize;
1527 jboolean errorOccurred = JNI_FALSE;
1528
1529 jplis_assert(prefixArray != NULL);
1530
1531 if (isRetransformable) {
1532 jvmtienv = agent->mRetransformEnvironment.mJVMTIEnv;
1533 } else {
1534 jvmtienv = agent->mNormalEnvironment.mJVMTIEnv;
1535 }
1536 arraySize = (*jnienv)->GetArrayLength(jnienv, prefixArray);
1537 errorOccurred = checkForThrowable(jnienv);
1538 jplis_assert(!errorOccurred);
1539
1540 if (!errorOccurred) {
1541 /* allocate the native to hold the native prefixes */
1542 const char** prefixes = (const char**) allocate(jvmtienv,
1543 arraySize * sizeof(char*));
1544 /* since JNI ReleaseStringUTFChars needs the jstring from which the native
1545 * string was allocated, we store them in a parallel array */
1546 jstring* originForRelease = (jstring*) allocate(jvmtienv,
1547 arraySize * sizeof(jstring));
1548 errorOccurred = (prefixes == NULL || originForRelease == NULL);
1549 jplis_assert(!errorOccurred);
1550 if ( errorOccurred ) {
1551 createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY);
1552 }
1553 else {
1554 jint inx = 0;
1555 jint i;
1556 for (i = 0; i < arraySize; i++) {
1557 jstring prefixStr = NULL;
1558 const char* prefix;
1559 jsize prefixLen;
1560 jboolean isCopy;
1561
1562 prefixStr = (jstring) ((*jnienv)->GetObjectArrayElement(jnienv,
1563 prefixArray, i));
1564 errorOccurred = checkForThrowable(jnienv);
1565 jplis_assert(!errorOccurred);
1566 if (errorOccurred) {
1567 break;
1568 }
1569 if (prefixStr == NULL) {
1570 continue;
1571 }
1572
1573 prefixLen = (*jnienv)->GetStringUTFLength(jnienv, prefixStr);
1574 errorOccurred = checkForThrowable(jnienv);
1575 jplis_assert(!errorOccurred);
1576 if (errorOccurred) {
1577 break;
1578 }
1579
1580 if (prefixLen > 0) {
1581 prefix = (*jnienv)->GetStringUTFChars(jnienv, prefixStr, &isCopy);
1582 errorOccurred = checkForThrowable(jnienv);
1583 jplis_assert(!errorOccurred);
1584 if (!errorOccurred && prefix != NULL) {
1585 prefixes[inx] = prefix;
1586 originForRelease[inx] = prefixStr;
1587 ++inx;
1588 }
1589 }
1590 }
1591
1592 err = (*jvmtienv)->SetNativeMethodPrefixes(jvmtienv, inx, (char**)prefixes);
1593 /* can be called from any phase */
1594 jplis_assert(err == JVMTI_ERROR_NONE);
1595
1596 for (i = 0; i < inx; i++) {
1597 (*jnienv)->ReleaseStringUTFChars(jnienv, originForRelease[i], prefixes[i]);
1598 }
1599 }
1600 deallocate(jvmtienv, (void*)prefixes);
1601 deallocate(jvmtienv, (void*)originForRelease);
1602 }
1603}
1604