• 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_dump.h"
42 #include "ti_heap.h"
43 #include "ti_logging.h"
44 #include "ti_monitor.h"
45 
46 #include "thread-inl.h"
47 
48 namespace openjdkjvmti {
49 
50 struct CParamInfo {
51   const char* name;
52   jvmtiParamKind kind;
53   jvmtiParamTypes base_type;
54   jboolean null_ok;
55 
ToParamInfoopenjdkjvmti::CParamInfo56   jvmtiParamInfo ToParamInfo(jvmtiEnv* env,
57                              /*out*/std::vector<JvmtiUniquePtr<char[]>>* char_buffers,
58                              /*out*/jvmtiError* err) const {
59     JvmtiUniquePtr<char[]> param_name = CopyString(env, name, err);
60     char* name_ptr = param_name.get();
61     char_buffers->push_back(std::move(param_name));
62     return jvmtiParamInfo{ name_ptr, kind, base_type, null_ok };
63   }
64 };
65 
GetExtensionFunctions(jvmtiEnv * env,jint * extension_count_ptr,jvmtiExtensionFunctionInfo ** extensions)66 jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
67                                                 jint* extension_count_ptr,
68                                                 jvmtiExtensionFunctionInfo** extensions) {
69   if (extension_count_ptr == nullptr || extensions == nullptr) {
70     return ERR(NULL_POINTER);
71   }
72 
73   std::vector<jvmtiExtensionFunctionInfo> ext_vector;
74 
75   // Holders for allocated values.
76   std::vector<JvmtiUniquePtr<char[]>> char_buffers;
77   std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
78   std::vector<JvmtiUniquePtr<jvmtiError[]>> error_buffers;
79 
80   auto add_extension = [&](jvmtiExtensionFunction func,
81                            const char* id,
82                            const char* short_description,
83                            const std::vector<CParamInfo>& params,
84                            const std::vector<jvmtiError>& errors) {
85     jvmtiExtensionFunctionInfo func_info;
86     jvmtiError error;
87 
88     func_info.func = func;
89 
90     JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
91     if (id_ptr == nullptr) {
92       return error;
93     }
94     func_info.id = id_ptr.get();
95     char_buffers.push_back(std::move(id_ptr));
96 
97     JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
98     if (descr == nullptr) {
99       return error;
100     }
101     func_info.short_description = descr.get();
102     char_buffers.push_back(std::move(descr));
103 
104     func_info.param_count = params.size();
105     if (!params.empty()) {
106       JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
107           AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
108       if (params_ptr == nullptr) {
109         return error;
110       }
111       func_info.params = params_ptr.get();
112       param_buffers.push_back(std::move(params_ptr));
113 
114       for (jint i = 0; i != func_info.param_count; ++i) {
115         func_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
116         if (error != OK) {
117           return error;
118         }
119       }
120     } else {
121       func_info.params = nullptr;
122     }
123 
124     func_info.error_count = errors.size();
125     if (!errors.empty()) {
126       JvmtiUniquePtr<jvmtiError[]> errors_ptr =
127           AllocJvmtiUniquePtr<jvmtiError[]>(env, errors.size(), &error);
128       if (errors_ptr == nullptr) {
129         return error;
130       }
131       func_info.errors = errors_ptr.get();
132       error_buffers.push_back(std::move(errors_ptr));
133 
134       for (jint i = 0; i != func_info.error_count; ++i) {
135         func_info.errors[i] = errors[i];
136       }
137     } else {
138       func_info.errors = nullptr;
139     }
140 
141     ext_vector.push_back(func_info);
142 
143     return ERR(NONE);
144   };
145 
146   jvmtiError error;
147 
148   // Heap extensions.
149   error = add_extension(
150       reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetObjectHeapId),
151       "com.android.art.heap.get_object_heap_id",
152       "Retrieve the heap id of the the object tagged with the given argument. An "
153           "arbitrary object is chosen if multiple objects exist with the same tag.",
154       {
155           { "tag", JVMTI_KIND_IN, JVMTI_TYPE_JLONG, false},
156           { "heap_id", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false}
157       },
158       { JVMTI_ERROR_NOT_FOUND });
159   if (error != ERR(NONE)) {
160     return error;
161   }
162 
163   error = add_extension(
164       reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetHeapName),
165       "com.android.art.heap.get_heap_name",
166       "Retrieve the name of the heap with the given id.",
167       {
168           { "heap_id", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
169           { "heap_name", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false}
170       },
171       { JVMTI_ERROR_ILLEGAL_ARGUMENT });
172   if (error != ERR(NONE)) {
173     return error;
174   }
175 
176   error = add_extension(
177       reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::IterateThroughHeapExt),
178       "com.android.art.heap.iterate_through_heap_ext",
179       "Iterate through a heap. This is equivalent to the standard IterateThroughHeap function,"
180       " except for additionally passing the heap id of the current object. The jvmtiHeapCallbacks"
181       " structure is reused, with the callbacks field overloaded to a signature of "
182       "jint (*)(jlong, jlong, jlong*, jint length, void*, jint).",
183       {
184           { "heap_filter", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
185           { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true},
186           { "callbacks", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false},
187           { "user_data", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, true}
188       },
189       {
190           ERR(MUST_POSSESS_CAPABILITY),
191           ERR(INVALID_CLASS),
192           ERR(NULL_POINTER),
193       });
194   if (error != ERR(NONE)) {
195     return error;
196   }
197 
198   error = add_extension(
199       reinterpret_cast<jvmtiExtensionFunction>(AllocUtil::GetGlobalJvmtiAllocationState),
200       "com.android.art.alloc.get_global_jvmti_allocation_state",
201       "Returns the total amount of memory currently allocated by all jvmtiEnvs through the"
202       " 'Allocate' jvmti function. This does not include any memory that has been deallocated"
203       " through the 'Deallocate' function. This number is approximate and might not correspond"
204       " exactly to the sum of the sizes of all not freed allocations.",
205       {
206           { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
207       },
208       { ERR(NULL_POINTER) });
209   if (error != ERR(NONE)) {
210     return error;
211   }
212 
213   // DDMS extension
214   error = add_extension(
215       reinterpret_cast<jvmtiExtensionFunction>(DDMSUtil::HandleChunk),
216       "com.android.art.internal.ddm.process_chunk",
217       "Handles a single ddms chunk request and returns a response. The reply data is in the ddms"
218       " chunk format. It returns the processed chunk. This is provided for backwards compatibility"
219       " reasons only. Agents should avoid making use of this extension when possible and instead"
220       " use the other JVMTI entrypoints explicitly.",
221       {
222         { "type_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
223         { "length_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
224         { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, true },
225         { "type_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
226         { "data_len_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
227         { "data_out", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_JBYTE, false }
228       },
229       { ERR(NULL_POINTER), ERR(ILLEGAL_ARGUMENT), ERR(OUT_OF_MEMORY) });
230   if (error != ERR(NONE)) {
231     return error;
232   }
233 
234   // GetClassLoaderClassDescriptors extension
235   error = add_extension(
236       reinterpret_cast<jvmtiExtensionFunction>(ClassUtil::GetClassLoaderClassDescriptors),
237       "com.android.art.class.get_class_loader_class_descriptors",
238       "Retrieves a list of all the classes (as class descriptors) that the given class loader is"
239       " capable of being the defining class loader for. The return format is a list of"
240       " null-terminated descriptor strings of the form \"L/java/lang/Object;\". Each descriptor"
241       " will be in the list at most once. If the class_loader is null the bootclassloader will be"
242       " used. If the class_loader is not null it must either be a java.lang.BootClassLoader, a"
243       " dalvik.system.BaseDexClassLoader or a derived type. The data_out list and all elements"
244       " must be deallocated by the caller.",
245       {
246         { "class_loader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, true },
247         { "class_descriptor_count_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
248         { "data_out", JVMTI_KIND_ALLOC_ALLOC_BUF, JVMTI_TYPE_CCHAR, false },
249       },
250       {
251         ERR(NULL_POINTER),
252         ERR(ILLEGAL_ARGUMENT),
253         ERR(OUT_OF_MEMORY),
254         ERR(NOT_IMPLEMENTED),
255       });
256   if (error != ERR(NONE)) {
257     return error;
258   }
259 
260   // Raw monitors no suspend
261   error = add_extension(
262       reinterpret_cast<jvmtiExtensionFunction>(MonitorUtil::RawMonitorEnterNoSuspend),
263       "com.android.art.concurrent.raw_monitor_enter_no_suspend",
264       "Normally entering a monitor will not return until both the monitor is locked and the"
265       " current thread is not suspended. This method will return once the monitor is locked"
266       " even if the thread is suspended. Note that using rawMonitorWait will wait until the"
267       " thread is not suspended again on wakeup and so should be avoided.",
268       {
269           { "raw_monitor", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false },
270       },
271       {
272         ERR(NULL_POINTER),
273         ERR(INVALID_MONITOR),
274       });
275   if (error != ERR(NONE)) {
276     return error;
277   }
278 
279   // GetLastError extension
280   error = add_extension(
281       reinterpret_cast<jvmtiExtensionFunction>(LogUtil::GetLastError),
282       "com.android.art.misc.get_last_error_message",
283       "In some cases the jvmti plugin will log data about errors to the android logcat. These can"
284       " be useful to tools so we make (some) of the messages available here as well. This will"
285       " fill the given 'msg' buffer with the last non-fatal message associated with this"
286       " jvmti-env. Note this is best-effort only, not all log messages will be accessible through"
287       " this API. This will return the last error-message from all threads. Care should be taken"
288       " interpreting the return value when used with a multi-threaded program. The error message"
289       " will only be cleared by a call to 'com.android.art.misc.clear_last_error_message' and will"
290       " not be cleared by intervening successful calls. If no (tracked) error message has been"
291       " sent since the last call to clear_last_error_message this API will return"
292       " JVMTI_ERROR_ABSENT_INFORMATION. Not all failures will cause an error message to be"
293       " recorded.",
294       {
295           { "msg", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false },
296       },
297       {
298         ERR(NULL_POINTER),
299         ERR(ABSENT_INFORMATION),
300       });
301   if (error != ERR(NONE)) {
302     return error;
303   }
304 
305   // ClearLastError extension
306   error = add_extension(
307       reinterpret_cast<jvmtiExtensionFunction>(LogUtil::ClearLastError),
308       "com.android.art.misc.clear_last_error_message",
309       "Clears the error message returned by 'com.android.art.misc.get_last_error_message'.",
310       { },
311       { });
312   if (error != ERR(NONE)) {
313     return error;
314   }
315 
316   // DumpInternalState
317   error = add_extension(
318       reinterpret_cast<jvmtiExtensionFunction>(DumpUtil::DumpInternalState),
319       "com.android.art.misc.get_plugin_internal_state",
320       "Gets internal state about the plugin and serializes it to the given msg. "
321       "There is no particular format to this message beyond being human readable.",
322       {
323           { "msg", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false },
324       },
325       { ERR(NULL_POINTER) });
326   if (error != ERR(NONE)) {
327     return error;
328   }
329 
330   // Copy into output buffer.
331 
332   *extension_count_ptr = ext_vector.size();
333   JvmtiUniquePtr<jvmtiExtensionFunctionInfo[]> out_data =
334       AllocJvmtiUniquePtr<jvmtiExtensionFunctionInfo[]>(env, ext_vector.size(), &error);
335   if (out_data == nullptr) {
336     return error;
337   }
338   memcpy(out_data.get(),
339           ext_vector.data(),
340           ext_vector.size() * sizeof(jvmtiExtensionFunctionInfo));
341   *extensions = out_data.release();
342 
343   // Release all the buffer holders, we're OK now.
344   for (auto& holder : char_buffers) {
345     holder.release();
346   }
347   for (auto& holder : param_buffers) {
348     holder.release();
349   }
350   for (auto& holder : error_buffers) {
351     holder.release();
352   }
353 
354   return OK;
355 }
356 
357 
GetExtensionEvents(jvmtiEnv * env,jint * extension_count_ptr,jvmtiExtensionEventInfo ** extensions)358 jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env,
359                                              jint* extension_count_ptr,
360                                              jvmtiExtensionEventInfo** extensions) {
361   std::vector<jvmtiExtensionEventInfo> ext_vector;
362 
363   // Holders for allocated values.
364   std::vector<JvmtiUniquePtr<char[]>> char_buffers;
365   std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
366 
367   auto add_extension = [&](ArtJvmtiEvent extension_event_index,
368                            const char* id,
369                            const char* short_description,
370                            const std::vector<CParamInfo>& params) {
371     DCHECK(IsExtensionEvent(extension_event_index));
372     jvmtiExtensionEventInfo event_info;
373     jvmtiError error;
374 
375     event_info.extension_event_index = static_cast<jint>(extension_event_index);
376 
377     JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
378     if (id_ptr == nullptr) {
379       return error;
380     }
381     event_info.id = id_ptr.get();
382     char_buffers.push_back(std::move(id_ptr));
383 
384     JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
385     if (descr == nullptr) {
386       return error;
387     }
388     event_info.short_description = descr.get();
389     char_buffers.push_back(std::move(descr));
390 
391     event_info.param_count = params.size();
392     if (!params.empty()) {
393       JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
394           AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
395       if (params_ptr == nullptr) {
396         return error;
397       }
398       event_info.params = params_ptr.get();
399       param_buffers.push_back(std::move(params_ptr));
400 
401       for (jint i = 0; i != event_info.param_count; ++i) {
402         event_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
403         if (error != OK) {
404           return error;
405         }
406       }
407     } else {
408       event_info.params = nullptr;
409     }
410 
411     ext_vector.push_back(event_info);
412 
413     return ERR(NONE);
414   };
415 
416   jvmtiError error;
417   error = add_extension(
418       ArtJvmtiEvent::kDdmPublishChunk,
419       "com.android.art.internal.ddm.publish_chunk",
420       "Called when there is new ddms information that the agent or other clients can use. The"
421       " agent is given the 'type' of the ddms chunk and a 'data_size' byte-buffer in 'data'."
422       " The 'data' pointer is only valid for the duration of the publish_chunk event. The agent"
423       " is responsible for interpreting the information present in the 'data' buffer. This is"
424       " provided for backwards-compatibility support only. Agents should prefer to use relevant"
425       " JVMTI events and functions above listening for this event.",
426       {
427         { "jni_env", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, false },
428         { "type", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
429         { "data_size", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
430         { "data",  JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, false },
431       });
432   if (error != OK) {
433     return error;
434   }
435 
436   // Copy into output buffer.
437 
438   *extension_count_ptr = ext_vector.size();
439   JvmtiUniquePtr<jvmtiExtensionEventInfo[]> out_data =
440       AllocJvmtiUniquePtr<jvmtiExtensionEventInfo[]>(env, ext_vector.size(), &error);
441   if (out_data == nullptr) {
442     return error;
443   }
444   memcpy(out_data.get(),
445          ext_vector.data(),
446          ext_vector.size() * sizeof(jvmtiExtensionEventInfo));
447   *extensions = out_data.release();
448 
449   // Release all the buffer holders, we're OK now.
450   for (auto& holder : char_buffers) {
451     holder.release();
452   }
453   for (auto& holder : param_buffers) {
454     holder.release();
455   }
456 
457   return OK;
458 }
459 
SetExtensionEventCallback(jvmtiEnv * env,jint extension_event_index,jvmtiExtensionEvent callback,EventHandler * event_handler)460 jvmtiError ExtensionUtil::SetExtensionEventCallback(jvmtiEnv* env,
461                                                     jint extension_event_index,
462                                                     jvmtiExtensionEvent callback,
463                                                     EventHandler* event_handler) {
464   if (!IsExtensionEvent(extension_event_index)) {
465     return ERR(ILLEGAL_ARGUMENT);
466   }
467   ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
468   jvmtiEventMode mode = callback == nullptr ? JVMTI_DISABLE : JVMTI_ENABLE;
469   // Lock the event_info_mutex_ while we set the event to make sure it isn't lost by a concurrent
470   // change to the normal callbacks.
471   {
472     art::WriterMutexLock lk(art::Thread::Current(), art_env->event_info_mutex_);
473     if (art_env->event_callbacks.get() == nullptr) {
474       art_env->event_callbacks.reset(new ArtJvmtiEventCallbacks());
475     }
476     jvmtiError err = art_env->event_callbacks->Set(extension_event_index, callback);
477     if (err != OK) {
478       return err;
479     }
480   }
481   return event_handler->SetEvent(art_env,
482                                  /*thread=*/nullptr,
483                                  static_cast<ArtJvmtiEvent>(extension_event_index),
484                                  mode);
485 }
486 
487 }  // namespace openjdkjvmti
488