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