Bug Summary

File:jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c
Warning:line 187, column 9
Access to field 'mJVMTIEnv' results in a dereference of a null pointer (loaded from variable 'environment')

Annotated Source Code

Press '?' to see keyboard shortcuts

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