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. */ 59JPLISAgent * 60allocateJPLISAgent(jvmtiEnv * jvmtiEnv); 61 62/* Initializes an already-allocated JPLIS agent data structure. */ 63JPLISInitializationError 64initializeJPLISAgent( JPLISAgent * agent, 65 JavaVM * vm, 66 jvmtiEnv * jvmtienv); 67/* De-allocates a JPLIS agent data structure. Only used in partial-failure cases at startup; 68 * in normal usage the JPLIS agent lives forever 69 */ 70void 71deallocateJPLISAgent( jvmtiEnv * jvmtienv, 72 JPLISAgent * agent); 73 74/* Does one-time work to interrogate the JVM about capabilities and cache the answers. */ 75void 76checkCapabilities(JPLISAgent * agent); 77 78/* Takes the elements of the command string (agent class name and options string) and 79 * create java strings for them. 80 * Returns true if a classname was found. Makes no promises beyond the textual; says nothing about whether 81 * the class exists or can be loaded. 82 * If return value is true, sets outputClassname to a non-NULL local JNI reference. 83 * If return value is true, sets outputOptionsString either to NULL or to a non-NULL local JNI reference. 84 * If return value is false, neither output parameter is set. 85 */ 86jboolean 87commandStringIntoJavaStrings( JNIEnv * jnienv, 88 const char * classname, 89 const char * optionsString, 90 jstring * outputClassname, 91 jstring * outputOptionsString); 92 93/* Start one Java agent from the supplied parameters. 94 * Most of the logic lives in a helper function that lives over in Java code-- 95 * we pass parameters out to Java and use our own Java helper to actually 96 * load the agent and call the premain. 97 * Returns true if the Java agent class is loaded and the premain/agentmain method completes 98 * with no exceptions, false otherwise. 99 */ 100jboolean 101invokeJavaAgentMainMethod( JNIEnv * jnienv, 102 jobject instrumentationImpl, 103 jmethodID agentMainMethod, 104 jstring className, 105 jstring optionsString); 106 107/* Once we have loaded the Java agent and called the premain, 108 * we can release the copies we have been keeping of the command line 109 * data (agent class name and option strings). 110 */ 111void 112deallocateCommandLineData(JPLISAgent * agent); 113 114/* 115 * Common support for various class list fetchers. 116 */ 117typedef jvmtiError (*ClassListFetcher) 118 ( jvmtiEnv * jvmtiEnv, 119 jobject classLoader, 120 jint * classCount, 121 jclass ** classes); 122 123/* Fetcher that ignores the class loader parameter, and uses the JVMTI to get a list of all classes. 124 * Returns a jvmtiError according to the underlying JVMTI service. 125 */ 126jvmtiError 127getAllLoadedClassesClassListFetcher( jvmtiEnv * jvmtiEnv, 128 jobject classLoader, 129 jint * classCount, 130 jclass ** classes); 131 132/* Fetcher that uses the class loader parameter, and uses the JVMTI to get a list of all classes 133 * for which the supplied loader is the initiating loader. 134 * Returns a jvmtiError according to the underlying JVMTI service. 135 */ 136jvmtiError 137getInitiatedClassesClassListFetcher( jvmtiEnv * jvmtiEnv, 138 jobject classLoader, 139 jint * classCount, 140 jclass ** classes); 141 142/* 143 * Common guts for two native methods, which are the same except for the policy for fetching 144 * the list of classes. 145 * Either returns a local JNI reference to an array of references to java.lang.Class. 146 * Can throw, if it does will alter the JNIEnv with an outstanding exception. 147 */ 148jobjectArray 149commonGetClassList( JNIEnv * jnienv, 150 JPLISAgent * agent, 151 jobject classLoader, 152 ClassListFetcher fetcher); 153 154 155/* 156 * Misc. utilities. 157 */ 158 159/* Checked exception mapper used by the redefine classes implementation. 160 * Allows ClassNotFoundException or UnmodifiableClassException; maps others 161 * to InternalError. Can return NULL in an error case. 162 */ 163jthrowable 164redefineClassMapper( JNIEnv * jnienv, 165 jthrowable throwableToMap); 166 167/* Turns a buffer of jclass * into a Java array whose elements are java.lang.Class. 168 * Can throw, if it does will alter the JNIEnv with an outstanding exception. 169 */ 170jobjectArray 171getObjectArrayFromClasses(JNIEnv* jnienv, jclass* classes, jint classCount); 172 173 174JPLISEnvironment * 175getJPLISEnvironment(jvmtiEnv * jvmtienv) { 176 JPLISEnvironment * environment = NULL; 177 jvmtiError jvmtierror = JVMTI_ERROR_NONE; 178 179 jvmtierror = (*jvmtienv)->GetEnvironmentLocalStorage( 180 jvmtienv, 181 (void**)&environment); 182 /* can be called from any phase */ 183 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 184 185 if (jvmtierror == JVMTI_ERROR_NONE) { 186 jplis_assert(environment != NULL); 187 jplis_assert(environment->mJVMTIEnv == jvmtienv); 188 } else { 189 environment = NULL; 190 } 191 return environment; 192} 193 194/* 195 * OnLoad processing code. 196 */ 197 198/* 199 * Creates a new JPLISAgent. 200 * Returns error if the agent cannot be created and initialized. 201 * The JPLISAgent* pointed to by agent_ptr is set to the new broker, 202 * or NULL if an error has occurred. 203 */ 204JPLISInitializationError 205createNewJPLISAgent(JavaVM * vm, JPLISAgent **agent_ptr) { 206 JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE; 207 jvmtiEnv * jvmtienv = NULL; 208 jint jnierror = JNI_OK; 209 210 *agent_ptr = NULL; 211 jnierror = (*vm)->GetEnv( vm, 212 (void **) &jvmtienv, 213 JVMTI_VERSION_1_1); 214 if ( jnierror != JNI_OK ) { 215 initerror = JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT; 216 } else { 217 JPLISAgent * agent = allocateJPLISAgent(jvmtienv); 218 if ( agent == NULL ) { 219 initerror = JPLIS_INIT_ERROR_ALLOCATION_FAILURE; 220 } else { 221 initerror = initializeJPLISAgent( agent, 222 vm, 223 jvmtienv); 224 if ( initerror == JPLIS_INIT_ERROR_NONE ) { 225 *agent_ptr = agent; 226 } else { 227 deallocateJPLISAgent(jvmtienv, agent); 228 } 229 } 230 231 /* don't leak envs */ 232 if ( initerror != JPLIS_INIT_ERROR_NONE ) { 233 jvmtiError jvmtierror = (*jvmtienv)->DisposeEnvironment(jvmtienv); 234 /* can be called from any phase */ 235 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 236 } 237 } 238 239 return initerror; 240} 241 242/* 243 * Allocates a JPLISAgent. Returns NULL if it cannot be allocated 244 */ 245JPLISAgent * 246allocateJPLISAgent(jvmtiEnv * jvmtienv) { 247 return (JPLISAgent *) allocate( jvmtienv, 248 sizeof(JPLISAgent)); 249} 250 251JPLISInitializationError 252initializeJPLISAgent( JPLISAgent * agent, 253 JavaVM * vm, 254 jvmtiEnv * jvmtienv) { 255 jvmtiError jvmtierror = JVMTI_ERROR_NONE; 256 jvmtiPhase phase; 257 258 agent->mJVM = vm; 259 agent->mNormalEnvironment.mJVMTIEnv = jvmtienv; 260 agent->mNormalEnvironment.mAgent = agent; 261 agent->mNormalEnvironment.mIsRetransformer = JNI_FALSE; 262 agent->mRetransformEnvironment.mJVMTIEnv = NULL; /* NULL until needed */ 263 agent->mRetransformEnvironment.mAgent = agent; 264 agent->mRetransformEnvironment.mIsRetransformer = JNI_FALSE; /* JNI_FALSE until mJVMTIEnv is set */ 265 agent->mAgentmainCaller = NULL; 266 agent->mInstrumentationImpl = NULL; 267 agent->mPremainCaller = NULL; 268 agent->mTransform = NULL; 269 agent->mRedefineAvailable = JNI_FALSE; /* assume no for now */ 270 agent->mRedefineAdded = JNI_FALSE; 271 agent->mNativeMethodPrefixAvailable = JNI_FALSE; /* assume no for now */ 272 agent->mNativeMethodPrefixAdded = JNI_FALSE; 273 agent->mAgentClassName = NULL; 274 agent->mOptionsString = NULL; 275 agent->mJarfile = NULL; 276 277 /* make sure we can recover either handle in either direction. 278 * the agent has a ref to the jvmti; make it mutual 279 */ 280 jvmtierror = (*jvmtienv)->SetEnvironmentLocalStorage( 281 jvmtienv, 282 &(agent->mNormalEnvironment)); 283 /* can be called from any phase */ 284 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 285 286 /* check what capabilities are available */ 287 checkCapabilities(agent); 288 289 /* check phase - if live phase then we don't need the VMInit event */ 290 jvmtierror = (*jvmtienv)->GetPhase(jvmtienv, &phase); 291 /* can be called from any phase */ 292 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 293 if (phase == JVMTI_PHASE_LIVE) { 294 return JPLIS_INIT_ERROR_NONE; 295 } 296 297 if (phase != JVMTI_PHASE_ONLOAD) { 298 /* called too early or called too late; either way bail out */ 299 return JPLIS_INIT_ERROR_FAILURE; 300 } 301 302 /* now turn on the VMInit event */ 303 if ( jvmtierror == JVMTI_ERROR_NONE ) { 304 jvmtiEventCallbacks callbacks; 305 memset(&callbacks, 0, sizeof(callbacks)); 306 callbacks.VMInit = &eventHandlerVMInit; 307 308 jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv, 309 &callbacks, 310 sizeof(callbacks)); 311 check_phase_ret_blob(jvmtierror, JPLIS_INIT_ERROR_FAILURE); 312 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 313 } 314 315 if ( jvmtierror == JVMTI_ERROR_NONE ) { 316 jvmtierror = (*jvmtienv)->SetEventNotificationMode( 317 jvmtienv, 318 JVMTI_ENABLE, 319 JVMTI_EVENT_VM_INIT, 320 NULL /* all threads */); 321 check_phase_ret_blob(jvmtierror, JPLIS_INIT_ERROR_FAILURE); 322 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 323 } 324 325 return (jvmtierror == JVMTI_ERROR_NONE)? JPLIS_INIT_ERROR_NONE : JPLIS_INIT_ERROR_FAILURE; 326} 327 328void 329deallocateJPLISAgent(jvmtiEnv * jvmtienv, JPLISAgent * agent) { 330 deallocate(jvmtienv, agent); 331} 332 333 334JPLISInitializationError 335recordCommandLineData( JPLISAgent * agent, 336 const char * agentClassName, 337 const char * optionsString ) { 338 JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE; 339 char * ourCopyOfAgentClassName = NULL; 340 char * ourCopyOfOptionsString = NULL; 341 342 /* if no actual params, bail out now */ 343 if ((agentClassName == NULL) || (*agentClassName == 0)) { 344 initerror = JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED; 345 } else { 346 ourCopyOfAgentClassName = allocate(jvmti(agent), strlen(agentClassName)+1); 347 if (ourCopyOfAgentClassName == NULL) { 348 initerror = JPLIS_INIT_ERROR_ALLOCATION_FAILURE; 349 } else { 350 if (optionsString != NULL) { 351 ourCopyOfOptionsString = allocate(jvmti(agent), strlen(optionsString)+1); 352 if (ourCopyOfOptionsString == NULL) { 353 deallocate(jvmti(agent), ourCopyOfAgentClassName); 354 initerror = JPLIS_INIT_ERROR_ALLOCATION_FAILURE; 355 } 356 } 357 } 358 } 359 360 if (initerror == JPLIS_INIT_ERROR_NONE) { 361 strcpy(ourCopyOfAgentClassName, agentClassName); 362 if (optionsString != NULL) { 363 strcpy(ourCopyOfOptionsString, optionsString); 364 } 365 agent->mAgentClassName = ourCopyOfAgentClassName; 366 agent->mOptionsString = ourCopyOfOptionsString; 367 } 368 369 return initerror; 370} 371 372/* 373 * VMInit processing code. 374 */ 375 376 377/* 378 * If this call fails, the JVM launch will ultimately be aborted, 379 * so we don't have to be super-careful to clean up in partial failure 380 * cases. 381 */ 382jboolean 383processJavaStart( JPLISAgent * agent, 384 JNIEnv * jnienv) { 385 jboolean result; 386 387 /* 388 * OK, Java is up now. We can start everything that needs Java. 389 */ 390 391 /* 392 * First make our 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 435jboolean 436startJavaAgent( 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 462void 463deallocateCommandLineData( 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 */ 476jboolean 477createInstrumentationImpl( 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 567jboolean 568commandStringIntoJavaStrings( 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 598jboolean 599invokeJavaAgentMainMethod( 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 622jboolean 623setLivePhaseEventHandlers( 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 */ 669void 670checkCapabilities(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 */ 694void 695enableNativeMethodPrefixCapability(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 */ 712void 713addNativeMethodPrefixCapability(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 */ 729void 730addOriginalMethodOrderCapability(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 */ 747void 748addRedefineClassesCapability(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 774static jobject 775getModuleObject(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 free((void*)pkg_name_buf); 794 check_phase_ret_blob(err, NULL); 795 jplis_assert_msg(err == JVMTI_ERROR_NONE, "error in the JVMTI GetNamedModule"); 796 797 return moduleObject; 798} 799 800/* 801 * Support for the JVMTI callbacks 802 */ 803 804void 805transformClassFile( JPLISAgent * agent, 806 JNIEnv * jnienv, 807 jobject loaderObject, 808 const char* name, 809 jclass classBeingRedefined, 810 jobject protectionDomain, 811 jint class_data_len, 812 const unsigned char* class_data, 813 jint* new_class_data_len, 814 unsigned char** new_class_data, 815 jboolean is_retransformer) { 816 jboolean errorOutstanding = JNI_FALSE; 817 jstring classNameStringObject = NULL; 818 jarray classFileBufferObject = NULL; 819 jarray transformedBufferObject = NULL; 820 jsize transformedBufferSize = 0; 821 unsigned char * resultBuffer = NULL; 822 jboolean shouldRun = JNI_FALSE; 823 824 /* only do this if we aren't already in the middle of processing a class on this thread */ 825 shouldRun = tryToAcquireReentrancyToken( 826 jvmti(agent), 827 NULL); /* this thread */ 828 829 if ( shouldRun ) { 830 /* first marshall all the parameters */ 831 classNameStringObject = (*jnienv)->NewStringUTF(jnienv, 832 name); 833 errorOutstanding = checkForAndClearThrowable(jnienv); 834 jplis_assert_msg(!errorOutstanding, "can't create name string"); 835 836 if ( !errorOutstanding ) { 837 classFileBufferObject = (*jnienv)->NewByteArray(jnienv, 838 class_data_len); 839 errorOutstanding = checkForAndClearThrowable(jnienv); 840 jplis_assert_msg(!errorOutstanding, "can't create byte array"); 841 } 842 843 if ( !errorOutstanding ) { 844 jbyte * typedBuffer = (jbyte *) class_data; /* nasty cast, dumb JNI interface, const missing */ 845 /* The sign cast is safe. The const cast is dumb. */ 846 (*jnienv)->SetByteArrayRegion( jnienv, 847 classFileBufferObject, 848 0, 849 class_data_len, 850 typedBuffer); 851 errorOutstanding = checkForAndClearThrowable(jnienv); 852 jplis_assert_msg(!errorOutstanding, "can't set byte array region"); 853 } 854 855 /* now call the JPL agents to do the transforming */ 856 /* potential future optimization: may want to skip this if there are none */ 857 if ( !errorOutstanding ) { 858 jobject moduleObject = NULL; 859 860 if (classBeingRedefined == NULL) { 861 moduleObject = getModuleObject(jvmti(agent), loaderObject, name); 862 } else { 863 // Redefine or retransform, InstrumentationImpl.transform() will use 864 // classBeingRedefined.getModule() to get the module. 865 } 866 jplis_assert(agent->mInstrumentationImpl != NULL); 867 jplis_assert(agent->mTransform != NULL); 868 transformedBufferObject = (*jnienv)->CallObjectMethod( 869 jnienv, 870 agent->mInstrumentationImpl, 871 agent->mTransform, 872 moduleObject, 873 loaderObject, 874 classNameStringObject, 875 classBeingRedefined, 876 protectionDomain, 877 classFileBufferObject, 878 is_retransformer); 879 errorOutstanding = checkForAndClearThrowable(jnienv); 880 jplis_assert_msg(!errorOutstanding, "transform method call failed"); 881 } 882 883 /* Finally, unmarshall the parameters (if someone touched the buffer, tell the JVM) */ 884 if ( !errorOutstanding ) { 885 if ( transformedBufferObject != NULL ) { 886 transformedBufferSize = (*jnienv)->GetArrayLength( jnienv, 887 transformedBufferObject); 888 errorOutstanding = checkForAndClearThrowable(jnienv); 889 jplis_assert_msg(!errorOutstanding, "can't get array length"); 890 891 if ( !errorOutstanding ) { 892 /* allocate the response buffer with the JVMTI allocate call. 893 * This is what the JVMTI spec says to do for Class File Load hook responses 894 */ 895 jvmtiError allocError = (*(jvmti(agent)))->Allocate(jvmti(agent), 896 transformedBufferSize, 897 &resultBuffer); 898 errorOutstanding = (allocError != JVMTI_ERROR_NONE); 899 jplis_assert_msg(!errorOutstanding, "can't allocate result buffer"); 900 } 901 902 if ( !errorOutstanding ) { 903 (*jnienv)->GetByteArrayRegion( jnienv, 904 transformedBufferObject, 905 0, 906 transformedBufferSize, 907 (jbyte *) resultBuffer); 908 errorOutstanding = checkForAndClearThrowable(jnienv); 909 jplis_assert_msg(!errorOutstanding, "can't get byte array region"); 910 911 /* in this case, we will not return the buffer to the JVMTI, 912 * so we need to deallocate it ourselves 913 */ 914 if ( errorOutstanding ) { 915 deallocate( jvmti(agent), 916 (void*)resultBuffer); 917 } 918 } 919 920 if ( !errorOutstanding ) { 921 *new_class_data_len = (transformedBufferSize); 922 *new_class_data = resultBuffer; 923 } 924 } 925 } 926 927 /* release the token */ 928 releaseReentrancyToken( jvmti(agent), 929 NULL); /* this thread */ 930 931 } 932 933 return; 934} 935 936/* 937 * Misc. internal utilities. 938 */ 939 940/* 941 * The only checked exceptions we can throw are ClassNotFoundException and 942 * UnmodifiableClassException. All others map to InternalError. 943 */ 944jthrowable 945redefineClassMapper( JNIEnv * jnienv, 946 jthrowable throwableToMap) { 947 jthrowable mappedThrowable = NULL; 948 949 jplis_assert(isSafeForJNICalls(jnienv)); 950 jplis_assert(!isUnchecked(jnienv, throwableToMap)); 951 952 if ( isInstanceofClassName( jnienv, 953 throwableToMap, 954 "java/lang/ClassNotFoundException") ) { 955 mappedThrowable = throwableToMap; 956 } else { 957 if ( isInstanceofClassName( jnienv, 958 throwableToMap, 959 "java/lang/instrument/UnmodifiableClassException")) { 960 mappedThrowable = throwableToMap; 961 } else { 962 jstring message = NULL; 963 964 message = getMessageFromThrowable(jnienv, throwableToMap); 965 mappedThrowable = createInternalError(jnienv, message); 966 } 967 } 968 969 jplis_assert(isSafeForJNICalls(jnienv)); 970 return mappedThrowable; 971} 972 973jobjectArray 974getObjectArrayFromClasses(JNIEnv* jnienv, jclass* classes, jint classCount) { 975 jclass classArrayClass = NULL; 976 jobjectArray localArray = NULL; 977 jint classIndex = 0; 978 jboolean errorOccurred = JNI_FALSE; 979 980 /* get the class array class */ 981 classArrayClass = (*jnienv)->FindClass(jnienv, "java/lang/Class"); 982 errorOccurred = checkForThrowable(jnienv); 983 984 if (!errorOccurred) { 985 jplis_assert_msg(classArrayClass != NULL, "FindClass returned null class"); 986 987 /* create the array for the classes */ 988 localArray = (*jnienv)->NewObjectArray(jnienv, classCount, classArrayClass, NULL); 989 errorOccurred = checkForThrowable(jnienv); 990 991 if (!errorOccurred) { 992 jplis_assert_msg(localArray != NULL, "NewObjectArray returned null array"); 993 994 /* now copy refs to all the classes and put them into the array */ 995 for (classIndex = 0; classIndex < classCount; classIndex++) { 996 /* put class into array */ 997 (*jnienv)->SetObjectArrayElement(jnienv, localArray, classIndex, classes[classIndex]); 998 errorOccurred = checkForThrowable(jnienv); 999 1000 if (errorOccurred) { 1001 localArray = NULL; 1002 break; 1003 } 1004 } 1005 } 1006 } 1007 1008 return localArray; 1009} 1010 1011 1012/* Return the environment with the retransformation capability. 1013 * Create it if it doesn't exist. 1014 * Return NULL if it can't be created. 1015 */ 1016jvmtiEnv * 1017retransformableEnvironment(JPLISAgent * agent) { 1018 jvmtiEnv * retransformerEnv = NULL; 1019 jint jnierror = JNI_OK; 1020 jvmtiCapabilities desiredCapabilities; 1021 jvmtiEventCallbacks callbacks; 1022 jvmtiError jvmtierror; 1023 1024 if (agent->mRetransformEnvironment.mJVMTIEnv != NULL) { 1025 return agent->mRetransformEnvironment.mJVMTIEnv; 1026 } 1027 jnierror = (*agent->mJVM)->GetEnv( agent->mJVM, 1028 (void **) &retransformerEnv, 1029 JVMTI_VERSION_1_1); 1030 if ( jnierror != JNI_OK ) { 1031 return NULL; 1032 } 1033 jvmtierror = (*retransformerEnv)->GetCapabilities(retransformerEnv, &desiredCapabilities); 1034 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 1035 desiredCapabilities.can_retransform_classes = 1; 1036 if (agent->mNativeMethodPrefixAdded) { 1037 desiredCapabilities.can_set_native_method_prefix = 1; 1038 } 1039 1040 jvmtierror = (*retransformerEnv)->AddCapabilities(retransformerEnv, &desiredCapabilities); 1041 if (jvmtierror != JVMTI_ERROR_NONE) { 1042 /* cannot get the capability, dispose of the retransforming environment */ 1043 jvmtierror = (*retransformerEnv)->DisposeEnvironment(retransformerEnv); 1044 jplis_assert(jvmtierror == JVMTI_ERROR_NOT_AVAILABLE); 1045 return NULL; 1046 } 1047 memset(&callbacks, 0, sizeof(callbacks)); 1048 callbacks.ClassFileLoadHook = &eventHandlerClassFileLoadHook; 1049 1050 jvmtierror = (*retransformerEnv)->SetEventCallbacks(retransformerEnv, 1051 &callbacks, 1052 sizeof(callbacks)); 1053 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 1054 if (jvmtierror == JVMTI_ERROR_NONE) { 1055 // install the retransforming environment 1056 agent->mRetransformEnvironment.mJVMTIEnv = retransformerEnv; 1057 agent->mRetransformEnvironment.mIsRetransformer = JNI_TRUE; 1058 1059 // Make it for ClassFileLoadHook handling 1060 jvmtierror = (*retransformerEnv)->SetEnvironmentLocalStorage( 1061 retransformerEnv, 1062 &(agent->mRetransformEnvironment)); 1063 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 1064 if (jvmtierror == JVMTI_ERROR_NONE) { 1065 return retransformerEnv; 1066 } 1067 } 1068 return NULL; 1069} 1070 1071 1072/* 1073 * Underpinnings for native methods 1074 */ 1075 1076jboolean 1077isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz) { 1078 jvmtiEnv * jvmtienv = jvmti(agent); 1079 jvmtiError jvmtierror; 1080 jboolean is_modifiable = JNI_FALSE; 1081 1082 jvmtierror = (*jvmtienv)->IsModifiableClass( jvmtienv, 1083 clazz, 1084 &is_modifiable); 1085 check_phase_ret_false(jvmtierror); 1086 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 1087 1088 return is_modifiable; 1089} 1090 1091jboolean 1092isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent) { 1093 return agent->mRetransformEnvironment.mIsRetransformer; 1094} 1095 1096void 1097setHasRetransformableTransformers(JNIEnv * jnienv, JPLISAgent * agent, jboolean has) { 1098 jvmtiEnv * retransformerEnv = retransformableEnvironment(agent); 1099 jvmtiError jvmtierror; 1100 1101 jplis_assert(retransformerEnv != NULL); 1102 jvmtierror = (*retransformerEnv)->SetEventNotificationMode( 1103 retransformerEnv, 1104 has? JVMTI_ENABLE : JVMTI_DISABLE, 1105 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, 1106 NULL /* all threads */); 1107 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 1108} 1109 1110void 1111retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes) { 1112 jvmtiEnv * retransformerEnv = retransformableEnvironment(agent); 1113 jboolean errorOccurred = JNI_FALSE; 1114 jvmtiError errorCode = JVMTI_ERROR_NONE; 1115 jsize numClasses = 0; 1116 jclass * classArray = NULL; 1117 1118 /* This is supposed to be checked by caller, but just to be sure */ 1119 if (retransformerEnv == NULL) { 1120 jplis_assert(retransformerEnv != NULL); 1121 errorOccurred = JNI_TRUE; 1122 errorCode = JVMTI_ERROR_MUST_POSSESS_CAPABILITY; 1123 } 1124 1125 /* This was supposed to be checked by caller too */ 1126 if (!errorOccurred && classes == NULL) { 1127 jplis_assert(classes != NULL); 1128 errorOccurred = JNI_TRUE; 1129 errorCode = JVMTI_ERROR_NULL_POINTER; 1130 } 1131 1132 if (!errorOccurred) { 1133 numClasses = (*jnienv)->GetArrayLength(jnienv, classes); 1134 errorOccurred = checkForThrowable(jnienv); 1135 jplis_assert(!errorOccurred); 1136 1137 if (!errorOccurred && numClasses == 0) { 1138 jplis_assert(numClasses != 0); 1139 errorOccurred = JNI_TRUE; 1140 errorCode = JVMTI_ERROR_NULL_POINTER; 1141 } 1142 } 1143 1144 if (!errorOccurred) { 1145 classArray = (jclass *) allocate(retransformerEnv, 1146 numClasses * sizeof(jclass)); 1147 errorOccurred = (classArray == NULL); 1148 jplis_assert(!errorOccurred); 1149 if (errorOccurred) { 1150 errorCode = JVMTI_ERROR_OUT_OF_MEMORY; 1151 } 1152 } 1153 1154 if (!errorOccurred) { 1155 jint index; 1156 for (index = 0; index < numClasses; index++) { 1157 classArray[index] = (*jnienv)->GetObjectArrayElement(jnienv, classes, index); 1158 errorOccurred = checkForThrowable(jnienv); 1159 jplis_assert(!errorOccurred); 1160 if (errorOccurred) { 1161 break; 1162 } 1163 1164 if (classArray[index] == NULL) { 1165 jplis_assert(classArray[index] != NULL); 1166 errorOccurred = JNI_TRUE; 1167 errorCode = JVMTI_ERROR_NULL_POINTER; 1168 break; 1169 } 1170 } 1171 } 1172 1173 if (!errorOccurred) { 1174 errorCode = (*retransformerEnv)->RetransformClasses(retransformerEnv, 1175 numClasses, classArray); 1176 errorOccurred = (errorCode != JVMTI_ERROR_NONE); 1177 } 1178 1179 /* Give back the buffer if we allocated it. Throw any exceptions after. 1180 */ 1181 if (classArray != NULL) { 1182 deallocate(retransformerEnv, (void*)classArray); 1183 } 1184 1185 if (errorCode != JVMTI_ERROR_NONE) { 1186 createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode); 1187 } 1188 1189 mapThrownThrowableIfNecessary(jnienv, redefineClassMapper); 1190} 1191 1192/* 1193 * Java code must not call this with a null list or a zero-length list. 1194 */ 1195void 1196redefineClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classDefinitions) { 1197 jvmtiEnv* jvmtienv = jvmti(agent); 1198 jboolean errorOccurred = JNI_FALSE; 1199 jclass classDefClass = NULL; 1200 jmethodID getDefinitionClassMethodID = NULL; 1201 jmethodID getDefinitionClassFileMethodID = NULL; 1202 jvmtiClassDefinition* classDefs = NULL; 1203 jbyteArray* targetFiles = NULL; 1204 jsize numDefs = 0; 1205 1206 jplis_assert(classDefinitions != NULL); 1207 1208 numDefs = (*jnienv)->GetArrayLength(jnienv, classDefinitions); 1209 errorOccurred = checkForThrowable(jnienv); 1210 jplis_assert(!errorOccurred); 1211 1212 if (!errorOccurred) { 1213 jplis_assert(numDefs > 0); 1214 /* get method IDs for methods to call on class definitions */ 1215 classDefClass = (*jnienv)->FindClass(jnienv, "java/lang/instrument/ClassDefinition"); 1216 errorOccurred = checkForThrowable(jnienv); 1217 jplis_assert(!errorOccurred); 1218 } 1219 1220 if (!errorOccurred) { 1221 getDefinitionClassMethodID = (*jnienv)->GetMethodID( jnienv, 1222 classDefClass, 1223 "getDefinitionClass", 1224 "()Ljava/lang/Class;"); 1225 errorOccurred = checkForThrowable(jnienv); 1226 jplis_assert(!errorOccurred); 1227 } 1228 1229 if (!errorOccurred) { 1230 getDefinitionClassFileMethodID = (*jnienv)->GetMethodID( jnienv, 1231 classDefClass, 1232 "getDefinitionClassFile", 1233 "()[B"); 1234 errorOccurred = checkForThrowable(jnienv); 1235 jplis_assert(!errorOccurred); 1236 } 1237 1238 if (!errorOccurred) { 1239 classDefs = (jvmtiClassDefinition *) allocate( 1240 jvmtienv, 1241 numDefs * sizeof(jvmtiClassDefinition)); 1242 errorOccurred = (classDefs == NULL); 1243 jplis_assert(!errorOccurred); 1244 if ( errorOccurred ) { 1245 createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY); 1246 } 1247 1248 else { 1249 /* 1250 * We have to save the targetFile values that we compute so 1251 * that we can release the class_bytes arrays that are 1252 * returned by GetByteArrayElements(). In case of a JNI 1253 * error, we can't (easily) recompute the targetFile values 1254 * and we still want to free any memory we allocated. 1255 */ 1256 targetFiles = (jbyteArray *) allocate(jvmtienv, 1257 numDefs * sizeof(jbyteArray)); 1258 errorOccurred = (targetFiles == NULL); 1259 jplis_assert(!errorOccurred); 1260 if ( errorOccurred ) { 1261 deallocate(jvmtienv, (void*)classDefs); 1262 createAndThrowThrowableFromJVMTIErrorCode(jnienv, 1263 JVMTI_ERROR_OUT_OF_MEMORY); 1264 } 1265 else { 1266 jint i, j; 1267 1268 // clear classDefs so we can correctly free memory during errors 1269 memset(classDefs, 0, numDefs * sizeof(jvmtiClassDefinition)); 1270 1271 for (i = 0; i < numDefs; i++) { 1272 jclass classDef = NULL; 1273 1274 classDef = (*jnienv)->GetObjectArrayElement(jnienv, classDefinitions, i); 1275 errorOccurred = checkForThrowable(jnienv); 1276 jplis_assert(!errorOccurred); 1277 if (errorOccurred) { 1278 break; 1279 } 1280 1281 classDefs[i].klass = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassMethodID); 1282 errorOccurred = checkForThrowable(jnienv); 1283 jplis_assert(!errorOccurred); 1284 if (errorOccurred) { 1285 break; 1286 } 1287 1288 targetFiles[i] = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassFileMethodID); 1289 errorOccurred = checkForThrowable(jnienv); 1290 jplis_assert(!errorOccurred); 1291 if (errorOccurred) { 1292 break; 1293 } 1294 1295 classDefs[i].class_byte_count = (*jnienv)->GetArrayLength(jnienv, targetFiles[i]); 1296 errorOccurred = checkForThrowable(jnienv); 1297 jplis_assert(!errorOccurred); 1298 if (errorOccurred) { 1299 break; 1300 } 1301 1302 /* 1303 * Allocate class_bytes last so we don't have to free 1304 * memory on a partial row error. 1305 */ 1306 classDefs[i].class_bytes = (unsigned char*)(*jnienv)->GetByteArrayElements(jnienv, targetFiles[i], NULL); 1307 errorOccurred = checkForThrowable(jnienv); 1308 jplis_assert(!errorOccurred); 1309 if (errorOccurred) { 1310 break; 1311 } 1312 } 1313 1314 if (!errorOccurred) { 1315 jvmtiError errorCode = JVMTI_ERROR_NONE; 1316 errorCode = (*jvmtienv)->RedefineClasses(jvmtienv, numDefs, classDefs); 1317 if (errorCode == JVMTI_ERROR_WRONG_PHASE) { 1318 /* insulate caller from the wrong phase error */ 1319 errorCode = JVMTI_ERROR_NONE; 1320 } else { 1321 errorOccurred = (errorCode != JVMTI_ERROR_NONE); 1322 if ( errorOccurred ) { 1323 createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode); 1324 } 1325 } 1326 } 1327 1328 /* 1329 * Cleanup memory that we allocated above. If we had a 1330 * JNI error, a JVM/TI error or no errors, index 'i' 1331 * tracks how far we got in processing the classDefs 1332 * array. Note: ReleaseByteArrayElements() is safe to 1333 * call with a JNI exception pending. 1334 */ 1335 for (j = 0; j < i; j++) { 1336 if ((jbyte *)classDefs[j].class_bytes != NULL) { 1337 (*jnienv)->ReleaseByteArrayElements(jnienv, 1338 targetFiles[j], (jbyte *)classDefs[j].class_bytes, 1339 0 /* copy back and free */); 1340 /* 1341 * Only check for error if we didn't already have one 1342 * so we don't overwrite errorOccurred. 1343 */ 1344 if (!errorOccurred) { 1345 errorOccurred = checkForThrowable(jnienv); 1346 jplis_assert(!errorOccurred); 1347 } 1348 } 1349 } 1350 deallocate(jvmtienv, (void*)targetFiles); 1351 deallocate(jvmtienv, (void*)classDefs); 1352 } 1353 } 1354 } 1355 1356 mapThrownThrowableIfNecessary(jnienv, redefineClassMapper); 1357} 1358 1359/* Cheesy sharing. ClassLoader may be null. */ 1360jobjectArray 1361commonGetClassList( JNIEnv * jnienv, 1362 JPLISAgent * agent, 1363 jobject classLoader, 1364 ClassListFetcher fetcher) { 1365 jvmtiEnv * jvmtienv = jvmti(agent); 1366 jboolean errorOccurred = JNI_FALSE; 1367 jvmtiError jvmtierror = JVMTI_ERROR_NONE; 1368 jint classCount = 0; 1369 jclass * classes = NULL; 1370 jobjectArray localArray = NULL; 1371 1372 /* retrieve the classes from the JVMTI agent */ 1373 jvmtierror = (*fetcher)( jvmtienv, 1374 classLoader, 1375 &classCount, 1376 &classes); 1377 check_phase_ret_blob(jvmtierror, localArray); 1378 errorOccurred = (jvmtierror != JVMTI_ERROR_NONE); 1379 jplis_assert(!errorOccurred); 1380 1381 if ( errorOccurred ) { 1382 createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror); 1383 } else { 1384 localArray = getObjectArrayFromClasses( jnienv, 1385 classes, 1386 classCount); 1387 errorOccurred = checkForThrowable(jnienv); 1388 jplis_assert(!errorOccurred); 1389 1390 /* do this whether or not we saw a problem */ 1391 deallocate(jvmtienv, (void*)classes); 1392 } 1393 1394 mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper); 1395 return localArray; 1396 1397} 1398 1399jvmtiError 1400getAllLoadedClassesClassListFetcher( jvmtiEnv * jvmtienv, 1401 jobject classLoader, 1402 jint * classCount, 1403 jclass ** classes) { 1404 return (*jvmtienv)->GetLoadedClasses(jvmtienv, classCount, classes); 1405} 1406 1407jobjectArray 1408getAllLoadedClasses(JNIEnv * jnienv, JPLISAgent * agent) { 1409 return commonGetClassList( jnienv, 1410 agent, 1411 NULL, 1412 getAllLoadedClassesClassListFetcher); 1413} 1414 1415jvmtiError 1416getInitiatedClassesClassListFetcher( jvmtiEnv * jvmtienv, 1417 jobject classLoader, 1418 jint * classCount, 1419 jclass ** classes) { 1420 return (*jvmtienv)->GetClassLoaderClasses(jvmtienv, classLoader, classCount, classes); 1421} 1422 1423 1424jobjectArray 1425getInitiatedClasses(JNIEnv * jnienv, JPLISAgent * agent, jobject classLoader) { 1426 return commonGetClassList( jnienv, 1427 agent, 1428 classLoader, 1429 getInitiatedClassesClassListFetcher); 1430} 1431 1432jlong 1433getObjectSize(JNIEnv * jnienv, JPLISAgent * agent, jobject objectToSize) { 1434 jvmtiEnv * jvmtienv = jvmti(agent); 1435 jlong objectSize = -1; 1436 jvmtiError jvmtierror = JVMTI_ERROR_NONE; 1437 1438 jvmtierror = (*jvmtienv)->GetObjectSize(jvmtienv, objectToSize, &objectSize); 1439 check_phase_ret_0(jvmtierror); 1440 jplis_assert(jvmtierror == JVMTI_ERROR_NONE); 1441 if ( jvmtierror != JVMTI_ERROR_NONE ) { 1442 createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror); 1443 } 1444 1445 mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper); 1446 return objectSize; 1447} 1448 1449void 1450appendToClassLoaderSearch(JNIEnv * jnienv, JPLISAgent * agent, jstring jarFile, jboolean isBootLoader) 1451{ 1452 jvmtiEnv * jvmtienv = jvmti(agent); 1453 jboolean errorOutstanding; 1454 jvmtiError jvmtierror; 1455 const char* utf8Chars; 1456 jsize utf8Len; 1457 jboolean isCopy; 1458 char platformChars[MAXPATHLEN]; 1459 int platformLen; 1460 1461 utf8Len = (*jnienv)->GetStringUTFLength(jnienv, jarFile); 1462 errorOutstanding = checkForAndClearThrowable(jnienv); 1463 1464 if (!errorOutstanding) { 1465 utf8Chars = (*jnienv)->GetStringUTFChars(jnienv, jarFile, &isCopy); 1466 errorOutstanding = checkForAndClearThrowable(jnienv); 1467 1468 if (!errorOutstanding && utf8Chars != NULL) { 1469 /* 1470 * JVMTI spec'ed to use modified UTF8. At this time this is not implemented 1471 * the platform encoding is used. 1472 */ 1473 platformLen = convertUft8ToPlatformString((char*)utf8Chars, utf8Len, platformChars, MAXPATHLEN); 1474 if (platformLen < 0) { 1475 createAndThrowInternalError(jnienv); 1476 return; 1477 } 1478 1479 (*jnienv)->ReleaseStringUTFChars(jnienv, jarFile, utf8Chars); 1480 errorOutstanding = checkForAndClearThrowable(jnienv); 1481 1482 if (!errorOutstanding) { 1483 1484 if (isBootLoader) { 1485 jvmtierror = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, platformChars); 1486 } else { 1487 jvmtierror = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, platformChars); 1488 } 1489 check_phase_ret(jvmtierror); 1490 1491 if ( jvmtierror != JVMTI_ERROR_NONE ) { 1492 createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror); 1493 } 1494 } 1495 } 1496 } 1497 1498 mapThrownThrowableIfNecessary(jnienv, mapAllCheckedToInternalErrorMapper); 1499} 1500 1501/* 1502 * Set the prefixes used to wrap native methods (so they can be instrumented). 1503 * Each transform can set a prefix, any that have been set come in as prefixArray. 1504 * Convert them in native strings in a native array then call JVM TI. 1505 * One a given call, this function handles either the prefixes for retransformable 1506 * transforms or for normal transforms. 1507 */ 1508void 1509setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefixArray, 1510 jboolean isRetransformable) { 1511 jvmtiEnv* jvmtienv; 1512 jvmtiError err = JVMTI_ERROR_NONE; 1513 jsize arraySize; 1514 jboolean errorOccurred = JNI_FALSE; 1515 1516 jplis_assert(prefixArray != NULL); 1517 1518 if (isRetransformable) { 1519 jvmtienv = agent->mRetransformEnvironment.mJVMTIEnv; 1520 } else { 1521 jvmtienv = agent->mNormalEnvironment.mJVMTIEnv; 1522 } 1523 arraySize = (*jnienv)->GetArrayLength(jnienv, prefixArray); 1524 errorOccurred = checkForThrowable(jnienv); 1525 jplis_assert(!errorOccurred); 1526 1527 if (!errorOccurred) { 1528 /* allocate the native to hold the native prefixes */ 1529 const char** prefixes = (const char**) allocate(jvmtienv, 1530 arraySize * sizeof(char*)); 1531 /* since JNI ReleaseStringUTFChars needs the jstring from which the native 1532 * string was allocated, we store them in a parallel array */ 1533 jstring* originForRelease = (jstring*) allocate(jvmtienv, 1534 arraySize * sizeof(jstring)); 1535 errorOccurred = (prefixes == NULL || originForRelease == NULL); 1536 jplis_assert(!errorOccurred); 1537 if ( errorOccurred ) { 1538 createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY); 1539 } 1540 else { 1541 jint inx = 0; 1542 jint i; 1543 for (i = 0; i < arraySize; i++) { 1544 jstring prefixStr = NULL; 1545 const char* prefix; 1546 jsize prefixLen; 1547 jboolean isCopy; 1548 1549 prefixStr = (jstring) ((*jnienv)->GetObjectArrayElement(jnienv, 1550 prefixArray, i)); 1551 errorOccurred = checkForThrowable(jnienv); 1552 jplis_assert(!errorOccurred); 1553 if (errorOccurred) { 1554 break; 1555 } 1556 if (prefixStr == NULL) { 1557 continue; 1558 } 1559 1560 prefixLen = (*jnienv)->GetStringUTFLength(jnienv, prefixStr); 1561 errorOccurred = checkForThrowable(jnienv); 1562 jplis_assert(!errorOccurred); 1563 if (errorOccurred) { 1564 break; 1565 } 1566 1567 if (prefixLen > 0) { 1568 prefix = (*jnienv)->GetStringUTFChars(jnienv, prefixStr, &isCopy); 1569 errorOccurred = checkForThrowable(jnienv); 1570 jplis_assert(!errorOccurred); 1571 if (!errorOccurred && prefix != NULL) { 1572 prefixes[inx] = prefix; 1573 originForRelease[inx] = prefixStr; 1574 ++inx; 1575 } 1576 } 1577 } 1578 1579 err = (*jvmtienv)->SetNativeMethodPrefixes(jvmtienv, inx, (char**)prefixes); 1580 /* can be called from any phase */ 1581 jplis_assert(err == JVMTI_ERROR_NONE); 1582 1583 for (i = 0; i < inx; i++) { 1584 (*jnienv)->ReleaseStringUTFChars(jnienv, originForRelease[i], prefixes[i]); 1585 } 1586 } 1587 deallocate(jvmtienv, (void*)prefixes); 1588 deallocate(jvmtienv, (void*)originForRelease); 1589 } 1590} 1591