blob: 625fb265397fa9b6fa4141ce6b9abf6c307f4bc8 [file] [log] [blame]
Andreas Gampe3c252f02016-10-27 18:25:17 -07001/* Copyright (C) 2016 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 "ti_method.h"
33
Andreas Gampe49fc60e2017-08-24 13:19:59 -070034#include <type_traits>
35
Andreas Gampe3c252f02016-10-27 18:25:17 -070036#include "art_jvmti.h"
37#include "art_method-inl.h"
38#include "base/enums.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070039#include "base/mutex-inl.h"
Andreas Gampe27dfa052017-02-16 15:04:36 -080040#include "dex_file_annotations.h"
Andreas Gampee2abbc62017-09-15 11:59:26 -070041#include "dex_file_types.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070042#include "events-inl.h"
Alex Light0a5ec3d2017-07-25 16:50:26 -070043#include "jit/jit.h"
Andreas Gampe13b27842016-11-07 16:48:23 -080044#include "jni_internal.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070045#include "mirror/class-inl.h"
46#include "mirror/class_loader.h"
47#include "mirror/object-inl.h"
Andreas Gampe27dfa052017-02-16 15:04:36 -080048#include "mirror/object_array-inl.h"
Andreas Gampe36bcd4f2016-10-28 18:07:18 -070049#include "modifiers.h"
Steven Morelande431e272017-07-18 16:53:49 -070050#include "nativehelper/ScopedLocalRef.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070051#include "runtime_callbacks.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070052#include "scoped_thread_state_change-inl.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070053#include "stack.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070054#include "thread-current-inl.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070055#include "thread_list.h"
Alex Lighte814f9d2017-07-31 16:14:39 -070056#include "ti_stack.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070057#include "ti_thread.h"
Alex Light0af8cde2017-04-20 13:35:05 -070058#include "ti_phase.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070059
60namespace openjdkjvmti {
61
Alex Lightd78ddec2017-04-18 15:20:38 -070062struct TiMethodCallback : public art::MethodCallback {
63 void RegisterNativeMethod(art::ArtMethod* method,
64 const void* cur_method,
65 /*out*/void** new_method)
66 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
67 if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kNativeMethodBind)) {
68 art::Thread* thread = art::Thread::Current();
Alex Light0af8cde2017-04-20 13:35:05 -070069 art::JNIEnvExt* jnienv = thread->GetJniEnv();
Alex Lightd78ddec2017-04-18 15:20:38 -070070 ScopedLocalRef<jthread> thread_jni(
Alex Light0af8cde2017-04-20 13:35:05 -070071 jnienv, PhaseUtil::IsLivePhase() ? jnienv->AddLocalReference<jthread>(thread->GetPeer())
72 : nullptr);
Alex Lightd78ddec2017-04-18 15:20:38 -070073 art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
74 event_handler->DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(
75 thread,
Alex Light0af8cde2017-04-20 13:35:05 -070076 static_cast<JNIEnv*>(jnienv),
Alex Lightd78ddec2017-04-18 15:20:38 -070077 thread_jni.get(),
78 art::jni::EncodeArtMethod(method),
79 const_cast<void*>(cur_method),
80 new_method);
81 }
82 }
83
84 EventHandler* event_handler = nullptr;
85};
86
87TiMethodCallback gMethodCallback;
88
89void MethodUtil::Register(EventHandler* handler) {
90 gMethodCallback.event_handler = handler;
91 art::ScopedThreadStateChange stsc(art::Thread::Current(),
92 art::ThreadState::kWaitingForDebuggerToAttach);
93 art::ScopedSuspendAll ssa("Add method callback");
94 art::Runtime::Current()->GetRuntimeCallbacks()->AddMethodCallback(&gMethodCallback);
95}
96
97void MethodUtil::Unregister() {
98 art::ScopedThreadStateChange stsc(art::Thread::Current(),
99 art::ThreadState::kWaitingForDebuggerToAttach);
100 art::ScopedSuspendAll ssa("Remove method callback");
101 art::Runtime* runtime = art::Runtime::Current();
102 runtime->GetRuntimeCallbacks()->RemoveMethodCallback(&gMethodCallback);
103}
104
Alex Light4c174282017-07-05 10:18:18 -0700105jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
106 jmethodID method,
107 jint* size_ptr,
108 unsigned char** bytecode_ptr) {
109 if (method == nullptr) {
110 return ERR(INVALID_METHODID);
111 }
112 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
113
114 if (art_method->IsNative()) {
115 return ERR(NATIVE_METHOD);
116 }
117
118 if (size_ptr == nullptr || bytecode_ptr == nullptr) {
119 return ERR(NULL_POINTER);
120 }
121
122 art::ScopedObjectAccess soa(art::Thread::Current());
123 const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
124 if (code_item == nullptr) {
125 *size_ptr = 0;
126 *bytecode_ptr = nullptr;
127 return OK;
128 }
129 // 2 bytes per instruction for dex code.
130 *size_ptr = code_item->insns_size_in_code_units_ * 2;
131 jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr);
132 if (err != OK) {
133 return err;
134 }
135 memcpy(*bytecode_ptr, code_item->insns_, *size_ptr);
136 return OK;
137}
138
Andreas Gampef71832e2017-01-09 11:38:04 -0800139jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
140 jmethodID method,
141 jint* size_ptr) {
142 if (method == nullptr) {
143 return ERR(INVALID_METHODID);
144 }
145 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
146
147 if (art_method->IsNative()) {
148 return ERR(NATIVE_METHOD);
149 }
150
151 if (size_ptr == nullptr) {
152 return ERR(NULL_POINTER);
153 }
154
155 art::ScopedObjectAccess soa(art::Thread::Current());
156 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
Andreas Gampee1f79b62017-04-12 21:11:28 -0700157 // Use the shorty.
158 art::ArtMethod* base_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
159 size_t arg_count = art::ArtMethod::NumArgRegisters(base_method->GetShorty());
160 if (!base_method->IsStatic()) {
161 arg_count++;
162 }
163 *size_ptr = static_cast<jint>(arg_count);
Andreas Gampef71832e2017-01-09 11:38:04 -0800164 return ERR(NONE);
165 }
166
167 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
168 *size_ptr = art_method->GetCodeItem()->ins_size_;
169
170 return ERR(NONE);
171}
172
Alex Lightce68cc62017-07-26 10:30:38 -0700173jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
174 jmethodID method,
175 jint* entry_count_ptr,
176 jvmtiLocalVariableEntry** table_ptr) {
177 if (method == nullptr) {
178 return ERR(INVALID_METHODID);
179 }
180 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
181
182 if (art_method->IsNative()) {
183 return ERR(NATIVE_METHOD);
184 }
185
186 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
187 return ERR(NULL_POINTER);
188 }
189
190 art::ScopedObjectAccess soa(art::Thread::Current());
191 const art::DexFile* dex_file = art_method->GetDexFile();
192 const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
193 // TODO code_item == nullptr means that the method is abstract (or native, but we check that
194 // earlier). We should check what is returned by the RI in this situation since it's not clear
195 // what the appropriate return value is from the spec.
196 if (dex_file == nullptr || code_item == nullptr) {
197 return ERR(ABSENT_INFORMATION);
198 }
199
200 struct LocalVariableContext {
201 explicit LocalVariableContext(jvmtiEnv* jenv) : env_(jenv), variables_(), err_(OK) {}
202
203 static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
204 reinterpret_cast<LocalVariableContext*>(raw_ctx)->Insert(entry);
205 }
206
207 void Insert(const art::DexFile::LocalInfo& entry) {
208 if (err_ != OK) {
209 return;
210 }
211 JvmtiUniquePtr<char[]> name_str = CopyString(env_, entry.name_, &err_);
212 if (err_ != OK) {
213 return;
214 }
215 JvmtiUniquePtr<char[]> sig_str = CopyString(env_, entry.descriptor_, &err_);
216 if (err_ != OK) {
217 return;
218 }
219 JvmtiUniquePtr<char[]> generic_sig_str = CopyString(env_, entry.signature_, &err_);
220 if (err_ != OK) {
221 return;
222 }
223 variables_.push_back({
224 .start_location = static_cast<jlocation>(entry.start_address_),
225 .length = static_cast<jint>(entry.end_address_ - entry.start_address_),
226 .name = name_str.release(),
227 .signature = sig_str.release(),
228 .generic_signature = generic_sig_str.release(),
229 .slot = entry.reg_,
230 });
231 }
232
233 jvmtiError Release(jint* out_entry_count_ptr, jvmtiLocalVariableEntry** out_table_ptr) {
234 jlong table_size = sizeof(jvmtiLocalVariableEntry) * variables_.size();
235 if (err_ != OK ||
236 (err_ = env_->Allocate(table_size,
237 reinterpret_cast<unsigned char**>(out_table_ptr))) != OK) {
238 Cleanup();
239 return err_;
240 } else {
241 *out_entry_count_ptr = variables_.size();
242 memcpy(*out_table_ptr, variables_.data(), table_size);
243 return OK;
244 }
245 }
246
247 void Cleanup() {
248 for (jvmtiLocalVariableEntry& e : variables_) {
249 env_->Deallocate(reinterpret_cast<unsigned char*>(e.name));
250 env_->Deallocate(reinterpret_cast<unsigned char*>(e.signature));
251 env_->Deallocate(reinterpret_cast<unsigned char*>(e.generic_signature));
252 }
253 }
254
255 jvmtiEnv* env_;
256 std::vector<jvmtiLocalVariableEntry> variables_;
257 jvmtiError err_;
258 };
259
260 LocalVariableContext context(env);
261 if (!dex_file->DecodeDebugLocalInfo(code_item,
262 art_method->IsStatic(),
263 art_method->GetDexMethodIndex(),
264 LocalVariableContext::Callback,
265 &context)) {
266 // Something went wrong with decoding the debug information. It might as well not be there.
267 return ERR(ABSENT_INFORMATION);
268 } else {
269 return context.Release(entry_count_ptr, table_ptr);
270 }
271}
272
Andreas Gampef71832e2017-01-09 11:38:04 -0800273jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
274 jmethodID method,
275 jint* max_ptr) {
276 if (method == nullptr) {
277 return ERR(INVALID_METHODID);
278 }
279 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
280
281 if (art_method->IsNative()) {
282 return ERR(NATIVE_METHOD);
283 }
284
285 if (max_ptr == nullptr) {
286 return ERR(NULL_POINTER);
287 }
288
289 art::ScopedObjectAccess soa(art::Thread::Current());
290 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
291 // This isn't specified as an error case, so return 0.
292 *max_ptr = 0;
293 return ERR(NONE);
294 }
295
296 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
297 *max_ptr = art_method->GetCodeItem()->registers_size_;
298
299 return ERR(NONE);
300}
301
Andreas Gampe3c252f02016-10-27 18:25:17 -0700302jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
303 jmethodID method,
304 char** name_ptr,
305 char** signature_ptr,
306 char** generic_ptr) {
307 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe13b27842016-11-07 16:48:23 -0800308 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe3c252f02016-10-27 18:25:17 -0700309 art_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
310
Andreas Gampe54711412017-02-21 12:41:43 -0800311 JvmtiUniquePtr<char[]> name_copy;
Andreas Gampe3c252f02016-10-27 18:25:17 -0700312 if (name_ptr != nullptr) {
313 const char* method_name = art_method->GetName();
314 if (method_name == nullptr) {
315 method_name = "<error>";
316 }
Andreas Gampe54711412017-02-21 12:41:43 -0800317 jvmtiError ret;
318 name_copy = CopyString(env, method_name, &ret);
319 if (name_copy == nullptr) {
Andreas Gampe3c252f02016-10-27 18:25:17 -0700320 return ret;
321 }
Andreas Gampe54711412017-02-21 12:41:43 -0800322 *name_ptr = name_copy.get();
Andreas Gampe3c252f02016-10-27 18:25:17 -0700323 }
324
Andreas Gampe54711412017-02-21 12:41:43 -0800325 JvmtiUniquePtr<char[]> signature_copy;
Andreas Gampe3c252f02016-10-27 18:25:17 -0700326 if (signature_ptr != nullptr) {
327 const art::Signature sig = art_method->GetSignature();
328 std::string str = sig.ToString();
Andreas Gampe54711412017-02-21 12:41:43 -0800329 jvmtiError ret;
330 signature_copy = CopyString(env, str.c_str(), &ret);
331 if (signature_copy == nullptr) {
Andreas Gampe3c252f02016-10-27 18:25:17 -0700332 return ret;
333 }
Andreas Gampe54711412017-02-21 12:41:43 -0800334 *signature_ptr = signature_copy.get();
Andreas Gampe3c252f02016-10-27 18:25:17 -0700335 }
336
Andreas Gampe862bdd82016-11-18 13:31:13 -0800337 if (generic_ptr != nullptr) {
338 *generic_ptr = nullptr;
Andreas Gampe27dfa052017-02-16 15:04:36 -0800339 if (!art_method->GetDeclaringClass()->IsProxyClass()) {
340 art::mirror::ObjectArray<art::mirror::String>* str_array =
341 art::annotations::GetSignatureAnnotationForMethod(art_method);
342 if (str_array != nullptr) {
343 std::ostringstream oss;
344 for (int32_t i = 0; i != str_array->GetLength(); ++i) {
345 oss << str_array->Get(i)->ToModifiedUtf8();
346 }
347 std::string output_string = oss.str();
Andreas Gampe54711412017-02-21 12:41:43 -0800348 jvmtiError ret;
349 JvmtiUniquePtr<char[]> generic_copy = CopyString(env, output_string.c_str(), &ret);
350 if (generic_copy == nullptr) {
Andreas Gampe27dfa052017-02-16 15:04:36 -0800351 return ret;
352 }
Andreas Gampe54711412017-02-21 12:41:43 -0800353 *generic_ptr = generic_copy.release();
Andreas Gampe27dfa052017-02-16 15:04:36 -0800354 } else if (soa.Self()->IsExceptionPending()) {
355 // TODO: Should we report an error here?
356 soa.Self()->ClearException();
357 }
358 }
Andreas Gampe862bdd82016-11-18 13:31:13 -0800359 }
Andreas Gampe3c252f02016-10-27 18:25:17 -0700360
361 // Everything is fine, release the buffers.
362 name_copy.release();
363 signature_copy.release();
364
365 return ERR(NONE);
366}
367
Andreas Gampe368a2082016-10-28 17:33:13 -0700368jvmtiError MethodUtil::GetMethodDeclaringClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
369 jmethodID method,
370 jclass* declaring_class_ptr) {
371 if (declaring_class_ptr == nullptr) {
372 return ERR(NULL_POINTER);
373 }
374
Andreas Gampe13b27842016-11-07 16:48:23 -0800375 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe368a2082016-10-28 17:33:13 -0700376 // Note: No GetInterfaceMethodIfProxy, we want to actual class.
377
Andreas Gampe13b27842016-11-07 16:48:23 -0800378 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe368a2082016-10-28 17:33:13 -0700379 art::mirror::Class* klass = art_method->GetDeclaringClass();
380 *declaring_class_ptr = soa.AddLocalReference<jclass>(klass);
381
382 return ERR(NONE);
383}
384
Andreas Gampef71832e2017-01-09 11:38:04 -0800385jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
386 jmethodID method,
387 jlocation* start_location_ptr,
388 jlocation* end_location_ptr) {
389 if (method == nullptr) {
390 return ERR(INVALID_METHODID);
391 }
392 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
393
394 if (art_method->IsNative()) {
395 return ERR(NATIVE_METHOD);
396 }
397
398 if (start_location_ptr == nullptr || end_location_ptr == nullptr) {
399 return ERR(NULL_POINTER);
400 }
401
402 art::ScopedObjectAccess soa(art::Thread::Current());
403 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
Andreas Gampee1f79b62017-04-12 21:11:28 -0700404 // This isn't specified as an error case, so return -1/-1 as the RI does.
405 *start_location_ptr = -1;
406 *end_location_ptr = -1;
Andreas Gampef71832e2017-01-09 11:38:04 -0800407 return ERR(NONE);
408 }
409
410 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
411 *start_location_ptr = 0;
412 *end_location_ptr = art_method->GetCodeItem()->insns_size_in_code_units_ - 1;
413
414 return ERR(NONE);
415}
416
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700417jvmtiError MethodUtil::GetMethodModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
418 jmethodID method,
419 jint* modifiers_ptr) {
420 if (modifiers_ptr == nullptr) {
421 return ERR(NULL_POINTER);
422 }
423
Andreas Gampe13b27842016-11-07 16:48:23 -0800424 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700425 uint32_t modifiers = art_method->GetAccessFlags();
426
427 // Note: Keep this code in sync with Executable.fixMethodFlags.
428 if ((modifiers & art::kAccAbstract) != 0) {
429 modifiers &= ~art::kAccNative;
430 }
431 modifiers &= ~art::kAccSynchronized;
432 if ((modifiers & art::kAccDeclaredSynchronized) != 0) {
433 modifiers |= art::kAccSynchronized;
434 }
435 modifiers &= art::kAccJavaFlagsMask;
436
437 *modifiers_ptr = modifiers;
438 return ERR(NONE);
439}
440
Andreas Gampeda3e5612016-12-13 19:00:53 -0800441using LineNumberContext = std::vector<jvmtiLineNumberEntry>;
442
443static bool CollectLineNumbers(void* void_context, const art::DexFile::PositionInfo& entry) {
444 LineNumberContext* context = reinterpret_cast<LineNumberContext*>(void_context);
445 jvmtiLineNumberEntry jvmti_entry = { static_cast<jlocation>(entry.address_),
446 static_cast<jint>(entry.line_) };
447 context->push_back(jvmti_entry);
448 return false; // Collect all, no early exit.
449}
450
451jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
452 jmethodID method,
453 jint* entry_count_ptr,
454 jvmtiLineNumberEntry** table_ptr) {
455 if (method == nullptr) {
456 return ERR(NULL_POINTER);
457 }
458 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
459 DCHECK(!art_method->IsRuntimeMethod());
460
461 const art::DexFile::CodeItem* code_item;
462 const art::DexFile* dex_file;
463 {
464 art::ScopedObjectAccess soa(art::Thread::Current());
465
466 if (art_method->IsProxyMethod()) {
467 return ERR(ABSENT_INFORMATION);
468 }
469 if (art_method->IsNative()) {
470 return ERR(NATIVE_METHOD);
471 }
472 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
473 return ERR(NULL_POINTER);
474 }
475
476 code_item = art_method->GetCodeItem();
477 dex_file = art_method->GetDexFile();
478 DCHECK(code_item != nullptr) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
479 }
480
481 LineNumberContext context;
482 bool success = dex_file->DecodeDebugPositionInfo(code_item, CollectLineNumbers, &context);
483 if (!success) {
484 return ERR(ABSENT_INFORMATION);
485 }
486
487 unsigned char* data;
488 jlong mem_size = context.size() * sizeof(jvmtiLineNumberEntry);
489 jvmtiError alloc_error = env->Allocate(mem_size, &data);
490 if (alloc_error != ERR(NONE)) {
491 return alloc_error;
492 }
493 *table_ptr = reinterpret_cast<jvmtiLineNumberEntry*>(data);
494 memcpy(*table_ptr, context.data(), mem_size);
495 *entry_count_ptr = static_cast<jint>(context.size());
496
497 return ERR(NONE);
498}
499
Andreas Gampefdeef522017-01-09 14:40:25 -0800500template <typename T>
501static jvmtiError IsMethodT(jvmtiEnv* env ATTRIBUTE_UNUSED,
502 jmethodID method,
503 T test,
504 jboolean* is_t_ptr) {
505 if (method == nullptr) {
506 return ERR(INVALID_METHODID);
507 }
508 if (is_t_ptr == nullptr) {
509 return ERR(NULL_POINTER);
510 }
511
512 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
513 *is_t_ptr = test(art_method) ? JNI_TRUE : JNI_FALSE;
514
515 return ERR(NONE);
516}
517
518jvmtiError MethodUtil::IsMethodNative(jvmtiEnv* env, jmethodID m, jboolean* is_native_ptr) {
519 auto test = [](art::ArtMethod* method) {
520 return method->IsNative();
521 };
522 return IsMethodT(env, m, test, is_native_ptr);
523}
524
525jvmtiError MethodUtil::IsMethodObsolete(jvmtiEnv* env, jmethodID m, jboolean* is_obsolete_ptr) {
526 auto test = [](art::ArtMethod* method) {
527 return method->IsObsolete();
528 };
529 return IsMethodT(env, m, test, is_obsolete_ptr);
530}
531
532jvmtiError MethodUtil::IsMethodSynthetic(jvmtiEnv* env, jmethodID m, jboolean* is_synthetic_ptr) {
533 auto test = [](art::ArtMethod* method) {
534 return method->IsSynthetic();
535 };
536 return IsMethodT(env, m, test, is_synthetic_ptr);
537}
538
Alex Lightbebd7bd2017-07-25 14:05:52 -0700539class CommonLocalVariableClosure : public art::Closure {
540 public:
541 CommonLocalVariableClosure(art::Thread* caller,
542 jint depth,
543 jint slot)
544 : result_(ERR(INTERNAL)), caller_(caller), depth_(depth), slot_(slot) {}
545
546 void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
547 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
548 std::unique_ptr<art::Context> context(art::Context::Create());
549 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
550 visitor.WalkStack();
551 if (!visitor.FoundFrame()) {
552 // Must have been a bad depth.
553 result_ = ERR(NO_MORE_FRAMES);
554 return;
555 }
556 art::ArtMethod* method = visitor.GetMethod();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700557 if (method->IsNative()) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700558 // TODO We really should support get/set for non-shadow frames.
559 result_ = ERR(OPAQUE_FRAME);
560 return;
561 } else if (method->GetCodeItem()->registers_size_ <= slot_) {
562 result_ = ERR(INVALID_SLOT);
563 return;
564 }
Alex Light0a5ec3d2017-07-25 16:50:26 -0700565 bool needs_instrument = !visitor.IsShadowFrame();
Alex Lightbebd7bd2017-07-25 14:05:52 -0700566 uint32_t pc = visitor.GetDexPc(/*abort_on_failure*/ false);
Andreas Gampee2abbc62017-09-15 11:59:26 -0700567 if (pc == art::dex::kDexNoIndex) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700568 // Cannot figure out current PC.
569 result_ = ERR(OPAQUE_FRAME);
570 return;
571 }
572 std::string descriptor;
573 art::Primitive::Type slot_type = art::Primitive::kPrimVoid;
574 jvmtiError err = GetSlotType(method, pc, &descriptor, &slot_type);
575 if (err != OK) {
576 result_ = err;
577 return;
578 }
579
580 err = GetTypeError(method, slot_type, descriptor);
581 if (err != OK) {
582 result_ = err;
583 return;
584 }
585 result_ = Execute(method, visitor);
Alex Light0a5ec3d2017-07-25 16:50:26 -0700586 if (needs_instrument) {
587 art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(self);
588 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700589 }
590
591 jvmtiError GetResult() const {
592 return result_;
593 }
594
595 protected:
596 virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
597 REQUIRES(art::Locks::mutator_lock_) = 0;
598 virtual jvmtiError GetTypeError(art::ArtMethod* method,
599 art::Primitive::Type type,
600 const std::string& descriptor)
601 REQUIRES(art::Locks::mutator_lock_) = 0;
602
603 jvmtiError GetSlotType(art::ArtMethod* method,
604 uint32_t dex_pc,
605 /*out*/std::string* descriptor,
606 /*out*/art::Primitive::Type* type)
607 REQUIRES(art::Locks::mutator_lock_) {
608 const art::DexFile* dex_file = method->GetDexFile();
609 const art::DexFile::CodeItem* code_item = method->GetCodeItem();
610 if (dex_file == nullptr || code_item == nullptr) {
611 return ERR(OPAQUE_FRAME);
612 }
613
614 struct GetLocalVariableInfoContext {
615 explicit GetLocalVariableInfoContext(jint slot,
616 uint32_t pc,
617 std::string* out_descriptor,
618 art::Primitive::Type* out_type)
619 : found_(false), jslot_(slot), pc_(pc), descriptor_(out_descriptor), type_(out_type) {
620 *descriptor_ = "";
621 *type_ = art::Primitive::kPrimVoid;
622 }
623
624 static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
625 reinterpret_cast<GetLocalVariableInfoContext*>(raw_ctx)->Handle(entry);
626 }
627
628 void Handle(const art::DexFile::LocalInfo& entry) {
629 if (found_) {
630 return;
631 } else if (entry.start_address_ <= pc_ &&
632 entry.end_address_ > pc_ &&
633 entry.reg_ == jslot_) {
634 found_ = true;
635 *type_ = art::Primitive::GetType(entry.descriptor_[0]);
636 *descriptor_ = entry.descriptor_;
637 }
638 return;
639 }
640
641 bool found_;
642 jint jslot_;
643 uint32_t pc_;
644 std::string* descriptor_;
645 art::Primitive::Type* type_;
646 };
647
648 GetLocalVariableInfoContext context(slot_, dex_pc, descriptor, type);
649 if (!dex_file->DecodeDebugLocalInfo(code_item,
650 method->IsStatic(),
651 method->GetDexMethodIndex(),
652 GetLocalVariableInfoContext::Callback,
653 &context) || !context.found_) {
654 // Something went wrong with decoding the debug information. It might as well not be there.
655 return ERR(INVALID_SLOT);
656 } else {
657 return OK;
658 }
659 }
660
661 jvmtiError result_;
662 art::Thread* caller_;
663 jint depth_;
664 jint slot_;
665};
666
667class GetLocalVariableClosure : public CommonLocalVariableClosure {
668 public:
669 GetLocalVariableClosure(art::Thread* caller,
670 jint depth,
671 jint slot,
672 art::Primitive::Type type,
673 jvalue* val)
674 : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
675
676 protected:
677 jvmtiError GetTypeError(art::ArtMethod* method ATTRIBUTE_UNUSED,
678 art::Primitive::Type slot_type,
679 const std::string& descriptor ATTRIBUTE_UNUSED)
680 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
681 switch (slot_type) {
682 case art::Primitive::kPrimByte:
683 case art::Primitive::kPrimChar:
684 case art::Primitive::kPrimInt:
685 case art::Primitive::kPrimShort:
686 case art::Primitive::kPrimBoolean:
687 return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
688 case art::Primitive::kPrimLong:
689 case art::Primitive::kPrimFloat:
690 case art::Primitive::kPrimDouble:
691 case art::Primitive::kPrimNot:
692 return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
693 case art::Primitive::kPrimVoid:
694 LOG(FATAL) << "Unexpected primitive type " << slot_type;
695 UNREACHABLE();
696 }
697 }
698
699 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
700 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
701 switch (type_) {
702 case art::Primitive::kPrimNot: {
703 uint32_t ptr_val;
704 if (!visitor.GetVReg(method,
705 static_cast<uint16_t>(slot_),
706 art::kReferenceVReg,
707 &ptr_val)) {
708 return ERR(OPAQUE_FRAME);
709 }
710 art::ObjPtr<art::mirror::Object> obj(reinterpret_cast<art::mirror::Object*>(ptr_val));
711 val_->l = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
712 break;
713 }
714 case art::Primitive::kPrimInt:
715 case art::Primitive::kPrimFloat: {
716 if (!visitor.GetVReg(method,
717 static_cast<uint16_t>(slot_),
718 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg : art::kIntVReg,
719 reinterpret_cast<uint32_t*>(&val_->i))) {
720 return ERR(OPAQUE_FRAME);
721 }
722 break;
723 }
724 case art::Primitive::kPrimDouble:
725 case art::Primitive::kPrimLong: {
726 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
727 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
728 if (!visitor.GetVRegPair(method,
729 static_cast<uint16_t>(slot_),
730 lo_type,
731 high_type,
732 reinterpret_cast<uint64_t*>(&val_->j))) {
733 return ERR(OPAQUE_FRAME);
734 }
735 break;
736 }
737 default: {
738 LOG(FATAL) << "unexpected register type " << type_;
739 UNREACHABLE();
740 }
741 }
742 return OK;
743 }
744
745 private:
746 art::Primitive::Type type_;
747 jvalue* val_;
748};
749
750jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
751 jthread thread,
752 jint depth,
753 jint slot,
754 art::Primitive::Type type,
755 jvalue* val) {
756 if (depth < 0) {
757 return ERR(ILLEGAL_ARGUMENT);
758 }
759 art::Thread* self = art::Thread::Current();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700760 // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
761 art::jit::ScopedJitSuspend suspend_jit;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700762 art::ScopedObjectAccess soa(self);
Alex Light3ae82532017-07-26 13:59:07 -0700763 art::MutexLock mu(self, *art::Locks::thread_list_lock_);
Alex Light7ddc23d2017-09-22 15:33:41 -0700764 art::Thread* target = nullptr;
765 jvmtiError err = ERR(INTERNAL);
766 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
767 return err;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700768 }
769 GetLocalVariableClosure c(self, depth, slot, type, val);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700770 if (!target->RequestSynchronousCheckpoint(&c)) {
771 return ERR(THREAD_NOT_ALIVE);
772 } else {
773 return c.GetResult();
774 }
775}
776
777class SetLocalVariableClosure : public CommonLocalVariableClosure {
778 public:
779 SetLocalVariableClosure(art::Thread* caller,
780 jint depth,
781 jint slot,
782 art::Primitive::Type type,
783 jvalue val)
784 : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
785
786 protected:
787 jvmtiError GetTypeError(art::ArtMethod* method,
788 art::Primitive::Type slot_type,
789 const std::string& descriptor)
790 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
791 switch (slot_type) {
792 case art::Primitive::kPrimNot: {
793 if (type_ != art::Primitive::kPrimNot) {
794 return ERR(TYPE_MISMATCH);
795 } else if (val_.l == nullptr) {
796 return OK;
797 } else {
798 art::ClassLinker* cl = art::Runtime::Current()->GetClassLinker();
799 art::ObjPtr<art::mirror::Class> set_class =
800 caller_->DecodeJObject(val_.l)->GetClass();
801 art::ObjPtr<art::mirror::ClassLoader> loader =
802 method->GetDeclaringClass()->GetClassLoader();
803 art::ObjPtr<art::mirror::Class> slot_class =
804 cl->LookupClass(caller_, descriptor.c_str(), loader);
805 DCHECK(!slot_class.IsNull());
806 return slot_class->IsAssignableFrom(set_class) ? OK : ERR(TYPE_MISMATCH);
807 }
808 }
809 case art::Primitive::kPrimByte:
810 case art::Primitive::kPrimChar:
811 case art::Primitive::kPrimInt:
812 case art::Primitive::kPrimShort:
813 case art::Primitive::kPrimBoolean:
814 return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
815 case art::Primitive::kPrimLong:
816 case art::Primitive::kPrimFloat:
817 case art::Primitive::kPrimDouble:
818 return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
819 case art::Primitive::kPrimVoid:
820 LOG(FATAL) << "Unexpected primitive type " << slot_type;
821 UNREACHABLE();
822 }
823 }
824
825 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
826 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
827 switch (type_) {
828 case art::Primitive::kPrimNot: {
829 uint32_t ptr_val;
830 art::ObjPtr<art::mirror::Object> obj(caller_->DecodeJObject(val_.l));
831 ptr_val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(obj.Ptr()));
832 if (!visitor.SetVReg(method,
833 static_cast<uint16_t>(slot_),
834 ptr_val,
835 art::kReferenceVReg)) {
836 return ERR(OPAQUE_FRAME);
837 }
838 break;
839 }
840 case art::Primitive::kPrimInt:
841 case art::Primitive::kPrimFloat: {
842 if (!visitor.SetVReg(method,
843 static_cast<uint16_t>(slot_),
844 static_cast<uint32_t>(val_.i),
845 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg
846 : art::kIntVReg)) {
847 return ERR(OPAQUE_FRAME);
848 }
849 break;
850 }
851 case art::Primitive::kPrimDouble:
852 case art::Primitive::kPrimLong: {
853 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
854 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
855 if (!visitor.SetVRegPair(method,
856 static_cast<uint16_t>(slot_),
857 static_cast<uint64_t>(val_.j),
858 lo_type,
859 high_type)) {
860 return ERR(OPAQUE_FRAME);
861 }
862 break;
863 }
864 default: {
865 LOG(FATAL) << "unexpected register type " << type_;
866 UNREACHABLE();
867 }
868 }
869 return OK;
870 }
871
872 private:
873 art::Primitive::Type type_;
874 jvalue val_;
875};
876
877jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
878 jthread thread,
879 jint depth,
880 jint slot,
881 art::Primitive::Type type,
882 jvalue val) {
883 if (depth < 0) {
884 return ERR(ILLEGAL_ARGUMENT);
885 }
886 art::Thread* self = art::Thread::Current();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700887 // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
888 art::jit::ScopedJitSuspend suspend_jit;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700889 art::ScopedObjectAccess soa(self);
Alex Light3ae82532017-07-26 13:59:07 -0700890 art::MutexLock mu(self, *art::Locks::thread_list_lock_);
Alex Light7ddc23d2017-09-22 15:33:41 -0700891 art::Thread* target = nullptr;
892 jvmtiError err = ERR(INTERNAL);
893 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
894 return err;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700895 }
896 SetLocalVariableClosure c(self, depth, slot, type, val);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700897 if (!target->RequestSynchronousCheckpoint(&c)) {
898 return ERR(THREAD_NOT_ALIVE);
899 } else {
900 return c.GetResult();
901 }
902}
903
904class GetLocalInstanceClosure : public art::Closure {
905 public:
906 GetLocalInstanceClosure(art::Thread* caller, jint depth, jobject* val)
907 : result_(ERR(INTERNAL)),
908 caller_(caller),
909 depth_(depth),
910 val_(val) {}
911
912 void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
913 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
914 std::unique_ptr<art::Context> context(art::Context::Create());
915 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
916 visitor.WalkStack();
917 if (!visitor.FoundFrame()) {
918 // Must have been a bad depth.
919 result_ = ERR(NO_MORE_FRAMES);
920 return;
921 }
922 art::ArtMethod* method = visitor.GetMethod();
923 if (!visitor.IsShadowFrame() && !method->IsNative() && !method->IsProxyMethod()) {
924 // TODO We really should support get/set for non-shadow frames.
925 result_ = ERR(OPAQUE_FRAME);
926 return;
927 }
928 result_ = OK;
929 art::ObjPtr<art::mirror::Object> obj = visitor.GetThisObject();
930 *val_ = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
931 }
932
933 jvmtiError GetResult() const {
934 return result_;
935 }
936
937 private:
938 jvmtiError result_;
939 art::Thread* caller_;
940 jint depth_;
941 jobject* val_;
942};
943
944jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED,
945 jthread thread,
946 jint depth,
947 jobject* data) {
948 if (depth < 0) {
949 return ERR(ILLEGAL_ARGUMENT);
950 }
951 art::Thread* self = art::Thread::Current();
952 art::ScopedObjectAccess soa(self);
Alex Light3ae82532017-07-26 13:59:07 -0700953 art::MutexLock mu(self, *art::Locks::thread_list_lock_);
Alex Light7ddc23d2017-09-22 15:33:41 -0700954 art::Thread* target = nullptr;
955 jvmtiError err = ERR(INTERNAL);
956 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
957 return err;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700958 }
959 GetLocalInstanceClosure c(self, depth, data);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700960 if (!target->RequestSynchronousCheckpoint(&c)) {
961 return ERR(THREAD_NOT_ALIVE);
962 } else {
963 return c.GetResult();
964 }
965}
966
967#define FOR_JVMTI_JVALUE_TYPES(fn) \
968 fn(jint, art::Primitive::kPrimInt, i) \
969 fn(jlong, art::Primitive::kPrimLong, j) \
970 fn(jfloat, art::Primitive::kPrimFloat, f) \
971 fn(jdouble, art::Primitive::kPrimDouble, d) \
972 fn(jobject, art::Primitive::kPrimNot, l)
973
974namespace impl {
975
976template<typename T> void WriteJvalue(T, jvalue*);
977template<typename T> void ReadJvalue(jvalue, T*);
978template<typename T> art::Primitive::Type GetJNIType();
979
980#define JNI_TYPE_CHAR(type, prim, id) \
981template<> art::Primitive::Type GetJNIType<type>() { \
982 return prim; \
983}
984
985FOR_JVMTI_JVALUE_TYPES(JNI_TYPE_CHAR);
986
987#undef JNI_TYPE_CHAR
988
Andreas Gampe49fc60e2017-08-24 13:19:59 -0700989#define RW_JVALUE(srctype, prim, id) \
990 template<> void ReadJvalue<srctype>(jvalue in, std::add_pointer<srctype>::type out) { \
Alex Lightbebd7bd2017-07-25 14:05:52 -0700991 *out = in.id; \
992 } \
Andreas Gampe49fc60e2017-08-24 13:19:59 -0700993 template<> void WriteJvalue<srctype>(srctype in, jvalue* out) { \
Alex Lightbebd7bd2017-07-25 14:05:52 -0700994 out->id = in; \
995 }
996
997FOR_JVMTI_JVALUE_TYPES(RW_JVALUE);
998
999#undef RW_JVALUE
1000
1001} // namespace impl
1002
1003template<typename T>
1004jvmtiError MethodUtil::SetLocalVariable(jvmtiEnv* env,
1005 jthread thread,
1006 jint depth,
1007 jint slot,
1008 T data) {
1009 jvalue v = {.j = 0};
1010 art::Primitive::Type type = impl::GetJNIType<T>();
1011 impl::WriteJvalue(data, &v);
1012 return SetLocalVariableGeneric(env, thread, depth, slot, type, v);
1013}
1014
1015template<typename T>
1016jvmtiError MethodUtil::GetLocalVariable(jvmtiEnv* env,
1017 jthread thread,
1018 jint depth,
1019 jint slot,
1020 T* data) {
1021 if (data == nullptr) {
1022 return ERR(NULL_POINTER);
1023 }
1024 jvalue v = {.j = 0};
1025 art::Primitive::Type type = impl::GetJNIType<T>();
1026 jvmtiError err = GetLocalVariableGeneric(env, thread, depth, slot, type, &v);
1027 if (err != OK) {
1028 return err;
1029 } else {
1030 impl::ReadJvalue(v, data);
1031 return OK;
1032 }
1033}
1034
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001035#define GET_SET_LV(srctype, prim, id) \
1036 template jvmtiError MethodUtil::GetLocalVariable<srctype>(jvmtiEnv*, \
1037 jthread, \
1038 jint, \
1039 jint, \
1040 std::add_pointer<srctype>::type); \
1041 template jvmtiError MethodUtil::SetLocalVariable<srctype>(jvmtiEnv*, \
1042 jthread, \
1043 jint, \
1044 jint, \
1045 srctype);
Alex Lightbebd7bd2017-07-25 14:05:52 -07001046
1047FOR_JVMTI_JVALUE_TYPES(GET_SET_LV);
1048
1049#undef GET_SET_LV
1050
1051#undef FOR_JVMTI_JVALUE_TYPES
1052
Andreas Gampe3c252f02016-10-27 18:25:17 -07001053} // namespace openjdkjvmti