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