1 | /* |
2 | * Copyright (c) 2003, 2017, 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 | #ifndef _JPLISAGENT_H_ |
31 | #define _JPLISAGENT_H_ |
32 | |
33 | #include <jni.h> |
34 | #include <jvmti.h> |
35 | |
36 | #ifdef __cplusplus |
37 | extern "C" { |
38 | #endif |
39 | |
40 | /* |
41 | * The JPLISAgent manages the initialization all of the Java programming language Agents. |
42 | * It also supports the native method bridge between the JPLIS and the JVMTI. |
43 | * It maintains a single JVMTI Env that all JPL agents share. |
44 | * It parses command line requests and creates individual Java agents. |
45 | */ |
46 | |
47 | |
48 | /* |
49 | * Forward definitions |
50 | */ |
51 | struct _JPLISAgent; |
52 | |
53 | typedef struct _JPLISAgent JPLISAgent; |
54 | typedef struct _JPLISEnvironment JPLISEnvironment; |
55 | |
56 | |
57 | /* constants for class names and methods names and such |
58 | these all must stay in sync with Java code & interfaces |
59 | */ |
60 | #define JPLIS_INSTRUMENTIMPL_CLASSNAME "sun/instrument/InstrumentationImpl" |
61 | #define JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODNAME "<init>" |
62 | #define JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODSIGNATURE "(JZZ)V" |
63 | #define JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODNAME "loadClassAndCallPremain" |
64 | #define JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODSIGNATURE "(Ljava/lang/String;Ljava/lang/String;)V" |
65 | #define JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODNAME "loadClassAndCallAgentmain" |
66 | #define JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODSIGNATURE "(Ljava/lang/String;Ljava/lang/String;)V" |
67 | #define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODNAME "transform" |
68 | #define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODSIGNATURE \ |
69 | "(Ljava/lang/Module;Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/Class;Ljava/security/ProtectionDomain;[BZ)[B" |
70 | |
71 | |
72 | /* |
73 | * Error messages |
74 | */ |
75 | #define JPLIS_ERRORMESSAGE_CANNOTSTART "processing of -javaagent failed" |
76 | |
77 | |
78 | /* |
79 | * Our initialization errors |
80 | */ |
81 | typedef enum { |
82 | JPLIS_INIT_ERROR_NONE, |
83 | JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT, |
84 | JPLIS_INIT_ERROR_FAILURE, |
85 | JPLIS_INIT_ERROR_ALLOCATION_FAILURE, |
86 | JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED |
87 | } JPLISInitializationError; |
88 | |
89 | |
90 | struct _JPLISEnvironment { |
91 | jvmtiEnv * mJVMTIEnv; /* the JVM TI environment */ |
92 | JPLISAgent * mAgent; /* corresponding agent */ |
93 | jboolean mIsRetransformer; /* indicates if special environment */ |
94 | }; |
95 | |
96 | struct _JPLISAgent { |
97 | JavaVM * mJVM; /* handle to the JVM */ |
98 | JPLISEnvironment mNormalEnvironment; /* for every thing but retransform stuff */ |
99 | JPLISEnvironment mRetransformEnvironment;/* for retransform stuff only */ |
100 | jobject mInstrumentationImpl; /* handle to the Instrumentation instance */ |
101 | jmethodID mPremainCaller; /* method on the InstrumentationImpl that does the premain stuff (cached to save lots of lookups) */ |
102 | jmethodID mAgentmainCaller; /* method on the InstrumentationImpl for agents loaded via attach mechanism */ |
103 | jmethodID mTransform; /* method on the InstrumentationImpl that does the class file transform */ |
104 | jboolean mRedefineAvailable; /* cached answer to "does this agent support redefine" */ |
105 | jboolean mRedefineAdded; /* indicates if can_redefine_classes capability has been added */ |
106 | jboolean mNativeMethodPrefixAvailable; /* cached answer to "does this agent support prefixing" */ |
107 | jboolean mNativeMethodPrefixAdded; /* indicates if can_set_native_method_prefix capability has been added */ |
108 | char const * mAgentClassName; /* agent class name */ |
109 | char const * mOptionsString; /* -javaagent options string */ |
110 | const char * mJarfile; /* agent jar file name */ |
111 | }; |
112 | |
113 | /* |
114 | * JVMTI event handlers |
115 | */ |
116 | |
117 | /* VMInit event handler. Installed during OnLoad, then removed during VMInit. */ |
118 | extern void JNICALL |
119 | eventHandlerVMInit( jvmtiEnv * jvmtienv, |
120 | JNIEnv * jnienv, |
121 | jthread thread); |
122 | |
123 | /* |
124 | * ClassFileLoadHook event handler. |
125 | * Enabled when the first transformer is added; |
126 | * Disabled when the last transformer is removed. |
127 | */ |
128 | extern void JNICALL |
129 | eventHandlerClassFileLoadHook( jvmtiEnv * jvmtienv, |
130 | JNIEnv * jnienv, |
131 | jclass class_being_redefined, |
132 | jobject loader, |
133 | const char* name, |
134 | jobject protectionDomain, |
135 | jint class_data_len, |
136 | const unsigned char* class_data, |
137 | jint* new_class_data_len, |
138 | unsigned char** new_class_data); |
139 | |
140 | /* |
141 | * Main entry points for the JPLIS JVMTI agent code |
142 | */ |
143 | |
144 | /* looks up the environment instance. returns null if there isn't one */ |
145 | extern JPLISEnvironment * |
146 | getJPLISEnvironment(jvmtiEnv * jvmtienv); |
147 | |
148 | /* Creates a new JPLIS agent. |
149 | * Returns error if the agent cannot be created and initialized. |
150 | * The JPLISAgent* pointed to by agent_ptr is set to the new broker, |
151 | * or NULL if an error has occurred. |
152 | */ |
153 | extern JPLISInitializationError |
154 | createNewJPLISAgent(JavaVM * vm, JPLISAgent **agent_ptr); |
155 | |
156 | /* Adds can_redefine_classes capability */ |
157 | extern void |
158 | addRedefineClassesCapability(JPLISAgent * agent); |
159 | |
160 | /* Add the can_set_native_method_prefix capability */ |
161 | extern void |
162 | addNativeMethodPrefixCapability(JPLISAgent * agent); |
163 | |
164 | /* Add the can_maintain_original_method_order capability (for testing) */ |
165 | extern void |
166 | addOriginalMethodOrderCapability(JPLISAgent * agent); |
167 | |
168 | |
169 | /* Our JPLIS agent is paralleled by a Java InstrumentationImpl instance. |
170 | * This routine uses JNI to create and initialized the Java instance. |
171 | * Returns true if it succeeds, false otherwise. |
172 | */ |
173 | extern jboolean |
174 | createInstrumentationImpl( JNIEnv * jnienv, |
175 | JPLISAgent * agent); |
176 | |
177 | |
178 | /* during OnLoad phase (command line parsing) |
179 | * record the parameters of -javaagent |
180 | */ |
181 | extern JPLISInitializationError |
182 | recordCommandLineData( JPLISAgent * agent, |
183 | const char * agentClass, |
184 | const char * optionsString ); |
185 | |
186 | /* Swaps the start phase event handlers out and the live phase event handlers in. |
187 | * Also used in attach to enabled live phase event handlers. |
188 | * Returns true if it succeeds, false otherwise. |
189 | */ |
190 | extern jboolean |
191 | setLivePhaseEventHandlers( JPLISAgent * agent); |
192 | |
193 | /* Loads the Java agent according to the already processed command line. For each, |
194 | * loads the Java agent class, then calls the premain method. |
195 | * Returns true if all Java agent classes are loaded and all premain methods complete with no exceptions, |
196 | * false otherwise. |
197 | */ |
198 | extern jboolean |
199 | startJavaAgent( JPLISAgent * agent, |
200 | JNIEnv * jnienv, |
201 | const char * classname, |
202 | const char * optionsString, |
203 | jmethodID agentMainMethod); |
204 | |
205 | |
206 | /* during VMInit processing |
207 | * this is how the invocation engine (callback wrapper) tells us to start up all the javaagents |
208 | */ |
209 | extern jboolean |
210 | processJavaStart( JPLISAgent * agent, |
211 | JNIEnv * jnienv); |
212 | |
213 | /* on an ongoing basis, |
214 | * this is how the invocation engine (callback wrapper) tells us to process a class file |
215 | */ |
216 | extern void |
217 | transformClassFile( JPLISAgent * agent, |
218 | JNIEnv * jnienv, |
219 | jobject loader, |
220 | const char* name, |
221 | jclass classBeingRedefined, |
222 | jobject protectionDomain, |
223 | jint class_data_len, |
224 | const unsigned char* class_data, |
225 | jint* new_class_data_len, |
226 | unsigned char** new_class_data, |
227 | jboolean is_retransformer); |
228 | |
229 | /* on an ongoing basis, |
230 | * Return the environment with the retransformation capability. |
231 | * Create it if it doesn't exist. |
232 | */ |
233 | extern jvmtiEnv * |
234 | retransformableEnvironment(JPLISAgent * agent); |
235 | |
236 | /* on an ongoing basis, |
237 | * these are implementations of the Instrumentation services. |
238 | * Most are simple covers for JVMTI access services. These are the guts of the InstrumentationImpl |
239 | * native methods. |
240 | */ |
241 | extern jboolean |
242 | isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz); |
243 | |
244 | extern jboolean |
245 | isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent); |
246 | |
247 | extern void |
248 | setHasTransformers(JNIEnv * jnienv, JPLISAgent * agent, jboolean has); |
249 | |
250 | extern void |
251 | setHasRetransformableTransformers(JNIEnv * jnienv, JPLISAgent * agent, jboolean has); |
252 | |
253 | extern void |
254 | retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes); |
255 | |
256 | extern void |
257 | redefineClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classDefinitions); |
258 | |
259 | extern jobjectArray |
260 | getAllLoadedClasses(JNIEnv * jnienv, JPLISAgent * agent); |
261 | |
262 | extern jobjectArray |
263 | getInitiatedClasses(JNIEnv * jnienv, JPLISAgent * agent, jobject classLoader); |
264 | |
265 | extern jlong |
266 | getObjectSize(JNIEnv * jnienv, JPLISAgent * agent, jobject objectToSize); |
267 | |
268 | extern void |
269 | appendToClassLoaderSearch(JNIEnv * jnienv, JPLISAgent * agent, jstring jarFile, jboolean isBootLoader); |
270 | |
271 | extern void |
272 | setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefixArray, |
273 | jboolean isRetransformable); |
274 | |
275 | #define jvmti(a) a->mNormalEnvironment.mJVMTIEnv |
276 | |
277 | /* |
278 | * A set of macros for insulating the JLI method callers from |
279 | * JVMTI_ERROR_WRONG_PHASE return codes. |
280 | */ |
281 | |
282 | /* for a JLI method where "blob" is executed before simply returning */ |
283 | #define check_phase_blob_ret(ret, blob) \ |
284 | if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ |
285 | blob; \ |
286 | return; \ |
287 | } |
288 | |
289 | /* for a JLI method where simply returning is benign */ |
290 | #define check_phase_ret(ret) \ |
291 | if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ |
292 | return; \ |
293 | } |
294 | |
295 | /* for a JLI method where returning zero (0) is benign */ |
296 | #define check_phase_ret_0(ret) \ |
297 | if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ |
298 | return 0; \ |
299 | } |
300 | |
301 | /* for a JLI method where returning one (1) is benign */ |
302 | #define check_phase_ret_1(ret) \ |
303 | if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ |
304 | return 1; \ |
305 | } |
306 | |
307 | /* for a case where a specific "blob" must be returned */ |
308 | #define check_phase_ret_blob(ret, blob) \ |
309 | if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ |
310 | return (blob); \ |
311 | } |
312 | |
313 | /* for a JLI method where returning false is benign */ |
314 | #define check_phase_ret_false(ret) \ |
315 | if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \ |
316 | return (jboolean) 0; \ |
317 | } |
318 | |
319 | #ifdef __cplusplus |
320 | } /* extern "C" */ |
321 | #endif /* __cplusplus */ |
322 | |
323 | |
324 | #endif |
325 | |