• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2017 The Android Open Source Project
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This file implements interfaces from the file jvmti.h. This implementation
5  * is licensed under the same terms as the file jvmti.h.  The
6  * copyright and license information for the file jvmti.h follows.
7  *
8  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10  *
11  * This code is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License version 2 only, as
13  * published by the Free Software Foundation.  Oracle designates this
14  * particular file as subject to the "Classpath" exception as provided
15  * by Oracle in the LICENSE file that accompanied this code.
16  *
17  * This code is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20  * version 2 for more details (a copy is included in the LICENSE file that
21  * accompanied this code).
22  *
23  * You should have received a copy of the GNU General Public License version
24  * 2 along with this work; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26  *
27  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28  * or visit www.oracle.com if you need additional information or have any
29  * questions.
30  */
31 
32 #include <vector>
33 
34 #include "ti_extension.h"
35 
36 #include "art_jvmti.h"
37 #include "events.h"
38 #include "ti_allocator.h"
39 #include "ti_class.h"
40 #include "ti_ddms.h"
41 #include "ti_heap.h"
42 #include "thread-inl.h"
43 
44 namespace openjdkjvmti {
45 
46 struct CParamInfo {
47   const char* name;
48   jvmtiParamKind kind;
49   jvmtiParamTypes base_type;
50   jboolean null_ok;
51 
ToParamInfoopenjdkjvmti::CParamInfo52   jvmtiParamInfo ToParamInfo(jvmtiEnv* env,
53                              /*out*/std::vector<JvmtiUniquePtr<char[]>>* char_buffers,
54                              /*out*/jvmtiError* err) const {
55     JvmtiUniquePtr<char[]> param_name = CopyString(env, name, err);
56     char* name_ptr = param_name.get();
57     char_buffers->push_back(std::move(param_name));
58     return jvmtiParamInfo{ name_ptr, kind, base_type, null_ok };
59   }
60 };
61 
GetExtensionFunctions(jvmtiEnv * env,jint * extension_count_ptr,jvmtiExtensionFunctionInfo ** extensions)62 jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
63                                                 jint* extension_count_ptr,
64                                                 jvmtiExtensionFunctionInfo** extensions) {
65   if (extension_count_ptr == nullptr || extensions == nullptr) {
66     return ERR(NULL_POINTER);
67   }
68 
69   std::vector<jvmtiExtensionFunctionInfo> ext_vector;
70 
71   // Holders for allocated values.
72   std::vector<JvmtiUniquePtr<char[]>> char_buffers;
73   std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
74   std::vector<JvmtiUniquePtr<jvmtiError[]>> error_buffers;
75 
76   auto add_extension = [&](jvmtiExtensionFunction func,
77                            const char* id,
78                            const char* short_description,
79                            const std::vector<CParamInfo>& params,
80                            const std::vector<jvmtiError>& errors) {
81     jvmtiExtensionFunctionInfo func_info;
82     jvmtiError error;
83 
84     func_info.func = func;
85 
86     JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
87     if (id_ptr == nullptr) {
88       return error;
89     }
90     func_info.id = id_ptr.get();
91     char_buffers.push_back(std::move(id_ptr));
92 
93     JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
94     if (descr == nullptr) {
95       return error;
96     }
97     func_info.short_description = descr.get();
98     char_buffers.push_back(std::move(descr));
99 
100     func_info.param_count = params.size();
101     if (!params.empty()) {
102       JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
103           AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
104       if (params_ptr == nullptr) {
105         return error;
106       }
107       func_info.params = params_ptr.get();
108       param_buffers.push_back(std::move(params_ptr));
109 
110       for (jint i = 0; i != func_info.param_count; ++i) {
111         func_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
112         if (error != OK) {
113           return error;
114         }
115       }
116     } else {
117       func_info.params = nullptr;
118     }
119 
120     func_info.error_count = errors.size();
121     if (!errors.empty()) {
122       JvmtiUniquePtr<jvmtiError[]> errors_ptr =
123           AllocJvmtiUniquePtr<jvmtiError[]>(env, errors.size(), &error);
124       if (errors_ptr == nullptr) {
125         return error;
126       }
127       func_info.errors = errors_ptr.get();
128       error_buffers.push_back(std::move(errors_ptr));
129 
130       for (jint i = 0; i != func_info.error_count; ++i) {
131         func_info.errors[i] = errors[i];
132       }
133     } else {
134       func_info.errors = nullptr;
135     }
136 
137     ext_vector.push_back(func_info);
138 
139     return ERR(NONE);
140   };
141 
142   jvmtiError error;
143 
144   // Heap extensions.
145   error = add_extension(
146       reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetObjectHeapId),
147       "com.android.art.heap.get_object_heap_id",
148       "Retrieve the heap id of the the object tagged with the given argument. An "
149           "arbitrary object is chosen if multiple objects exist with the same tag.",
150       {
151           { "tag", JVMTI_KIND_IN, JVMTI_TYPE_JLONG, false},
152           { "heap_id", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false}
153       },
154       { JVMTI_ERROR_NOT_FOUND });
155   if (error != ERR(NONE)) {
156     return error;
157   }
158 
159   error = add_extension(
160       reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetHeapName),
161       "com.android.art.heap.get_heap_name",
162       "Retrieve the name of the heap with the given id.",
163       {
164           { "heap_id", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
165           { "heap_name", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false}
166       },
167       { JVMTI_ERROR_ILLEGAL_ARGUMENT });
168   if (error != ERR(NONE)) {
169     return error;
170   }
171 
172   error = add_extension(
173       reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::IterateThroughHeapExt),
174       "com.android.art.heap.iterate_through_heap_ext",
175       "Iterate through a heap. This is equivalent to the standard IterateThroughHeap function,"
176       " except for additionally passing the heap id of the current object. The jvmtiHeapCallbacks"
177       " structure is reused, with the callbacks field overloaded to a signature of "
178       "jint (*)(jlong, jlong, jlong*, jint length, void*, jint).",
179       {
180           { "heap_filter", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
181           { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true},
182           { "callbacks", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false},
183           { "user_data", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, true}
184       },
185       {
186           ERR(MUST_POSSESS_CAPABILITY),
187           ERR(INVALID_CLASS),
188           ERR(NULL_POINTER),
189       });
190   if (error != ERR(NONE)) {
191     return error;
192   }
193 
194   error = add_extension(
195       reinterpret_cast<jvmtiExtensionFunction>(AllocUtil::GetGlobalJvmtiAllocationState),
196       "com.android.art.alloc.get_global_jvmti_allocation_state",
197       "Returns the total amount of memory currently allocated by all jvmtiEnvs through the"
198       " 'Allocate' jvmti function. This does not include any memory that has been deallocated"
199       " through the 'Deallocate' function. This number is approximate and might not correspond"
200       " exactly to the sum of the sizes of all not freed allocations.",
201       {
202           { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
203       },
204       { ERR(NULL_POINTER) });
205   if (error != ERR(NONE)) {
206     return error;
207   }
208 
209   // DDMS extension
210   error = add_extension(
211       reinterpret_cast<jvmtiExtensionFunction>(DDMSUtil::HandleChunk),
212       "com.android.art.internal.ddm.process_chunk",
213       "Handles a single ddms chunk request and returns a response. The reply data is in the ddms"
214       " chunk format. It returns the processed chunk. This is provided for backwards compatibility"
215       " reasons only. Agents should avoid making use of this extension when possible and instead"
216       " use the other JVMTI entrypoints explicitly.",
217       {
218         { "type_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
219         { "length_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
220         { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, true },
221         { "type_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
222         { "data_len_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
223         { "data_out", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_JBYTE, false }
224       },
225       { ERR(NULL_POINTER), ERR(ILLEGAL_ARGUMENT), ERR(OUT_OF_MEMORY) });
226   if (error != ERR(NONE)) {
227     return error;
228   }
229 
230   // GetClassLoaderClassDescriptors extension
231   error = add_extension(
232       reinterpret_cast<jvmtiExtensionFunction>(ClassUtil::GetClassLoaderClassDescriptors),
233       "com.android.art.class.get_class_loader_class_descriptors",
234       "Retrieves a list of all the classes (as class descriptors) that the given class loader is"
235       " capable of being the defining class loader for. The return format is a list of"
236       " null-terminated descriptor strings of the form \"L/java/lang/Object;\". Each descriptor"
237       " will be in the list at most once. If the class_loader is null the bootclassloader will be"
238       " used. If the class_loader is not null it must either be a java.lang.BootClassLoader, a"
239       " dalvik.system.BaseDexClassLoader or a derived type. The data_out list and all elements"
240       " must be deallocated by the caller.",
241       {
242         { "class_loader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, true },
243         { "class_descriptor_count_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
244         { "data_out", JVMTI_KIND_ALLOC_ALLOC_BUF, JVMTI_TYPE_CCHAR, false },
245       },
246       {
247         ERR(NULL_POINTER),
248         ERR(ILLEGAL_ARGUMENT),
249         ERR(OUT_OF_MEMORY),
250         ERR(NOT_IMPLEMENTED),
251       });
252   if (error != ERR(NONE)) {
253     return error;
254   }
255   // Copy into output buffer.
256 
257   *extension_count_ptr = ext_vector.size();
258   JvmtiUniquePtr<jvmtiExtensionFunctionInfo[]> out_data =
259       AllocJvmtiUniquePtr<jvmtiExtensionFunctionInfo[]>(env, ext_vector.size(), &error);
260   if (out_data == nullptr) {
261     return error;
262   }
263   memcpy(out_data.get(),
264           ext_vector.data(),
265           ext_vector.size() * sizeof(jvmtiExtensionFunctionInfo));
266   *extensions = out_data.release();
267 
268   // Release all the buffer holders, we're OK now.
269   for (auto& holder : char_buffers) {
270     holder.release();
271   }
272   for (auto& holder : param_buffers) {
273     holder.release();
274   }
275   for (auto& holder : error_buffers) {
276     holder.release();
277   }
278 
279   return OK;
280 }
281 
282 
GetExtensionEvents(jvmtiEnv * env,jint * extension_count_ptr,jvmtiExtensionEventInfo ** extensions)283 jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env,
284                                              jint* extension_count_ptr,
285                                              jvmtiExtensionEventInfo** extensions) {
286   std::vector<jvmtiExtensionEventInfo> ext_vector;
287 
288   // Holders for allocated values.
289   std::vector<JvmtiUniquePtr<char[]>> char_buffers;
290   std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
291 
292   auto add_extension = [&](ArtJvmtiEvent extension_event_index,
293                            const char* id,
294                            const char* short_description,
295                            const std::vector<CParamInfo>& params) {
296     DCHECK(IsExtensionEvent(extension_event_index));
297     jvmtiExtensionEventInfo event_info;
298     jvmtiError error;
299 
300     event_info.extension_event_index = static_cast<jint>(extension_event_index);
301 
302     JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
303     if (id_ptr == nullptr) {
304       return error;
305     }
306     event_info.id = id_ptr.get();
307     char_buffers.push_back(std::move(id_ptr));
308 
309     JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
310     if (descr == nullptr) {
311       return error;
312     }
313     event_info.short_description = descr.get();
314     char_buffers.push_back(std::move(descr));
315 
316     event_info.param_count = params.size();
317     if (!params.empty()) {
318       JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
319           AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
320       if (params_ptr == nullptr) {
321         return error;
322       }
323       event_info.params = params_ptr.get();
324       param_buffers.push_back(std::move(params_ptr));
325 
326       for (jint i = 0; i != event_info.param_count; ++i) {
327         event_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
328         if (error != OK) {
329           return error;
330         }
331       }
332     } else {
333       event_info.params = nullptr;
334     }
335 
336     ext_vector.push_back(event_info);
337 
338     return ERR(NONE);
339   };
340 
341   jvmtiError error;
342   error = add_extension(
343       ArtJvmtiEvent::kDdmPublishChunk,
344       "com.android.art.internal.ddm.publish_chunk",
345       "Called when there is new ddms information that the agent or other clients can use. The"
346       " agent is given the 'type' of the ddms chunk and a 'data_size' byte-buffer in 'data'."
347       " The 'data' pointer is only valid for the duration of the publish_chunk event. The agent"
348       " is responsible for interpreting the information present in the 'data' buffer. This is"
349       " provided for backwards-compatibility support only. Agents should prefer to use relevant"
350       " JVMTI events and functions above listening for this event.",
351       {
352         { "jni_env", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, false },
353         { "type", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
354         { "data_size", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
355         { "data",  JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, false },
356       });
357   if (error != OK) {
358     return error;
359   }
360 
361   // Copy into output buffer.
362 
363   *extension_count_ptr = ext_vector.size();
364   JvmtiUniquePtr<jvmtiExtensionEventInfo[]> out_data =
365       AllocJvmtiUniquePtr<jvmtiExtensionEventInfo[]>(env, ext_vector.size(), &error);
366   if (out_data == nullptr) {
367     return error;
368   }
369   memcpy(out_data.get(),
370          ext_vector.data(),
371          ext_vector.size() * sizeof(jvmtiExtensionEventInfo));
372   *extensions = out_data.release();
373 
374   // Release all the buffer holders, we're OK now.
375   for (auto& holder : char_buffers) {
376     holder.release();
377   }
378   for (auto& holder : param_buffers) {
379     holder.release();
380   }
381 
382   return OK;
383 }
384 
SetExtensionEventCallback(jvmtiEnv * env,jint extension_event_index,jvmtiExtensionEvent callback,EventHandler * event_handler)385 jvmtiError ExtensionUtil::SetExtensionEventCallback(jvmtiEnv* env,
386                                                     jint extension_event_index,
387                                                     jvmtiExtensionEvent callback,
388                                                     EventHandler* event_handler) {
389   if (!IsExtensionEvent(extension_event_index)) {
390     return ERR(ILLEGAL_ARGUMENT);
391   }
392   ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
393   jvmtiEventMode mode = callback == nullptr ? JVMTI_DISABLE : JVMTI_ENABLE;
394   // Lock the event_info_mutex_ while we set the event to make sure it isn't lost by a concurrent
395   // change to the normal callbacks.
396   {
397     art::WriterMutexLock lk(art::Thread::Current(), art_env->event_info_mutex_);
398     if (art_env->event_callbacks.get() == nullptr) {
399       art_env->event_callbacks.reset(new ArtJvmtiEventCallbacks());
400     }
401     jvmtiError err = art_env->event_callbacks->Set(extension_event_index, callback);
402     if (err != OK) {
403       return err;
404     }
405   }
406   return event_handler->SetEvent(art_env,
407                                  /*event_thread*/nullptr,
408                                  static_cast<ArtJvmtiEvent>(extension_event_index),
409                                  mode);
410 }
411 
412 }  // namespace openjdkjvmti
413