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') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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. */ | |||
59 | JPLISAgent * | |||
60 | allocateJPLISAgent(jvmtiEnv * jvmtiEnv); | |||
61 | ||||
62 | /* Initializes an already-allocated JPLIS agent data structure. */ | |||
63 | JPLISInitializationError | |||
64 | initializeJPLISAgent( JPLISAgent * agent, | |||
65 | JavaVM * vm, | |||
66 | jvmtiEnv * jvmtienv); | |||
67 | /* De-allocates a JPLIS agent data structure. Only used in partial-failure cases at startup; | |||
68 | * in normal usage the JPLIS agent lives forever | |||
69 | */ | |||
70 | void | |||
71 | deallocateJPLISAgent( jvmtiEnv * jvmtienv, | |||
72 | JPLISAgent * agent); | |||
73 | ||||
74 | /* Does one-time work to interrogate the JVM about capabilities and cache the answers. */ | |||
75 | void | |||
76 | checkCapabilities(JPLISAgent * agent); | |||
77 | ||||
78 | /* Takes the elements of the command string (agent class name and options string) and | |||
79 | * create java strings for them. | |||
80 | * Returns true if a classname was found. Makes no promises beyond the textual; says nothing about whether | |||
81 | * the class exists or can be loaded. | |||
82 | * If return value is true, sets outputClassname to a non-NULL local JNI reference. | |||
83 | * If return value is true, sets outputOptionsString either to NULL or to a non-NULL local JNI reference. | |||
84 | * If return value is false, neither output parameter is set. | |||
85 | */ | |||
86 | jboolean | |||
87 | commandStringIntoJavaStrings( JNIEnv * jnienv, | |||
88 | const char * classname, | |||
89 | const char * optionsString, | |||
90 | jstring * outputClassname, | |||
91 | jstring * outputOptionsString); | |||
92 | ||||
93 | /* Start one Java agent from the supplied parameters. | |||
94 | * Most of the logic lives in a helper function that lives over in Java code-- | |||
95 | * we pass parameters out to Java and use our own Java helper to actually | |||
96 | * load the agent and call the premain. | |||
97 | * Returns true if the Java agent class is loaded and the premain/agentmain method completes | |||
98 | * with no exceptions, false otherwise. | |||
99 | */ | |||
100 | jboolean | |||
101 | invokeJavaAgentMainMethod( JNIEnv * jnienv, | |||
102 | jobject instrumentationImpl, | |||
103 | jmethodID agentMainMethod, | |||
104 | jstring className, | |||
105 | jstring optionsString); | |||
106 | ||||
107 | /* Once we have loaded the Java agent and called the premain, | |||
108 | * we can release the copies we have been keeping of the command line | |||
109 | * data (agent class name and option strings). | |||
110 | */ | |||
111 | void | |||
112 | deallocateCommandLineData(JPLISAgent * agent); | |||
113 | ||||
114 | /* | |||
115 | * Common support for various class list fetchers. | |||
116 | */ | |||
117 | typedef jvmtiError (*ClassListFetcher) | |||
118 | ( jvmtiEnv * jvmtiEnv, | |||
119 | jobject classLoader, | |||
120 | jint * classCount, | |||
121 | jclass ** classes); | |||
122 | ||||
123 | /* Fetcher that ignores the class loader parameter, and uses the JVMTI to get a list of all classes. | |||
124 | * Returns a jvmtiError according to the underlying JVMTI service. | |||
125 | */ | |||
126 | jvmtiError | |||
127 | getAllLoadedClassesClassListFetcher( jvmtiEnv * jvmtiEnv, | |||
128 | jobject classLoader, | |||
129 | jint * classCount, | |||
130 | jclass ** classes); | |||
131 | ||||
132 | /* Fetcher that uses the class loader parameter, and uses the JVMTI to get a list of all classes | |||
133 | * for which the supplied loader is the initiating loader. | |||
134 | * Returns a jvmtiError according to the underlying JVMTI service. | |||
135 | */ | |||
136 | jvmtiError | |||
137 | getInitiatedClassesClassListFetcher( jvmtiEnv * jvmtiEnv, | |||
138 | jobject classLoader, | |||
139 | jint * classCount, | |||
140 | jclass ** classes); | |||
141 | ||||
142 | /* | |||
143 | * Common guts for two native methods, which are the same except for the policy for fetching | |||
144 | * the list of classes. | |||
145 | * Either returns a local JNI reference to an array of references to java.lang.Class. | |||
146 | * Can throw, if it does will alter the JNIEnv with an outstanding exception. | |||
147 | */ | |||
148 | jobjectArray | |||
149 | commonGetClassList( JNIEnv * jnienv, | |||
150 | JPLISAgent * agent, | |||
151 | jobject classLoader, | |||
152 | ClassListFetcher fetcher); | |||
153 | ||||
154 | ||||
155 | /* | |||
156 | * Misc. utilities. | |||
157 | */ | |||
158 | ||||
159 | /* Checked exception mapper used by the redefine classes implementation. | |||
160 | * Allows ClassNotFoundException or UnmodifiableClassException; maps others | |||
161 | * to InternalError. Can return NULL in an error case. | |||
162 | */ | |||
163 | jthrowable | |||
164 | redefineClassMapper( JNIEnv * jnienv, | |||
165 | jthrowable throwableToMap); | |||
166 | ||||
167 | /* Turns a buffer of jclass * into a Java array whose elements are java.lang.Class. | |||
168 | * Can throw, if it does will alter the JNIEnv with an outstanding exception. | |||
169 | */ | |||
170 | jobjectArray | |||
171 | getObjectArrayFromClasses(JNIEnv* jnienv, jclass* classes, jint classCount); | |||
172 | ||||
173 | ||||
174 | JPLISEnvironment * | |||
175 | getJPLISEnvironment(jvmtiEnv * jvmtienv) { | |||
176 | JPLISEnvironment * environment = NULL((void*)0); | |||
177 | jvmtiError jvmtierror = JVMTI_ERROR_NONE; | |||
178 | ||||
179 | jvmtierror = (*jvmtienv)->GetEnvironmentLocalStorage( | |||
| ||||
180 | jvmtienv, | |||
181 | (void**)&environment); | |||
182 | /* can be called from any phase */ | |||
183 | jplis_assert(jvmtierror == JVMTI_ERROR_NONE)JPLISAssertCondition((jboolean)(jvmtierror == JVMTI_ERROR_NONE ), "jvmtierror == JVMTI_ERROR_NONE", "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c" , 183); | |||
184 | ||||
185 | if (jvmtierror
| |||
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); | |||
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); | |||
| ||||
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 | */ | |||
204 | JPLISInitializationError | |||
205 | createNewJPLISAgent(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 | */ | |||
245 | JPLISAgent * | |||
246 | allocateJPLISAgent(jvmtiEnv * jvmtienv) { | |||
247 | return (JPLISAgent *) allocate( jvmtienv, | |||
248 | sizeof(JPLISAgent)); | |||
249 | } | |||
250 | ||||
251 | JPLISInitializationError | |||
252 | initializeJPLISAgent( JPLISAgent * agent, | |||
253 | JavaVM * vm, | |||
254 | jvmtiEnv * jvmtienv) { | |||
255 | jvmtiError jvmtierror = JVMTI_ERROR_NONE; | |||
256 | jvmtiPhase phase; | |||
257 | ||||
258 | agent->mJVM = vm; | |||
259 | agent->mNormalEnvironment.mJVMTIEnv = jvmtienv; | |||
260 | agent->mNormalEnvironment.mAgent = agent; | |||
261 | agent->mNormalEnvironment.mIsRetransformer = JNI_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 | ||||
328 | void | |||
329 | deallocateJPLISAgent(jvmtiEnv * jvmtienv, JPLISAgent * agent) { | |||
330 | deallocate(jvmtienv, agent); | |||
331 | } | |||
332 | ||||
333 | ||||
334 | JPLISInitializationError | |||
335 | recordCommandLineData( JPLISAgent * agent, | |||
336 | const char * agentClassName, | |||
337 | const char * optionsString ) { | |||
338 | JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE; | |||
339 | char * ourCopyOfAgentClassName = NULL((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 | */ | |||
382 | jboolean | |||
383 | processJavaStart( JPLISAgent * agent, | |||
384 | JNIEnv * jnienv) { | |||
385 | jboolean result; | |||
386 | ||||
387 | /* | |||
388 | * OK, Java is up now. We can start everything that needs Java. | |||
389 | */ | |||
390 | ||||
391 | /* | |||
392 | * First make our 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 | ||||
436 | jboolean | |||
437 | startJavaAgent( 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 | ||||
463 | void | |||
464 | deallocateCommandLineData( 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 | */ | |||
477 | jboolean | |||
478 | createInstrumentationImpl( 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 | ||||
568 | jboolean | |||
569 | commandStringIntoJavaStrings( 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 | ||||
599 | jboolean | |||
600 | invokeJavaAgentMainMethod( 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 | ||||
623 | jboolean | |||
624 | setLivePhaseEventHandlers( 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 | */ | |||
659 | void | |||
660 | checkCapabilities(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 | */ | |||
684 | void | |||
685 | enableNativeMethodPrefixCapability(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 | */ | |||
702 | void | |||
703 | addNativeMethodPrefixCapability(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 | */ | |||
719 | void | |||
720 | addOriginalMethodOrderCapability(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 | */ | |||
737 | void | |||
738 | addRedefineClassesCapability(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 | ||||
764 | static jobject | |||
765 | getModuleObject(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 | ||||
797 | void | |||
798 | transformClassFile( 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 | */ | |||
937 | jthrowable | |||
938 | redefineClassMapper( 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 | ||||
966 | jobjectArray | |||
967 | getObjectArrayFromClasses(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 | */ | |||
1009 | jvmtiEnv * | |||
1010 | retransformableEnvironment(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 | ||||
1069 | jboolean | |||
1070 | isModifiableClass(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 | ||||
1084 | jboolean | |||
1085 | isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent) { | |||
1086 | return agent->mRetransformEnvironment.mIsRetransformer; | |||
1087 | } | |||
1088 | ||||
1089 | void | |||
1090 | setHasTransformers(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 | ||||
1104 | void | |||
1105 | setHasRetransformableTransformers(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 | ||||
1119 | void | |||
1120 | retransformClasses(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 | */ | |||
1208 | void | |||
1209 | redefineClasses(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. */ | |||
1373 | jobjectArray | |||
1374 | commonGetClassList( 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 | ||||
1412 | jvmtiError | |||
1413 | getAllLoadedClassesClassListFetcher( jvmtiEnv * jvmtienv, | |||
1414 | jobject classLoader, | |||
1415 | jint * classCount, | |||
1416 | jclass ** classes) { | |||
1417 | return (*jvmtienv)->GetLoadedClasses(jvmtienv, classCount, classes); | |||
1418 | } | |||
1419 | ||||
1420 | jobjectArray | |||
1421 | getAllLoadedClasses(JNIEnv * jnienv, JPLISAgent * agent) { | |||
1422 | return commonGetClassList( jnienv, | |||
1423 | agent, | |||
1424 | NULL((void*)0), | |||
1425 | getAllLoadedClassesClassListFetcher); | |||
1426 | } | |||
1427 | ||||
1428 | jvmtiError | |||
1429 | getInitiatedClassesClassListFetcher( jvmtiEnv * jvmtienv, | |||
1430 | jobject classLoader, | |||
1431 | jint * classCount, | |||
1432 | jclass ** classes) { | |||
1433 | return (*jvmtienv)->GetClassLoaderClasses(jvmtienv, classLoader, classCount, classes); | |||
1434 | } | |||
1435 | ||||
1436 | ||||
1437 | jobjectArray | |||
1438 | getInitiatedClasses(JNIEnv * jnienv, JPLISAgent * agent, jobject classLoader) { | |||
1439 | return commonGetClassList( jnienv, | |||
1440 | agent, | |||
1441 | classLoader, | |||
1442 | getInitiatedClassesClassListFetcher); | |||
1443 | } | |||
1444 | ||||
1445 | jlong | |||
1446 | getObjectSize(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 | ||||
1462 | void | |||
1463 | appendToClassLoaderSearch(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 | */ | |||
1522 | void | |||
1523 | setNativeMethodPrefixes(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 | } |