1 /*
  2  * Copyright (c) 2004, 2019, 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 static JNIEnv *jni = NULL;
 33 static jvmtiEnv* jvmti = NULL;
 34 static jlong timeout = 0;
 35 static jboolean eventEnabled = JNI_FALSE;
 36 static volatile jboolean eventReceived1 = JNI_FALSE, eventReceived2 = JNI_FALSE;
 37 static jclass checkedClass;
 38 static jrawMonitorID eventMon;
 39 
 40 
 41 /* ============================================================================= */
 42 
 43 static void JNICALL
 44 ClassUnload(jvmtiEnv* jvmti_env, ...) {
 45     JNIEnv *jni_env = NULL;
 46     va_list ap;
 47 
 48     va_start(ap, jvmti_env);
 49     jni_env = va_arg(ap, JNIEnv *);
 50     const char * name = va_arg(ap, const char *);
 51     va_end(ap);
 52 
 53     // The name argument should never be null
 54     if (name == NULL) {
 55         nsk_jvmti_setFailStatus();
 56         NSK_COMPLAIN0("ClassUnload: 'name' input parameter is NULL.\n");
 57     } else {
 58         NSK_DISPLAY1("Class unloaded %s\n", name);
 59     }
 60 
 61     NSK_DISPLAY0("Received ClassUnload event.\n");
 62     if (eventEnabled == JNI_TRUE) {
 63         eventReceived1 = JNI_TRUE;
 64     } else {
 65         eventReceived2 = JNI_TRUE;
 66     }
 67 
 68     /* Notify main agent thread */
 69     if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(eventMon))) {
 70         nsk_jvmti_setFailStatus();
 71     }
 72     if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorNotify(eventMon))) {
 73         nsk_jvmti_setFailStatus();
 74     }
 75     if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(eventMon))) {
 76         nsk_jvmti_setFailStatus();
 77     }
 78 }
 79 
 80 jboolean isClassUnloadingEnabled() {
 81     jint extCount, i;
 82     jvmtiExtensionFunctionInfo* extList;
 83     jboolean found = JNI_FALSE;
 84     jboolean enabled = JNI_FALSE;
 85     jvmtiError err;
 86 
 87     NSK_DISPLAY0("Get extension functions list\n");
 88 
 89     if (!NSK_JVMTI_VERIFY(jvmti->GetExtensionFunctions(&extCount, &extList))) {
 90         nsk_jvmti_setFailStatus();
 91         return JNI_FALSE;
 92     }
 93 
 94     for (i = 0; i < extCount; i++) {
 95         if (strcmp(extList[i].id, (char*)"com.sun.hotspot.functions.IsClassUnloadingEnabled") == 0) {
 96             found = JNI_TRUE;
 97 
 98             err = (*extList[i].func)(jvmti, &enabled);
 99             if (err != JVMTI_ERROR_NONE) {
100                 NSK_COMPLAIN1("Error during invocation of IsClassUnloadingEnabled function: %d\n", err);
101                 nsk_jvmti_setFailStatus();
102                 return JNI_FALSE;
103             }
104         }
105     }
106     if (found == JNI_FALSE) {
107         NSK_COMPLAIN0("IsClassUnloadingEnabled was not found among extension functions.\n");
108         nsk_jvmti_setFailStatus();
109         return JNI_FALSE;
110     }
111 
112     return enabled;
113 }
114 
115 jboolean checkParams(jvmtiExtensionEventInfo event) {
116     // Check parameters are:
117     // JNIEnv *jni_env, const char* name
118     if (event.param_count != 2 ||
119           event.params[0].kind != JVMTI_KIND_IN_PTR ||
120           event.params[0].base_type != JVMTI_TYPE_JNIENV ||
121           event.params[1].kind != JVMTI_KIND_IN_PTR ||
122           event.params[1].base_type != JVMTI_TYPE_CCHAR) {
123         return JNI_FALSE;
124     } else {
125         return JNI_TRUE;
126     }
127 }
128 
129 jboolean enableClassUnloadEvent (jboolean enable) {
130     jint extCount, i;
131     jvmtiExtensionEventInfo* extList;
132     jboolean found = JNI_FALSE;
133     jvmtiEventMode mode = enable ? JVMTI_ENABLE : JVMTI_DISABLE;
134 
135     NSK_DISPLAY0("Get extension events list\n");
136     if (!NSK_JVMTI_VERIFY(jvmti->GetExtensionEvents(&extCount, &extList))) {
137         nsk_jvmti_setFailStatus();
138         return JNI_FALSE;
139     }
140 
141     for (i = 0; i < extCount; i++) {
142         if (strcmp(extList[i].id, (char*)"com.sun.hotspot.events.ClassUnload") == 0) {
143             found = JNI_TRUE;
144 
145             NSK_DISPLAY1("%s", extList[i].short_description);
146 
147             if (!checkParams(extList[i])) {
148                 NSK_COMPLAIN0("ClassUnload event has wrong parameters.");
149                 nsk_jvmti_setFailStatus();
150                 return JNI_FALSE;
151             }
152 
153             if (!NSK_JVMTI_VERIFY(
154                     jvmti->SetExtensionEventCallback(extList[i].extension_event_index,
155                                                      enable ? (jvmtiExtensionEvent)ClassUnload : NULL))) {
156                 nsk_jvmti_setFailStatus();
157                 return JNI_FALSE;
158             }
159             if (!NSK_JVMTI_VERIFY(
160                     jvmti->SetEventNotificationMode(mode, (jvmtiEvent)extList[i].extension_event_index, NULL))) {
161                 nsk_jvmti_setFailStatus();
162                 return JNI_FALSE;
163             }
164             eventEnabled = enable;
165             if (enable == JNI_TRUE) {
166                 NSK_DISPLAY1("%s callback enabled\n", extList[i].id);
167             } else {
168                 NSK_DISPLAY1("%s callback disabled\n", extList[i].id);
169             }
170         }
171     }
172     if (found == JNI_FALSE) {
173         NSK_COMPLAIN0("ClassUnload event was not found among extension events.\n");
174         nsk_jvmti_setFailStatus();
175         return JNI_FALSE;
176     }
177     return JNI_TRUE;
178 }
179 
180 
181 /* ============================================================================= */
182 
183 /** Agent algorithm. */
184 static void JNICALL
185 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
186     do {
187         if (isClassUnloadingEnabled() == JNI_FALSE) {
188             NSK_COMPLAIN0("ClassUnloadingEnabled returned false.\n");
189             nsk_jvmti_setFailStatus();
190         }
191 
192         NSK_DISPLAY0("Wait for loading of ex03t001a class.\n");
193         if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
194             return;
195 
196         if (enableClassUnloadEvent(JNI_TRUE) == JNI_FALSE) {
197             NSK_COMPLAIN0("Cannot set up ClassUnload event callback.\n");
198             break;
199         }
200 
201         NSK_DISPLAY0("Let debugee to unload ex03t001a class.\n");
202         if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
203             break;
204 
205         /* Wait for notifying from event's thread */
206         if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(eventMon))) {
207             nsk_jvmti_setFailStatus();
208         }
209         if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorWait(eventMon, timeout))) {
210             nsk_jvmti_setFailStatus();
211         }
212         if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(eventMon))) {
213             nsk_jvmti_setFailStatus();
214         }
215 
216         NSK_DISPLAY0("Wait for loading of ex03t001b class.\n");
217         if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
218             return;
219 
220         if (enableClassUnloadEvent(JNI_FALSE) == JNI_FALSE) {
221             NSK_COMPLAIN0("Cannot set off ClassUnload event callback.\n");
222             break;
223         }
224 
225         NSK_DISPLAY0("Let debugee to unload ex03t001b class.\n");
226         if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
227             return;
228 
229         /* Wait during 10 secs for notifying from event's thread */
230         if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(eventMon))) {
231             nsk_jvmti_setFailStatus();
232         }
233         if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorWait(eventMon, 10000))) {
234             nsk_jvmti_setFailStatus();
235         }
236         if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(eventMon))) {
237             nsk_jvmti_setFailStatus();
238         }
239 
240         if (eventReceived1 == JNI_FALSE) {
241             nsk_jvmti_setFailStatus();
242             NSK_COMPLAIN0("Expected ClassUnload event was not received.\n");
243         }
244 
245         if (eventReceived2 == JNI_TRUE) {
246             nsk_jvmti_setFailStatus();
247             NSK_COMPLAIN0("Received unexpected ClassUnload event.\n");
248         }
249 
250         if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
251             return;
252 
253     } while (0);
254 
255     NSK_TRACE(jvmti->DestroyRawMonitor(eventMon));
256 
257     NSK_DISPLAY0("Let debugee to finish\n");
258     if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
259         return;
260 }
261 
262 /* ============================================================================= */
263 
264 /** Agent library initialization. */
265 #ifdef STATIC_BUILD
266 JNIEXPORT jint JNICALL Agent_OnLoad_ex03t001(JavaVM *jvm, char *options, void *reserved) {
267     return Agent_Initialize(jvm, options, reserved);
268 }
269 JNIEXPORT jint JNICALL Agent_OnAttach_ex03t001(JavaVM *jvm, char *options, void *reserved) {
270     return Agent_Initialize(jvm, options, reserved);
271 }
272 JNIEXPORT jint JNI_OnLoad_ex03t001(JavaVM *jvm, char *options, void *reserved) {
273     return JNI_VERSION_1_8;
274 }
275 #endif
276 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
277 
278     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
279         return JNI_ERR;
280 
281     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
282 
283     if (!NSK_VERIFY((jvmti =
284             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
285         return JNI_ERR;
286 
287     if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("eventMon", &eventMon))) {
288         return JNI_ERR;
289     }
290 
291     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
292         return JNI_ERR;
293 
294     return JNI_OK;
295 }
296 
297 /* ============================================================================= */
298 
299 }