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