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