1 /*
   2  * Copyright (c) 2003, 2012, 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 
  25 #include "precompiled.hpp"
  26 #include "prims/jvmtiExport.hpp"
  27 #include "prims/jvmtiExtensions.hpp"
  28 
  29 // the list of extension functions
  30 GrowableArray<jvmtiExtensionFunctionInfo*>* JvmtiExtensions::_ext_functions;
  31 
  32 // the list of extension events
  33 GrowableArray<jvmtiExtensionEventInfo*>* JvmtiExtensions::_ext_events;
  34 
  35 
  36 // extension function
  37 static jvmtiError JNICALL IsClassUnloadingEnabled(const jvmtiEnv* env, jboolean* enabled, ...) {
  38   if (enabled == NULL) {
  39     return JVMTI_ERROR_NULL_POINTER;
  40   }
  41   *enabled = (jboolean)ClassUnloading;
  42   return JVMTI_ERROR_NONE;
  43 }
  44 
  45 // register extension functions and events. In this implementation we
  46 // have a single extension function (to prove the API) that tests if class
  47 // unloading is enabled or disabled. We also have a single extension event
  48 // EXT_EVENT_CLASS_UNLOAD which is used to provide the JVMDI_EVENT_CLASS_UNLOAD
  49 // event. The function and the event are registered here.
  50 //
  51 void JvmtiExtensions::register_extensions() {
  52   _ext_functions = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jvmtiExtensionFunctionInfo*>(1,true);
  53   _ext_events = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jvmtiExtensionEventInfo*>(1,true);
  54 
  55   // register our extension function
  56   static jvmtiParamInfo func_params[] = {
  57     { (char*)"IsClassUnloadingEnabled", JVMTI_KIND_OUT,  JVMTI_TYPE_JBOOLEAN, JNI_FALSE }
  58   };
  59   static jvmtiExtensionFunctionInfo ext_func = {
  60     (jvmtiExtensionFunction)IsClassUnloadingEnabled,
  61     (char*)"com.sun.hotspot.functions.IsClassUnloadingEnabled",
  62     (char*)"Tell if class unloading is enabled (-noclassgc)",
  63     sizeof(func_params)/sizeof(func_params[0]),
  64     func_params,
  65     0,              // no non-universal errors
  66     NULL
  67   };
  68   _ext_functions->append(&ext_func);
  69 
  70   // register our extension event
  71 
  72   static jvmtiParamInfo event_params[] = {
  73     { (char*)"JNI Environment", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, JNI_FALSE },
  74     { (char*)"Class", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, JNI_FALSE }
  75   };
  76   static jvmtiExtensionEventInfo ext_event = {
  77     EXT_EVENT_CLASS_UNLOAD,
  78     (char*)"com.sun.hotspot.events.ClassUnload",
  79     (char*)"CLASS_UNLOAD event",
  80     sizeof(event_params)/sizeof(event_params[0]),
  81     event_params
  82   };
  83   _ext_events->append(&ext_event);
  84 }
  85 
  86 
  87 // return the list of extension functions
  88 
  89 jvmtiError JvmtiExtensions::get_functions(JvmtiEnv* env,
  90                                           jint* extension_count_ptr,
  91                                           jvmtiExtensionFunctionInfo** extensions)
  92 {
  93   guarantee(_ext_functions != NULL, "registration not done");
  94 
  95   ResourceTracker rt(env);
  96 
  97   jvmtiExtensionFunctionInfo* ext_funcs;
  98   jvmtiError err = rt.allocate(_ext_functions->length() *
  99                                sizeof(jvmtiExtensionFunctionInfo),
 100                                (unsigned char**)&ext_funcs);
 101   if (err != JVMTI_ERROR_NONE) {
 102     return err;
 103   }
 104 
 105   for (int i=0; i<_ext_functions->length(); i++ ) {
 106     ext_funcs[i].func = _ext_functions->at(i)->func;
 107 
 108     char *id = _ext_functions->at(i)->id;
 109     err = rt.allocate(strlen(id)+1, (unsigned char**)&(ext_funcs[i].id));
 110     if (err != JVMTI_ERROR_NONE) {
 111       return err;
 112     }
 113     strcpy(ext_funcs[i].id, id);
 114 
 115     char *desc = _ext_functions->at(i)->short_description;
 116     err = rt.allocate(strlen(desc)+1,
 117                       (unsigned char**)&(ext_funcs[i].short_description));
 118     if (err != JVMTI_ERROR_NONE) {
 119       return err;
 120     }
 121     strcpy(ext_funcs[i].short_description, desc);
 122 
 123     // params
 124 
 125     jint param_count = _ext_functions->at(i)->param_count;
 126 
 127     ext_funcs[i].param_count = param_count;
 128     if (param_count == 0) {
 129       ext_funcs[i].params = NULL;
 130     } else {
 131       err = rt.allocate(param_count*sizeof(jvmtiParamInfo),
 132                         (unsigned char**)&(ext_funcs[i].params));
 133       if (err != JVMTI_ERROR_NONE) {
 134         return err;
 135       }
 136       jvmtiParamInfo* src_params = _ext_functions->at(i)->params;
 137       jvmtiParamInfo* dst_params = ext_funcs[i].params;
 138 
 139       for (int j=0; j<param_count; j++) {
 140         err = rt.allocate(strlen(src_params[j].name)+1,
 141                           (unsigned char**)&(dst_params[j].name));
 142         if (err != JVMTI_ERROR_NONE) {
 143           return err;
 144         }
 145         strcpy(dst_params[j].name, src_params[j].name);
 146 
 147         dst_params[j].kind = src_params[j].kind;
 148         dst_params[j].base_type = src_params[j].base_type;
 149         dst_params[j].null_ok = src_params[j].null_ok;
 150       }
 151     }
 152 
 153     // errors
 154 
 155     jint error_count = _ext_functions->at(i)->error_count;
 156     ext_funcs[i].error_count = error_count;
 157     if (error_count == 0) {
 158       ext_funcs[i].errors = NULL;
 159     } else {
 160       err = rt.allocate(error_count*sizeof(jvmtiError),
 161                         (unsigned char**)&(ext_funcs[i].errors));
 162       if (err != JVMTI_ERROR_NONE) {
 163         return err;
 164       }
 165       memcpy(ext_funcs[i].errors, _ext_functions->at(i)->errors,
 166              error_count*sizeof(jvmtiError));
 167     }
 168   }
 169 
 170   *extension_count_ptr = _ext_functions->length();
 171   *extensions = ext_funcs;
 172   return JVMTI_ERROR_NONE;
 173 }
 174 
 175 
 176 // return the list of extension events
 177 
 178 jvmtiError JvmtiExtensions::get_events(JvmtiEnv* env,
 179                                        jint* extension_count_ptr,
 180                                        jvmtiExtensionEventInfo** extensions)
 181 {
 182   guarantee(_ext_events != NULL, "registration not done");
 183 
 184   ResourceTracker rt(env);
 185 
 186   jvmtiExtensionEventInfo* ext_events;
 187   jvmtiError err = rt.allocate(_ext_events->length() * sizeof(jvmtiExtensionEventInfo),
 188                                (unsigned char**)&ext_events);
 189   if (err != JVMTI_ERROR_NONE) {
 190     return err;
 191   }
 192 
 193   for (int i=0; i<_ext_events->length(); i++ ) {
 194     ext_events[i].extension_event_index = _ext_events->at(i)->extension_event_index;
 195 
 196     char *id = _ext_events->at(i)->id;
 197     err = rt.allocate(strlen(id)+1, (unsigned char**)&(ext_events[i].id));
 198     if (err != JVMTI_ERROR_NONE) {
 199       return err;
 200     }
 201     strcpy(ext_events[i].id, id);
 202 
 203     char *desc = _ext_events->at(i)->short_description;
 204     err = rt.allocate(strlen(desc)+1,
 205                       (unsigned char**)&(ext_events[i].short_description));
 206     if (err != JVMTI_ERROR_NONE) {
 207       return err;
 208     }
 209     strcpy(ext_events[i].short_description, desc);
 210 
 211     // params
 212 
 213     jint param_count = _ext_events->at(i)->param_count;
 214 
 215     ext_events[i].param_count = param_count;
 216     if (param_count == 0) {
 217       ext_events[i].params = NULL;
 218     } else {
 219       err = rt.allocate(param_count*sizeof(jvmtiParamInfo),
 220                         (unsigned char**)&(ext_events[i].params));
 221       if (err != JVMTI_ERROR_NONE) {
 222         return err;
 223       }
 224       jvmtiParamInfo* src_params = _ext_events->at(i)->params;
 225       jvmtiParamInfo* dst_params = ext_events[i].params;
 226 
 227       for (int j=0; j<param_count; j++) {
 228         err = rt.allocate(strlen(src_params[j].name)+1,
 229                           (unsigned char**)&(dst_params[j].name));
 230         if (err != JVMTI_ERROR_NONE) {
 231           return err;
 232         }
 233         strcpy(dst_params[j].name, src_params[j].name);
 234 
 235         dst_params[j].kind = src_params[j].kind;
 236         dst_params[j].base_type = src_params[j].base_type;
 237         dst_params[j].null_ok = src_params[j].null_ok;
 238       }
 239     }
 240   }
 241 
 242   *extension_count_ptr = _ext_events->length();
 243   *extensions = ext_events;
 244   return JVMTI_ERROR_NONE;
 245 }
 246 
 247 // set callback for an extension event and enable/disable it.
 248 
 249 jvmtiError JvmtiExtensions::set_event_callback(JvmtiEnv* env,
 250                                                jint extension_event_index,
 251                                                jvmtiExtensionEvent callback)
 252 {
 253   guarantee(_ext_events != NULL, "registration not done");
 254 
 255   jvmtiExtensionEventInfo* event = NULL;
 256 
 257   // if there are extension events registered then validate that the
 258   // extension_event_index matches one of the registered events.
 259   if (_ext_events != NULL) {
 260     for (int i=0; i<_ext_events->length(); i++ ) {
 261       if (_ext_events->at(i)->extension_event_index == extension_event_index) {
 262          event = _ext_events->at(i);
 263          break;
 264       }
 265     }
 266   }
 267 
 268   // invalid event index
 269   if (event == NULL) {
 270     return JVMTI_ERROR_ILLEGAL_ARGUMENT;
 271   }
 272 
 273   JvmtiEventController::set_extension_event_callback(env, extension_event_index,
 274                                                      callback);
 275 
 276   return JVMTI_ERROR_NONE;
 277 }