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
30GrowableArray<jvmtiExtensionFunctionInfo*>* JvmtiExtensions::_ext_functions;
31
32// the list of extension events
33GrowableArray<jvmtiExtensionEventInfo*>* JvmtiExtensions::_ext_events;
34
35
36// extension function
37static 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//
51void 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, JVMTI_TYPE_JNIENV, JNI_FALSE },
74    { (char*)"Thread", JVMTI_KIND_IN, JVMTI_TYPE_JTHREAD, JNI_FALSE },
75    { (char*)"Class", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, JNI_FALSE }
76  };
77  static jvmtiExtensionEventInfo ext_event = {
78    EXT_EVENT_CLASS_UNLOAD,
79    (char*)"com.sun.hotspot.events.ClassUnload",
80    (char*)"CLASS_UNLOAD event",
81    sizeof(event_params)/sizeof(event_params[0]),
82    event_params
83  };
84  _ext_events->append(&ext_event);
85}
86
87
88// return the list of extension functions
89
90jvmtiError JvmtiExtensions::get_functions(JvmtiEnv* env,
91                                          jint* extension_count_ptr,
92                                          jvmtiExtensionFunctionInfo** extensions)
93{
94  guarantee(_ext_functions != NULL, "registration not done");
95
96  ResourceTracker rt(env);
97
98  jvmtiExtensionFunctionInfo* ext_funcs;
99  jvmtiError err = rt.allocate(_ext_functions->length() *
100                               sizeof(jvmtiExtensionFunctionInfo),
101                               (unsigned char**)&ext_funcs);
102  if (err != JVMTI_ERROR_NONE) {
103    return err;
104  }
105
106  for (int i=0; i<_ext_functions->length(); i++ ) {
107    ext_funcs[i].func = _ext_functions->at(i)->func;
108
109    char *id = _ext_functions->at(i)->id;
110    err = rt.allocate(strlen(id)+1, (unsigned char**)&(ext_funcs[i].id));
111    if (err != JVMTI_ERROR_NONE) {
112      return err;
113    }
114    strcpy(ext_funcs[i].id, id);
115
116    char *desc = _ext_functions->at(i)->short_description;
117    err = rt.allocate(strlen(desc)+1,
118                      (unsigned char**)&(ext_funcs[i].short_description));
119    if (err != JVMTI_ERROR_NONE) {
120      return err;
121    }
122    strcpy(ext_funcs[i].short_description, desc);
123
124    // params
125
126    jint param_count = _ext_functions->at(i)->param_count;
127
128    ext_funcs[i].param_count = param_count;
129    if (param_count == 0) {
130      ext_funcs[i].params = NULL;
131    } else {
132      err = rt.allocate(param_count*sizeof(jvmtiParamInfo),
133                        (unsigned char**)&(ext_funcs[i].params));
134      if (err != JVMTI_ERROR_NONE) {
135        return err;
136      }
137      jvmtiParamInfo* src_params = _ext_functions->at(i)->params;
138      jvmtiParamInfo* dst_params = ext_funcs[i].params;
139
140      for (int j=0; j<param_count; j++) {
141        err = rt.allocate(strlen(src_params[j].name)+1,
142                          (unsigned char**)&(dst_params[j].name));
143        if (err != JVMTI_ERROR_NONE) {
144          return err;
145        }
146        strcpy(dst_params[j].name, src_params[j].name);
147
148        dst_params[j].kind = src_params[j].kind;
149        dst_params[j].base_type = src_params[j].base_type;
150        dst_params[j].null_ok = src_params[j].null_ok;
151      }
152    }
153
154    // errors
155
156    jint error_count = _ext_functions->at(i)->error_count;
157    ext_funcs[i].error_count = error_count;
158    if (error_count == 0) {
159      ext_funcs[i].errors = NULL;
160    } else {
161      err = rt.allocate(error_count*sizeof(jvmtiError),
162                        (unsigned char**)&(ext_funcs[i].errors));
163      if (err != JVMTI_ERROR_NONE) {
164        return err;
165      }
166      memcpy(ext_funcs[i].errors, _ext_functions->at(i)->errors,
167             error_count*sizeof(jvmtiError));
168    }
169  }
170
171  *extension_count_ptr = _ext_functions->length();
172  *extensions = ext_funcs;
173  return JVMTI_ERROR_NONE;
174}
175
176
177// return the list of extension events
178
179jvmtiError JvmtiExtensions::get_events(JvmtiEnv* env,
180                                       jint* extension_count_ptr,
181                                       jvmtiExtensionEventInfo** extensions)
182{
183  guarantee(_ext_events != NULL, "registration not done");
184
185  ResourceTracker rt(env);
186
187  jvmtiExtensionEventInfo* ext_events;
188  jvmtiError err = rt.allocate(_ext_events->length() * sizeof(jvmtiExtensionEventInfo),
189                               (unsigned char**)&ext_events);
190  if (err != JVMTI_ERROR_NONE) {
191    return err;
192  }
193
194  for (int i=0; i<_ext_events->length(); i++ ) {
195    ext_events[i].extension_event_index = _ext_events->at(i)->extension_event_index;
196
197    char *id = _ext_events->at(i)->id;
198    err = rt.allocate(strlen(id)+1, (unsigned char**)&(ext_events[i].id));
199    if (err != JVMTI_ERROR_NONE) {
200      return err;
201    }
202    strcpy(ext_events[i].id, id);
203
204    char *desc = _ext_events->at(i)->short_description;
205    err = rt.allocate(strlen(desc)+1,
206                      (unsigned char**)&(ext_events[i].short_description));
207    if (err != JVMTI_ERROR_NONE) {
208      return err;
209    }
210    strcpy(ext_events[i].short_description, desc);
211
212    // params
213
214    jint param_count = _ext_events->at(i)->param_count;
215
216    ext_events[i].param_count = param_count;
217    if (param_count == 0) {
218      ext_events[i].params = NULL;
219    } else {
220      err = rt.allocate(param_count*sizeof(jvmtiParamInfo),
221                        (unsigned char**)&(ext_events[i].params));
222      if (err != JVMTI_ERROR_NONE) {
223        return err;
224      }
225      jvmtiParamInfo* src_params = _ext_events->at(i)->params;
226      jvmtiParamInfo* dst_params = ext_events[i].params;
227
228      for (int j=0; j<param_count; j++) {
229        err = rt.allocate(strlen(src_params[j].name)+1,
230                          (unsigned char**)&(dst_params[j].name));
231        if (err != JVMTI_ERROR_NONE) {
232          return err;
233        }
234        strcpy(dst_params[j].name, src_params[j].name);
235
236        dst_params[j].kind = src_params[j].kind;
237        dst_params[j].base_type = src_params[j].base_type;
238        dst_params[j].null_ok = src_params[j].null_ok;
239      }
240    }
241  }
242
243  *extension_count_ptr = _ext_events->length();
244  *extensions = ext_events;
245  return JVMTI_ERROR_NONE;
246}
247
248// set callback for an extension event and enable/disable it.
249
250jvmtiError JvmtiExtensions::set_event_callback(JvmtiEnv* env,
251                                               jint extension_event_index,
252                                               jvmtiExtensionEvent callback)
253{
254  guarantee(_ext_events != NULL, "registration not done");
255
256  jvmtiExtensionEventInfo* event = NULL;
257
258  // if there are extension events registered then validate that the
259  // extension_event_index matches one of the registered events.
260  if (_ext_events != NULL) {
261    for (int i=0; i<_ext_events->length(); i++ ) {
262      if (_ext_events->at(i)->extension_event_index == extension_event_index) {
263         event = _ext_events->at(i);
264         break;
265      }
266    }
267  }
268
269  // invalid event index
270  if (event == NULL) {
271    return JVMTI_ERROR_ILLEGAL_ARGUMENT;
272  }
273
274  JvmtiEventController::set_extension_event_callback(env, extension_event_index,
275                                                     callback);
276
277  return JVMTI_ERROR_NONE;
278}
279