annotate src/java.instrument/share/native/libinstrument/JPLISAgent.c @ 13901:b2a69d66dc65

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