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