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