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