blob: 5dc74456813fa47d94d54866f5b75aa9697a4553 [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,
Alex Light3f33c0a2017-11-08 10:17:37 -080025 *
26 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
27 * or visit www.oracle.com if you need additional information or have any
28 * questions.
29 */
30
31#include <vector>
32
33#include "ti_extension.h"
34
35#include "art_jvmti.h"
Alex Light8c2b9292017-11-09 13:21:01 -080036#include "events.h"
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +000037#include "jni_id_type.h"
38#include "runtime-inl.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080039#include "ti_allocator.h"
Alex Lightc7588752018-02-20 11:15:54 -080040#include "ti_class.h"
Alex Light8c2b9292017-11-09 13:21:01 -080041#include "ti_ddms.h"
Alex Lightb2146942019-03-12 15:46:40 +000042#include "ti_dump.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080043#include "ti_heap.h"
Alex Lightae45cbb2018-10-18 15:49:56 -070044#include "ti_logging.h"
Alex Lightc98f83e2018-07-26 08:28:36 -070045#include "ti_monitor.h"
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +000046#include "ti_redefine.h"
Alex Light639e73b2019-05-17 21:44:36 +000047#include "ti_search.h"
Alex Lightae45cbb2018-10-18 15:49:56 -070048
Alex Light8c2b9292017-11-09 13:21:01 -080049#include "thread-inl.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080050
51namespace openjdkjvmti {
52
53struct CParamInfo {
54 const char* name;
55 jvmtiParamKind kind;
56 jvmtiParamTypes base_type;
57 jboolean null_ok;
58
59 jvmtiParamInfo ToParamInfo(jvmtiEnv* env,
60 /*out*/std::vector<JvmtiUniquePtr<char[]>>* char_buffers,
61 /*out*/jvmtiError* err) const {
62 JvmtiUniquePtr<char[]> param_name = CopyString(env, name, err);
63 char* name_ptr = param_name.get();
64 char_buffers->push_back(std::move(param_name));
Igor Murashkin5573c372017-11-16 13:34:30 -080065 return jvmtiParamInfo{ name_ptr, kind, base_type, null_ok };
Alex Light3f33c0a2017-11-08 10:17:37 -080066 }
67};
68
69jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
70 jint* extension_count_ptr,
71 jvmtiExtensionFunctionInfo** extensions) {
72 if (extension_count_ptr == nullptr || extensions == nullptr) {
73 return ERR(NULL_POINTER);
74 }
75
76 std::vector<jvmtiExtensionFunctionInfo> ext_vector;
77
78 // Holders for allocated values.
79 std::vector<JvmtiUniquePtr<char[]>> char_buffers;
80 std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
81 std::vector<JvmtiUniquePtr<jvmtiError[]>> error_buffers;
82
83 auto add_extension = [&](jvmtiExtensionFunction func,
84 const char* id,
85 const char* short_description,
86 const std::vector<CParamInfo>& params,
87 const std::vector<jvmtiError>& errors) {
88 jvmtiExtensionFunctionInfo func_info;
89 jvmtiError error;
90
91 func_info.func = func;
92
93 JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
94 if (id_ptr == nullptr) {
95 return error;
96 }
97 func_info.id = id_ptr.get();
98 char_buffers.push_back(std::move(id_ptr));
99
100 JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
101 if (descr == nullptr) {
102 return error;
103 }
104 func_info.short_description = descr.get();
105 char_buffers.push_back(std::move(descr));
106
107 func_info.param_count = params.size();
108 if (!params.empty()) {
109 JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
110 AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
111 if (params_ptr == nullptr) {
112 return error;
113 }
114 func_info.params = params_ptr.get();
115 param_buffers.push_back(std::move(params_ptr));
116
117 for (jint i = 0; i != func_info.param_count; ++i) {
118 func_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
119 if (error != OK) {
120 return error;
121 }
122 }
123 } else {
124 func_info.params = nullptr;
125 }
126
127 func_info.error_count = errors.size();
128 if (!errors.empty()) {
129 JvmtiUniquePtr<jvmtiError[]> errors_ptr =
130 AllocJvmtiUniquePtr<jvmtiError[]>(env, errors.size(), &error);
131 if (errors_ptr == nullptr) {
132 return error;
133 }
134 func_info.errors = errors_ptr.get();
135 error_buffers.push_back(std::move(errors_ptr));
136
137 for (jint i = 0; i != func_info.error_count; ++i) {
138 func_info.errors[i] = errors[i];
139 }
140 } else {
141 func_info.errors = nullptr;
142 }
143
144 ext_vector.push_back(func_info);
145
146 return ERR(NONE);
147 };
148
149 jvmtiError error;
150
151 // Heap extensions.
152 error = add_extension(
153 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetObjectHeapId),
154 "com.android.art.heap.get_object_heap_id",
155 "Retrieve the heap id of the the object tagged with the given argument. An "
156 "arbitrary object is chosen if multiple objects exist with the same tag.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800157 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800158 { "tag", JVMTI_KIND_IN, JVMTI_TYPE_JLONG, false},
159 { "heap_id", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false}
160 },
161 { JVMTI_ERROR_NOT_FOUND });
162 if (error != ERR(NONE)) {
163 return error;
164 }
165
166 error = add_extension(
167 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetHeapName),
168 "com.android.art.heap.get_heap_name",
169 "Retrieve the name of the heap with the given id.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800170 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800171 { "heap_id", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
172 { "heap_name", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false}
173 },
174 { JVMTI_ERROR_ILLEGAL_ARGUMENT });
175 if (error != ERR(NONE)) {
176 return error;
177 }
178
179 error = add_extension(
180 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::IterateThroughHeapExt),
181 "com.android.art.heap.iterate_through_heap_ext",
182 "Iterate through a heap. This is equivalent to the standard IterateThroughHeap function,"
183 " except for additionally passing the heap id of the current object. The jvmtiHeapCallbacks"
184 " structure is reused, with the callbacks field overloaded to a signature of "
185 "jint (*)(jlong, jlong, jlong*, jint length, void*, jint).",
Igor Murashkin5573c372017-11-16 13:34:30 -0800186 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800187 { "heap_filter", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
188 { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true},
189 { "callbacks", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false},
190 { "user_data", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, true}
191 },
Igor Murashkin5573c372017-11-16 13:34:30 -0800192 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800193 ERR(MUST_POSSESS_CAPABILITY),
194 ERR(INVALID_CLASS),
195 ERR(NULL_POINTER),
196 });
197 if (error != ERR(NONE)) {
198 return error;
199 }
200
201 error = add_extension(
202 reinterpret_cast<jvmtiExtensionFunction>(AllocUtil::GetGlobalJvmtiAllocationState),
203 "com.android.art.alloc.get_global_jvmti_allocation_state",
204 "Returns the total amount of memory currently allocated by all jvmtiEnvs through the"
205 " 'Allocate' jvmti function. This does not include any memory that has been deallocated"
206 " through the 'Deallocate' function. This number is approximate and might not correspond"
207 " exactly to the sum of the sizes of all not freed allocations.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800208 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800209 { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
210 },
211 { ERR(NULL_POINTER) });
212 if (error != ERR(NONE)) {
213 return error;
214 }
215
Alex Light8c2b9292017-11-09 13:21:01 -0800216 // DDMS extension
217 error = add_extension(
218 reinterpret_cast<jvmtiExtensionFunction>(DDMSUtil::HandleChunk),
219 "com.android.art.internal.ddm.process_chunk",
220 "Handles a single ddms chunk request and returns a response. The reply data is in the ddms"
221 " chunk format. It returns the processed chunk. This is provided for backwards compatibility"
222 " reasons only. Agents should avoid making use of this extension when possible and instead"
223 " use the other JVMTI entrypoints explicitly.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800224 {
Alex Light8c2b9292017-11-09 13:21:01 -0800225 { "type_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
226 { "length_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
Alex Light6f2a6342017-12-12 09:55:05 -0800227 { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, true },
Alex Light8c2b9292017-11-09 13:21:01 -0800228 { "type_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
229 { "data_len_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
230 { "data_out", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_JBYTE, false }
231 },
232 { ERR(NULL_POINTER), ERR(ILLEGAL_ARGUMENT), ERR(OUT_OF_MEMORY) });
233 if (error != ERR(NONE)) {
234 return error;
235 }
236
Alex Lightc7588752018-02-20 11:15:54 -0800237 // GetClassLoaderClassDescriptors extension
238 error = add_extension(
239 reinterpret_cast<jvmtiExtensionFunction>(ClassUtil::GetClassLoaderClassDescriptors),
240 "com.android.art.class.get_class_loader_class_descriptors",
241 "Retrieves a list of all the classes (as class descriptors) that the given class loader is"
242 " capable of being the defining class loader for. The return format is a list of"
243 " null-terminated descriptor strings of the form \"L/java/lang/Object;\". Each descriptor"
244 " will be in the list at most once. If the class_loader is null the bootclassloader will be"
245 " used. If the class_loader is not null it must either be a java.lang.BootClassLoader, a"
246 " dalvik.system.BaseDexClassLoader or a derived type. The data_out list and all elements"
247 " must be deallocated by the caller.",
248 {
249 { "class_loader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, true },
250 { "class_descriptor_count_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
251 { "data_out", JVMTI_KIND_ALLOC_ALLOC_BUF, JVMTI_TYPE_CCHAR, false },
252 },
253 {
254 ERR(NULL_POINTER),
255 ERR(ILLEGAL_ARGUMENT),
256 ERR(OUT_OF_MEMORY),
257 ERR(NOT_IMPLEMENTED),
258 });
259 if (error != ERR(NONE)) {
260 return error;
261 }
Alex Lightc98f83e2018-07-26 08:28:36 -0700262
263 // Raw monitors no suspend
264 error = add_extension(
265 reinterpret_cast<jvmtiExtensionFunction>(MonitorUtil::RawMonitorEnterNoSuspend),
266 "com.android.art.concurrent.raw_monitor_enter_no_suspend",
267 "Normally entering a monitor will not return until both the monitor is locked and the"
268 " current thread is not suspended. This method will return once the monitor is locked"
269 " even if the thread is suspended. Note that using rawMonitorWait will wait until the"
270 " thread is not suspended again on wakeup and so should be avoided.",
271 {
272 { "raw_monitor", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false },
273 },
274 {
275 ERR(NULL_POINTER),
276 ERR(INVALID_MONITOR),
277 });
278 if (error != ERR(NONE)) {
279 return error;
280 }
Alex Lightae45cbb2018-10-18 15:49:56 -0700281
282 // GetLastError extension
283 error = add_extension(
284 reinterpret_cast<jvmtiExtensionFunction>(LogUtil::GetLastError),
285 "com.android.art.misc.get_last_error_message",
286 "In some cases the jvmti plugin will log data about errors to the android logcat. These can"
287 " be useful to tools so we make (some) of the messages available here as well. This will"
288 " fill the given 'msg' buffer with the last non-fatal message associated with this"
289 " jvmti-env. Note this is best-effort only, not all log messages will be accessible through"
290 " this API. This will return the last error-message from all threads. Care should be taken"
291 " interpreting the return value when used with a multi-threaded program. The error message"
292 " will only be cleared by a call to 'com.android.art.misc.clear_last_error_message' and will"
293 " not be cleared by intervening successful calls. If no (tracked) error message has been"
294 " sent since the last call to clear_last_error_message this API will return"
295 " JVMTI_ERROR_ABSENT_INFORMATION. Not all failures will cause an error message to be"
296 " recorded.",
297 {
298 { "msg", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false },
299 },
300 {
301 ERR(NULL_POINTER),
302 ERR(ABSENT_INFORMATION),
303 });
304 if (error != ERR(NONE)) {
305 return error;
306 }
307
308 // ClearLastError extension
309 error = add_extension(
310 reinterpret_cast<jvmtiExtensionFunction>(LogUtil::ClearLastError),
311 "com.android.art.misc.clear_last_error_message",
312 "Clears the error message returned by 'com.android.art.misc.get_last_error_message'.",
313 { },
314 { });
315 if (error != ERR(NONE)) {
316 return error;
317 }
318
Alex Lightb2146942019-03-12 15:46:40 +0000319 // DumpInternalState
320 error = add_extension(
321 reinterpret_cast<jvmtiExtensionFunction>(DumpUtil::DumpInternalState),
322 "com.android.art.misc.get_plugin_internal_state",
323 "Gets internal state about the plugin and serializes it to the given msg. "
324 "There is no particular format to this message beyond being human readable.",
325 {
326 { "msg", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false },
327 },
328 { ERR(NULL_POINTER) });
329 if (error != ERR(NONE)) {
330 return error;
331 }
332
Alex Light639e73b2019-05-17 21:44:36 +0000333 // AddToDexClassLoader
334 error = add_extension(
335 reinterpret_cast<jvmtiExtensionFunction>(SearchUtil::AddToDexClassLoader),
336 "com.android.art.classloader.add_to_dex_class_loader",
337 "Adds a dexfile to a given dalvik.system.BaseDexClassLoader in a manner similar to"
338 " AddToSystemClassLoader.",
339 {
340 { "classloader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, false },
341 { "segment", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, false },
342 },
343 {
344 ERR(NULL_POINTER),
345 ERR(CLASS_LOADER_UNSUPPORTED),
346 ERR(ILLEGAL_ARGUMENT),
347 ERR(WRONG_PHASE),
348 });
349 if (error != ERR(NONE)) {
350 return error;
351 }
352
353 // AddToDexClassLoaderInMemory
354 error = add_extension(
355 reinterpret_cast<jvmtiExtensionFunction>(SearchUtil::AddToDexClassLoaderInMemory),
356 "com.android.art.classloader.add_to_dex_class_loader_in_memory",
357 "Adds a dexfile buffer to a given dalvik.system.BaseDexClassLoader in a manner similar to"
358 " AddToSystemClassLoader. This may only be done during the LIVE phase. The buffer is copied"
359 " and the caller is responsible for deallocating it after this call.",
360 {
361 { "classloader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, false },
362 { "dex_bytes", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false },
363 { "dex_bytes_len", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
364 },
365 {
366 ERR(NULL_POINTER),
367 ERR(CLASS_LOADER_UNSUPPORTED),
368 ERR(ILLEGAL_ARGUMENT),
369 ERR(WRONG_PHASE),
370 });
371 if (error != ERR(NONE)) {
372 return error;
373 }
374
Alex Lightc14ec8f2019-07-18 16:08:41 -0700375 // ChangeArraySize
376 error = add_extension(
377 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::ChangeArraySize),
378 "com.android.art.heap.change_array_size",
379 "Changes the size of a java array. As far as all JNI and java code is concerned this is"
380 " atomic. Must have can_tag_objects capability. If the new length of the array is smaller"
381 " than the original length, then the array will be truncated to the new length. Otherwise,"
382 " all new slots will be filled with null, 0, or False as appropriate for the array type.",
383 {
384 { "array", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, false },
385 { "new_size", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
386 },
387 {
388 ERR(NULL_POINTER),
389 ERR(MUST_POSSESS_CAPABILITY),
390 ERR(ILLEGAL_ARGUMENT),
391 ERR(OUT_OF_MEMORY),
392 });
393 if (error != ERR(NONE)) {
394 return error;
395 }
396
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +0000397 // These require index-ids and debuggable to function
398 art::Runtime* runtime = art::Runtime::Current();
399 if (runtime->GetJniIdType() == art::JniIdType::kIndices &&
400 (runtime->GetInstrumentation()->IsForcedInterpretOnly() || runtime->IsJavaDebuggable())) {
401 // IsStructurallyModifiableClass
402 error = add_extension(
403 reinterpret_cast<jvmtiExtensionFunction>(Redefiner::IsStructurallyModifiableClass),
404 "com.android.art.class.is_structurally_modifiable_class",
405 "Returns whether a class can potentially be 'structurally' redefined using the various"
406 " structural redefinition extensions provided.",
407 {
408 { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, false },
409 { "result", JVMTI_KIND_OUT, JVMTI_TYPE_JBOOLEAN, false },
410 },
411 {
412 ERR(INVALID_CLASS),
413 ERR(NULL_POINTER),
414 });
415 if (error != ERR(NONE)) {
416 return error;
417 }
418
419 // StructurallyRedefineClass
420 error = add_extension(
421 reinterpret_cast<jvmtiExtensionFunction>(Redefiner::StructurallyRedefineClassDirect),
422 "com.android.art.UNSAFE.class.structurally_redefine_class_direct",
423 "Temporary prototype entrypoint for redefining a single class structurally. Currently this"
424 " only supports adding new static fields to a class without any instances."
425 " ClassFileLoadHook events will NOT be triggered. This does not currently support creating"
426 " obsolete methods. This function only has rudimentary error checking. This should not be"
427 " used except for testing.",
428 {
429 { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, false },
430 { "new_def", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false },
431 { "new_def_len", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
432 },
433 {
434 ERR(CLASS_LOADER_UNSUPPORTED),
435 ERR(FAILS_VERIFICATION),
436 ERR(ILLEGAL_ARGUMENT),
437 ERR(INVALID_CLASS),
438 ERR(MUST_POSSESS_CAPABILITY),
439 ERR(MUST_POSSESS_CAPABILITY),
440 ERR(NULL_POINTER),
441 ERR(OUT_OF_MEMORY),
442 ERR(UNMODIFIABLE_CLASS),
443 ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED),
444 ERR(UNSUPPORTED_REDEFINITION_METHOD_ADDED),
445 ERR(UNSUPPORTED_REDEFINITION_METHOD_DELETED),
446 ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED),
447 });
448 if (error != ERR(NONE)) {
449 return error;
450 }
451 } else {
452 LOG(INFO) << "debuggable & jni-type indices are required to implement structural "
453 << "class redefinition extensions.";
454 }
455
Alex Light3f33c0a2017-11-08 10:17:37 -0800456 // Copy into output buffer.
457
458 *extension_count_ptr = ext_vector.size();
459 JvmtiUniquePtr<jvmtiExtensionFunctionInfo[]> out_data =
460 AllocJvmtiUniquePtr<jvmtiExtensionFunctionInfo[]>(env, ext_vector.size(), &error);
461 if (out_data == nullptr) {
462 return error;
463 }
464 memcpy(out_data.get(),
465 ext_vector.data(),
466 ext_vector.size() * sizeof(jvmtiExtensionFunctionInfo));
467 *extensions = out_data.release();
468
469 // Release all the buffer holders, we're OK now.
470 for (auto& holder : char_buffers) {
471 holder.release();
472 }
473 for (auto& holder : param_buffers) {
474 holder.release();
475 }
476 for (auto& holder : error_buffers) {
477 holder.release();
478 }
479
480 return OK;
481}
482
483
Alex Light8c2b9292017-11-09 13:21:01 -0800484jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env,
Alex Light3f33c0a2017-11-08 10:17:37 -0800485 jint* extension_count_ptr,
486 jvmtiExtensionEventInfo** extensions) {
Alex Light8c2b9292017-11-09 13:21:01 -0800487 std::vector<jvmtiExtensionEventInfo> ext_vector;
488
489 // Holders for allocated values.
490 std::vector<JvmtiUniquePtr<char[]>> char_buffers;
491 std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
492
493 auto add_extension = [&](ArtJvmtiEvent extension_event_index,
494 const char* id,
495 const char* short_description,
496 const std::vector<CParamInfo>& params) {
497 DCHECK(IsExtensionEvent(extension_event_index));
498 jvmtiExtensionEventInfo event_info;
499 jvmtiError error;
500
501 event_info.extension_event_index = static_cast<jint>(extension_event_index);
502
503 JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
504 if (id_ptr == nullptr) {
505 return error;
506 }
507 event_info.id = id_ptr.get();
508 char_buffers.push_back(std::move(id_ptr));
509
510 JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
511 if (descr == nullptr) {
512 return error;
513 }
514 event_info.short_description = descr.get();
515 char_buffers.push_back(std::move(descr));
516
517 event_info.param_count = params.size();
518 if (!params.empty()) {
519 JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
520 AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
521 if (params_ptr == nullptr) {
522 return error;
523 }
524 event_info.params = params_ptr.get();
525 param_buffers.push_back(std::move(params_ptr));
526
527 for (jint i = 0; i != event_info.param_count; ++i) {
528 event_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
529 if (error != OK) {
530 return error;
531 }
532 }
533 } else {
534 event_info.params = nullptr;
535 }
536
537 ext_vector.push_back(event_info);
538
539 return ERR(NONE);
540 };
541
542 jvmtiError error;
543 error = add_extension(
544 ArtJvmtiEvent::kDdmPublishChunk,
545 "com.android.art.internal.ddm.publish_chunk",
546 "Called when there is new ddms information that the agent or other clients can use. The"
547 " agent is given the 'type' of the ddms chunk and a 'data_size' byte-buffer in 'data'."
548 " The 'data' pointer is only valid for the duration of the publish_chunk event. The agent"
549 " is responsible for interpreting the information present in the 'data' buffer. This is"
550 " provided for backwards-compatibility support only. Agents should prefer to use relevant"
551 " JVMTI events and functions above listening for this event.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800552 {
Alex Light8c2b9292017-11-09 13:21:01 -0800553 { "jni_env", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, false },
554 { "type", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
555 { "data_size", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
556 { "data", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, false },
557 });
558 if (error != OK) {
559 return error;
560 }
Alex Light72d7e942019-07-23 13:10:20 -0700561 error = add_extension(
562 ArtJvmtiEvent::kObsoleteObjectCreated,
563 "com.android.art.heap.obsolete_object_created",
564 "Called when an obsolete object is created.\n"
565 "An object becomes obsolete when, due to some jvmti function call all references to the"
566 " object are replaced with a reference to a different object. After this call finishes there"
567 " will be no strong references to the obsolete object anywere. If the object is retrieved"
568 " using GetObjectsWithTags its type (class) may have changed and any data it contains may"
569 " have been deleted. This is primarily designed to support memory tracking agents which make"
570 " use of the ObjectFree and VMObjectAlloc events for tracking. To support this use-case if"
571 " this event is not being handled it will by default act as though the following code was"
572 " registered as a handler:\n"
573 "\n"
574 " void HandleObsoleteObjectCreated(jvmtiEnv* env, jlong* obsolete_tag, jlong* new_tag) {\n"
575 " jlong temp = *obsolete_tag;\n"
576 " *obsolete_tag = *new_tag;\n"
577 " *new_tag = temp;\n"
578 " }\n"
579 "\n"
580 "Note that this event does not support filtering based on thread. This event has the same"
581 " restrictions on JNI and JVMTI function calls as the ObjectFree event.\n"
582 "\n"
583 "Arguments:\n"
584 " obsolete_tag: Pointer to the tag the old object (now obsolete) has. Setting the pointer"
585 " will update the tag value.\n"
586 " new_tag: Pointer to the tag the new object (replacing the obsolete one) has. Setting the"
587 " pointer will update the tag value.",
588 {
589 { "obsolete_tag", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JLONG, false },
590 { "new_tag", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JLONG, false },
591 });
592 if (error != OK) {
593 return error;
594 }
Alex Light8c2b9292017-11-09 13:21:01 -0800595
596 // Copy into output buffer.
597
598 *extension_count_ptr = ext_vector.size();
599 JvmtiUniquePtr<jvmtiExtensionEventInfo[]> out_data =
600 AllocJvmtiUniquePtr<jvmtiExtensionEventInfo[]>(env, ext_vector.size(), &error);
601 if (out_data == nullptr) {
602 return error;
603 }
604 memcpy(out_data.get(),
605 ext_vector.data(),
606 ext_vector.size() * sizeof(jvmtiExtensionEventInfo));
607 *extensions = out_data.release();
608
609 // Release all the buffer holders, we're OK now.
610 for (auto& holder : char_buffers) {
611 holder.release();
612 }
613 for (auto& holder : param_buffers) {
614 holder.release();
615 }
616
Alex Light3f33c0a2017-11-08 10:17:37 -0800617 return OK;
618}
619
Alex Light8c2b9292017-11-09 13:21:01 -0800620jvmtiError ExtensionUtil::SetExtensionEventCallback(jvmtiEnv* env,
621 jint extension_event_index,
622 jvmtiExtensionEvent callback,
623 EventHandler* event_handler) {
624 if (!IsExtensionEvent(extension_event_index)) {
625 return ERR(ILLEGAL_ARGUMENT);
626 }
627 ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
628 jvmtiEventMode mode = callback == nullptr ? JVMTI_DISABLE : JVMTI_ENABLE;
629 // Lock the event_info_mutex_ while we set the event to make sure it isn't lost by a concurrent
630 // change to the normal callbacks.
631 {
632 art::WriterMutexLock lk(art::Thread::Current(), art_env->event_info_mutex_);
633 if (art_env->event_callbacks.get() == nullptr) {
634 art_env->event_callbacks.reset(new ArtJvmtiEventCallbacks());
635 }
636 jvmtiError err = art_env->event_callbacks->Set(extension_event_index, callback);
637 if (err != OK) {
638 return err;
639 }
640 }
641 return event_handler->SetEvent(art_env,
Andreas Gampe6e897762018-10-16 13:09:32 -0700642 /*thread=*/nullptr,
Alex Light8c2b9292017-11-09 13:21:01 -0800643 static_cast<ArtJvmtiEvent>(extension_event_index),
644 mode);
Alex Light3f33c0a2017-11-08 10:17:37 -0800645}
646
647} // namespace openjdkjvmti