blob: 5b1a16c3ffde559560761d1951b5580f82ba62d2 [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 Light8c2b9292017-11-09 13:21:01 -080042#include "thread-inl.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080043
44namespace openjdkjvmti {
45
46struct CParamInfo {
47 const char* name;
48 jvmtiParamKind kind;
49 jvmtiParamTypes base_type;
50 jboolean null_ok;
51
52 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));
Igor Murashkin5573c372017-11-16 13:34:30 -080058 return jvmtiParamInfo{ name_ptr, kind, base_type, null_ok };
Alex Light3f33c0a2017-11-08 10:17:37 -080059 }
60};
61
62jvmtiError 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.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800150 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800151 { "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.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800163 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800164 { "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).",
Igor Murashkin5573c372017-11-16 13:34:30 -0800179 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800180 { "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 },
Igor Murashkin5573c372017-11-16 13:34:30 -0800185 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800186 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.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800201 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800202 { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
203 },
204 { ERR(NULL_POINTER) });
205 if (error != ERR(NONE)) {
206 return error;
207 }
208
Alex Light8c2b9292017-11-09 13:21:01 -0800209 // 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.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800217 {
Alex Light8c2b9292017-11-09 13:21:01 -0800218 { "type_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
219 { "length_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
Alex Light6f2a6342017-12-12 09:55:05 -0800220 { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, true },
Alex Light8c2b9292017-11-09 13:21:01 -0800221 { "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
Alex Lightc7588752018-02-20 11:15:54 -0800230 // 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 }
Alex Light3f33c0a2017-11-08 10:17:37 -0800255 // 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
Alex Light8c2b9292017-11-09 13:21:01 -0800283jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env,
Alex Light3f33c0a2017-11-08 10:17:37 -0800284 jint* extension_count_ptr,
285 jvmtiExtensionEventInfo** extensions) {
Alex Light8c2b9292017-11-09 13:21:01 -0800286 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.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800351 {
Alex Light8c2b9292017-11-09 13:21:01 -0800352 { "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
Alex Light3f33c0a2017-11-08 10:17:37 -0800382 return OK;
383}
384
Alex Light8c2b9292017-11-09 13:21:01 -0800385jvmtiError 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);
Alex Light3f33c0a2017-11-08 10:17:37 -0800410}
411
412} // namespace openjdkjvmti