1 /*
2 * Copyright (c) 2003, 2018, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 #include <string.h>
25 #include "jvmti.h"
26 #include "agent_common.h"
27 #include "jni_tools.h"
28 #include "jvmti_tools.h"
29
30 extern "C" {
31
32 /* ============================================================================= */
33
34 /* scaffold objects */
35 static jlong timeout = 0;
36
37 /* constant names */
38 #define DEBUGEE_CLASS_NAME "nsk/jvmti/IsMethodObsolete/isobsolete001"
39 #define TESTED_CLASS_NAME "nsk/jvmti/IsMethodObsolete/isobsolete001r"
40 #define TESTED_CLASS_SIG "L" TESTED_CLASS_NAME ";"
41 #define TESTED_THREAD_NAME "testedThread"
42 #define CLASSFILE_FIELD_NAME "classfileBytes"
43 #define CLASSFILE_FIELD_SIG "[B"
44
45 #define STATIC_METHOD_NAME "testedStaticMethod"
46 #define STATIC_METHOD_SIG "(I" TESTED_CLASS_SIG ")I"
47 #define INSTANCE_METHOD_NAME "testedInstanceMethod"
48 #define INSTANCE_METHOD_SIG "(I)I"
49
50 /* constants */
51 #define MAX_STACK_DEPTH 64
52
53 /* ============================================================================= */
54
55 /** Check is method obsolete is as expected. */
checkMethodObsolete(jvmtiEnv * jvmti,jmethodID method,const char name[],const char kind[],jboolean expected)56 static void checkMethodObsolete(jvmtiEnv* jvmti, jmethodID method, const char name[],
57 const char kind[], jboolean expected) {
58
59 jboolean obsolete = JNI_FALSE;
60
61 NSK_DISPLAY3("Call IsObsolete() for %s method: %p (%s)\n", kind, (void*)method, name);
62 if (!NSK_JVMTI_VERIFY(
63 jvmti->IsMethodObsolete(method, &obsolete))) {
64 nsk_jvmti_setFailStatus();
65 }
66 NSK_DISPLAY1(" ... got obsolete: %d\n", (int)obsolete);
67 if (obsolete != expected) {
68 NSK_COMPLAIN4("IsObsolete() returns unexpected value for %s method: %s\n"
69 "# return value: %d\n"
70 "# expected: %d\n",
71 kind, name,
72 (int)obsolete, (int)expected);
73 nsk_jvmti_setFailStatus();
74 }
75 }
76
77 /** Check is obsolete for methods on the stack are as expected. */
checkStackMethodsObsolete(jvmtiEnv * jvmti,jthread thread,const char kind[],jboolean expected)78 static void checkStackMethodsObsolete(jvmtiEnv* jvmti, jthread thread,
79 const char kind[], jboolean expected) {
80
81 jvmtiFrameInfo frameStack[MAX_STACK_DEPTH];
82 jint frameCount = 0;
83
84 NSK_DISPLAY1("Get stack frames for thread: %p\n", (void*)thread);
85 if (!NSK_JVMTI_VERIFY(
86 jvmti->GetStackTrace(thread, 0, MAX_STACK_DEPTH, frameStack, &frameCount))) {
87 nsk_jvmti_setFailStatus();
88 return;
89 }
90 NSK_DISPLAY1(" ... got frames: %d\n", (int)frameCount);
91
92 NSK_DISPLAY1("Check methods of each frame: %d frames\n", (int)frameCount);
93 {
94 int found = 0;
95 int i;
96
97 for (i = 0; i < frameCount; i++) {
98 char* name = NULL;
99 char* signature = NULL;
100 char* generic = NULL;
101 char* kind = NULL;
102
103 NSK_DISPLAY1(" frame #%i:\n", i);
104 NSK_DISPLAY1(" methodID: %p\n", (void*)frameStack[i].method);
105 if (!NSK_JVMTI_VERIFY(
106 jvmti->GetMethodName(frameStack[i].method, &name, &signature, &generic))) {
107 nsk_jvmti_setFailStatus();
108 continue;
109 }
110 NSK_DISPLAY1(" name: %s\n", nsk_null_string(name));
111 NSK_DISPLAY1(" signature: %s\n", nsk_null_string(signature));
112 NSK_DISPLAY1(" generic: %s\n", nsk_null_string(generic));
113 if (name != NULL
114 && (strcmp(STATIC_METHOD_NAME, name) == 0
115 || strcmp(INSTANCE_METHOD_NAME, name) == 0)) {
116 found++;
117 NSK_DISPLAY1("SUCCESS: found redefined method on stack: %s\n", name);
118 checkMethodObsolete(jvmti, frameStack[i].method, name,
119 "obsolete redefined", expected);
120 }
121
122 if (!NSK_JVMTI_VERIFY(
123 jvmti->Deallocate((unsigned char*)name))) {
124 nsk_jvmti_setFailStatus();
125 }
126 if (!NSK_JVMTI_VERIFY(
127 jvmti->Deallocate((unsigned char*)signature))) {
128 nsk_jvmti_setFailStatus();
129 }
130 if (!NSK_JVMTI_VERIFY(
131 jvmti->Deallocate((unsigned char*)generic))) {
132 nsk_jvmti_setFailStatus();
133 }
134 }
135
136 if (found < 2) {
137 NSK_COMPLAIN3("Not all %s methods found on stack:\n"
138 "# found methods: %d\n"
139 "# expected: %d\n",
140 kind, found, 2);
141 nsk_jvmti_setFailStatus();
142 }
143 }
144 }
145
146 /** Redefine class with given bytecode. */
redefineClass(jvmtiEnv * jvmti,jclass klass,const char className[],jint size,unsigned char bytes[])147 static int redefineClass(jvmtiEnv* jvmti, jclass klass, const char className[],
148 jint size, unsigned char bytes[]) {
149 jvmtiClassDefinition classDef;
150
151 classDef.klass = klass;
152 classDef.class_byte_count = size;
153 classDef.class_bytes = bytes;
154
155 NSK_DISPLAY1("Redefine class: %s\n", className);
156 if (!NSK_JVMTI_VERIFY(
157 jvmti->RedefineClasses(1, &classDef))) {
158 nsk_jvmti_setFailStatus();
159 return NSK_FALSE;
160 }
161 NSK_DISPLAY1(" ... redefined with classfile: %d bytes\n", (int)size);
162
163 return NSK_TRUE;
164 }
165
166 /** Get classfile bytes to redefine. */
getClassfileBytes(JNIEnv * jni,jvmtiEnv * jvmti,jint * size,unsigned char ** bytes)167 static int getClassfileBytes(JNIEnv* jni, jvmtiEnv* jvmti,
168 jint* size, unsigned char* *bytes) {
169 jclass debugeeClass = NULL;
170 jfieldID fieldID = NULL;
171 jbyteArray array = NULL;
172 jbyte* elements;
173 int i;
174
175 NSK_DISPLAY1("Find debugee class: %s\n", DEBUGEE_CLASS_NAME);
176 if (!NSK_JNI_VERIFY(jni, (debugeeClass =
177 jni->FindClass(DEBUGEE_CLASS_NAME)) != NULL)) {
178 nsk_jvmti_setFailStatus();
179 return NSK_FALSE;
180 }
181 NSK_DISPLAY1(" ... found class: %p\n", (void*)debugeeClass);
182
183 NSK_DISPLAY1("Find static field: %s\n", CLASSFILE_FIELD_NAME);
184 if (!NSK_JNI_VERIFY(jni, (fieldID =
185 jni->GetStaticFieldID(debugeeClass, CLASSFILE_FIELD_NAME, CLASSFILE_FIELD_SIG)) != NULL)) {
186 nsk_jvmti_setFailStatus();
187 return NSK_FALSE;
188 }
189 NSK_DISPLAY1(" ... got fieldID: %p\n", (void*)fieldID);
190
191 NSK_DISPLAY1("Get classfile bytes array from static field: %s\n", CLASSFILE_FIELD_NAME);
192 if (!NSK_JNI_VERIFY(jni, (array = (jbyteArray)
193 jni->GetStaticObjectField(debugeeClass, fieldID)) != NULL)) {
194 nsk_jvmti_setFailStatus();
195 return NSK_FALSE;
196 }
197 NSK_DISPLAY1(" ... got array object: %p\n", (void*)array);
198
199 if (!NSK_JNI_VERIFY(jni, (*size =
200 jni->GetArrayLength(array)) > 0)) {
201 nsk_jvmti_setFailStatus();
202 return NSK_FALSE;
203 }
204 NSK_DISPLAY1(" ... got array size: %d bytes\n", (int)*size);
205
206 {
207 jboolean isCopy;
208 if (!NSK_JNI_VERIFY(jni, (elements =
209 jni->GetByteArrayElements(array, &isCopy)) != NULL)) {
210 nsk_jvmti_setFailStatus();
211 return NSK_FALSE;
212 }
213 }
214 NSK_DISPLAY1(" ... got elements list: %p\n", (void*)elements);
215
216 if (!NSK_JVMTI_VERIFY(
217 jvmti->Allocate(*size, bytes))) {
218 nsk_jvmti_setFailStatus();
219 return NSK_FALSE;
220 }
221 NSK_DISPLAY1(" ... created bytes array: %p\n", (void*)*bytes);
222
223 for (i = 0; i < *size; i++) {
224 (*bytes)[i] = (unsigned char)elements[i];
225 }
226 NSK_DISPLAY1(" ... copied bytecode: %d bytes\n", (int)*size);
227
228 NSK_DISPLAY1("Release elements list: %p\n", (void*)elements);
229 NSK_TRACE(jni->ReleaseByteArrayElements(array, elements, JNI_ABORT));
230 NSK_DISPLAY0(" ... released\n");
231
232 return NSK_TRUE;
233 }
234
235
236 /** Agent algorithm. */
237 static void JNICALL
agentProc(jvmtiEnv * jvmti,JNIEnv * jni,void * arg)238 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
239 NSK_DISPLAY0("Wait for tested methods to run\n");
240 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
241 return;
242
243 /* perform testing */
244 {
245 jclass testedClass = NULL;
246 jobject testedThread = NULL;
247 jmethodID staticMethodID = NULL;
248 jmethodID instanceMethodID = NULL;
249 unsigned char* classfileBytes = NULL;
250 jint classfileSize = 0;
251
252 NSK_DISPLAY0(">>> Obtain bytes for class file redefinition\n");
253 {
254 if (!NSK_VERIFY(getClassfileBytes(jni, jvmti, &classfileSize, &classfileBytes)))
255 return;
256 }
257
258 NSK_DISPLAY0(">>> Find tested methods and running thread\n");
259 {
260 NSK_DISPLAY1("Find tested class: %s\n", TESTED_CLASS_NAME);
261 if (!NSK_JNI_VERIFY(jni, (testedClass =
262 jni->FindClass(TESTED_CLASS_NAME)) != NULL)) {
263 nsk_jvmti_setFailStatus();
264 return;
265 }
266 NSK_DISPLAY1(" ... found class: %p\n", (void*)testedClass);
267
268 NSK_DISPLAY1("Make global reference for class object: %p\n", (void*)testedClass);
269 if (!NSK_JNI_VERIFY(jni, (testedClass = (jclass)
270 jni->NewGlobalRef(testedClass)) != NULL)) {
271 nsk_jvmti_setFailStatus();
272 return;
273 }
274 NSK_DISPLAY1(" ... got reference: %p\n", (void*)testedClass);
275
276 NSK_DISPLAY1("Get static methodID: %s\n", STATIC_METHOD_NAME);
277 if (!NSK_JNI_VERIFY(jni, (staticMethodID =
278 jni->GetStaticMethodID(testedClass, STATIC_METHOD_NAME, STATIC_METHOD_SIG)) != NULL)) {
279 nsk_jvmti_setFailStatus();
280 return;
281 }
282 NSK_DISPLAY1(" ... got methodID: %p\n", (void*)staticMethodID);
283
284 NSK_DISPLAY1("Get instance methodID: %s\n", INSTANCE_METHOD_NAME);
285 if (!NSK_JNI_VERIFY(jni, (instanceMethodID =
286 jni->GetMethodID(testedClass, INSTANCE_METHOD_NAME, INSTANCE_METHOD_SIG)) != NULL)) {
287 nsk_jvmti_setFailStatus();
288 return;
289 }
290 NSK_DISPLAY1(" ... got methodID: %p\n", (void*)instanceMethodID);
291
292 NSK_DISPLAY1("Find thread with running methods by name: %s\n", TESTED_THREAD_NAME);
293 if (!NSK_VERIFY((testedThread =
294 nsk_jvmti_threadByName(TESTED_THREAD_NAME)) != NULL)) {
295 nsk_jvmti_setFailStatus();
296 return;
297 }
298 NSK_DISPLAY1(" ... got thread reference: %p\n", (void*)testedThread);
299 }
300
301 NSK_DISPLAY0(">>> Testcase #1: check IsObsolete() for methods before class redefinition\n");
302 {
303 checkMethodObsolete(jvmti, staticMethodID, STATIC_METHOD_NAME,
304 "not yet redefined", JNI_FALSE);
305 checkMethodObsolete(jvmti, instanceMethodID, INSTANCE_METHOD_NAME,
306 "not yet redefined", JNI_FALSE);
307 }
308
309 NSK_DISPLAY0(">>> Testcase #2: check IsObsolete() for methods on stack before class redefinition\n");
310 {
311 checkStackMethodsObsolete(jvmti, testedThread, "not yet redefined", JNI_FALSE);
312 }
313
314 NSK_DISPLAY0(">>> Redefine class while methods are on the stack\n");
315 {
316 if (!NSK_VERIFY(redefineClass(jvmti, testedClass, TESTED_CLASS_NAME,
317 classfileSize, classfileBytes)))
318 return;
319 }
320
321 NSK_DISPLAY0(">>> Testcase #3: check IsObsolete() for methods after class redefinition\n");
322 {
323 checkMethodObsolete(jvmti, staticMethodID, STATIC_METHOD_NAME,
324 "redefined", JNI_FALSE);
325 checkMethodObsolete(jvmti, instanceMethodID, INSTANCE_METHOD_NAME,
326 "redefined", JNI_FALSE);
327 }
328
329 NSK_DISPLAY0(">>> Testcase #4: check IsObsolete() for obsoleted methods on stack after class redefinition\n");
330 {
331 checkStackMethodsObsolete(jvmti, testedThread, "obsolete redefined", JNI_TRUE);
332 }
333
334 NSK_DISPLAY0(">>> Clean used data\n");
335 {
336 NSK_DISPLAY1("Deallocate classfile bytes array: %p\n", (void*)classfileBytes);
337 if (!NSK_JVMTI_VERIFY(
338 jvmti->Deallocate(classfileBytes))) {
339 nsk_jvmti_setFailStatus();
340 }
341
342 NSK_DISPLAY1("Delete global eference to thread: %p\n", (void*)testedThread);
343 NSK_TRACE(jni->DeleteGlobalRef(testedThread));
344
345 NSK_DISPLAY1("Delete global reference to class: %p\n", (void*)testedClass);
346 NSK_TRACE(jni->DeleteGlobalRef(testedClass));
347 }
348 }
349
350 NSK_DISPLAY0("Let debugee to finish\n");
351 if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
352 return;
353 }
354
355 /* ============================================================================= */
356
357 /** Agent library initialization. */
358 #ifdef STATIC_BUILD
Agent_OnLoad_isobsolete001(JavaVM * jvm,char * options,void * reserved)359 JNIEXPORT jint JNICALL Agent_OnLoad_isobsolete001(JavaVM *jvm, char *options, void *reserved) {
360 return Agent_Initialize(jvm, options, reserved);
361 }
Agent_OnAttach_isobsolete001(JavaVM * jvm,char * options,void * reserved)362 JNIEXPORT jint JNICALL Agent_OnAttach_isobsolete001(JavaVM *jvm, char *options, void *reserved) {
363 return Agent_Initialize(jvm, options, reserved);
364 }
JNI_OnLoad_isobsolete001(JavaVM * jvm,char * options,void * reserved)365 JNIEXPORT jint JNI_OnLoad_isobsolete001(JavaVM *jvm, char *options, void *reserved) {
366 return JNI_VERSION_1_8;
367 }
368 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)369 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
370 jvmtiEnv* jvmti = NULL;
371
372 /* init framework and parse options */
373 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
374 return JNI_ERR;
375
376 timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
377
378 /* create JVMTI environment */
379 if (!NSK_VERIFY((jvmti =
380 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
381 return JNI_ERR;
382
383 /* add required capabilities */
384 {
385 jvmtiCapabilities caps;
386
387 memset(&caps, 0, sizeof(caps));
388 caps.can_redefine_classes = 1;
389 if (!NSK_JVMTI_VERIFY(
390 jvmti->AddCapabilities(&caps))) {
391 return JNI_ERR;
392 }
393 }
394
395 /* register agent proc and arg */
396 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
397 return JNI_ERR;
398
399 return JNI_OK;
400 }
401
402 /* ============================================================================= */
403
404 }
405