1 /* 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
34 #include <initializer_list>
35 #include <type_traits>
36 #include <variant>
37
38 #include "android-base/macros.h"
39 #include "arch/context.h"
40 #include "art_jvmti.h"
41 #include "art_method-inl.h"
42 #include "base/globals.h"
43 #include "base/macros.h"
44 #include "base/mutex-inl.h"
45 #include "base/pointer_size.h"
46 #include "deopt_manager.h"
47 #include "dex/code_item_accessors-inl.h"
48 #include "dex/code_item_accessors.h"
49 #include "dex/dex_file_annotations.h"
50 #include "dex/dex_file_types.h"
51 #include "dex/dex_instruction.h"
52 #include "dex/dex_instruction_iterator.h"
53 #include "dex/modifiers.h"
54 #include "dex/primitive.h"
55 #include "events-inl.h"
56 #include "gc_root-inl.h"
57 #include "handle.h"
58 #include "jit/jit.h"
59 #include "jni/jni_internal.h"
60 #include "jvmti.h"
61 #include "mirror/class-inl.h"
62 #include "mirror/class_loader.h"
63 #include "mirror/object-inl.h"
64 #include "mirror/object_array-inl.h"
65 #include "nativehelper/scoped_local_ref.h"
66 #include "oat/oat_file.h"
67 #include "obj_ptr.h"
68 #include "runtime.h"
69 #include "runtime_callbacks.h"
70 #include "scoped_thread_state_change-inl.h"
71 #include "scoped_thread_state_change.h"
72 #include "stack.h"
73 #include "thread-current-inl.h"
74 #include "thread.h"
75 #include "thread_list.h"
76 #include "ti_logging.h"
77 #include "ti_stack.h"
78 #include "ti_thread.h"
79 #include "ti_phase.h"
80 #include "verifier/register_line-inl.h"
81 #include "verifier/reg_type-inl.h"
82 #include "verifier/reg_type_cache.h"
83 #include "verifier/method_verifier-inl.h"
84
85 namespace openjdkjvmti {
86
87 struct TiMethodCallback : public art::MethodCallback {
RegisterNativeMethodopenjdkjvmti::TiMethodCallback88 void RegisterNativeMethod(art::ArtMethod* method,
89 const void* cur_method,
90 /*out*/void** new_method)
91 override REQUIRES_SHARED(art::Locks::mutator_lock_) {
92 if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kNativeMethodBind)) {
93 art::Thread* thread = art::Thread::Current();
94 art::JNIEnvExt* jnienv = thread->GetJniEnv();
95 ScopedLocalRef<jthread> thread_jni(
96 jnienv, PhaseUtil::IsLivePhase() ? jnienv->AddLocalReference<jthread>(thread->GetPeer())
97 : nullptr);
98 jmethodID method_id = art::jni::EncodeArtMethod(method);
99 art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
100 event_handler->DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(
101 thread,
102 static_cast<JNIEnv*>(jnienv),
103 thread_jni.get(),
104 method_id,
105 const_cast<void*>(cur_method),
106 new_method);
107 }
108 }
109
110 EventHandler* event_handler = nullptr;
111 };
112
113 TiMethodCallback gMethodCallback;
114
Register(EventHandler * handler)115 void MethodUtil::Register(EventHandler* handler) {
116 gMethodCallback.event_handler = handler;
117 art::ScopedThreadStateChange stsc(art::Thread::Current(),
118 art::ThreadState::kWaitingForDebuggerToAttach);
119 art::ScopedSuspendAll ssa("Add method callback");
120 art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
121 callbacks->AddMethodCallback(&gMethodCallback);
122 }
123
Unregister()124 void MethodUtil::Unregister() {
125 art::ScopedThreadStateChange stsc(art::Thread::Current(),
126 art::ThreadState::kWaitingForDebuggerToAttach);
127 art::ScopedSuspendAll ssa("Remove method callback");
128 art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
129 callbacks->RemoveMethodCallback(&gMethodCallback);
130 }
131
GetBytecodes(jvmtiEnv * env,jmethodID method,jint * size_ptr,unsigned char ** bytecode_ptr)132 jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
133 jmethodID method,
134 jint* size_ptr,
135 unsigned char** bytecode_ptr) {
136 if (method == nullptr) {
137 return ERR(INVALID_METHODID);
138 }
139 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
140
141 if (art_method->IsNative()) {
142 return ERR(NATIVE_METHOD);
143 }
144
145 if (size_ptr == nullptr || bytecode_ptr == nullptr) {
146 return ERR(NULL_POINTER);
147 }
148
149 art::ScopedObjectAccess soa(art::Thread::Current());
150 art::CodeItemInstructionAccessor accessor(art_method->DexInstructions());
151 if (!accessor.HasCodeItem()) {
152 *size_ptr = 0;
153 *bytecode_ptr = nullptr;
154 return OK;
155 }
156 // 2 bytes per instruction for dex code.
157 *size_ptr = accessor.InsnsSizeInCodeUnits() * 2;
158 jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr);
159 if (err != OK) {
160 return err;
161 }
162 memcpy(*bytecode_ptr, accessor.Insns(), *size_ptr);
163 return OK;
164 }
165
GetArgumentsSize(jvmtiEnv * env,jmethodID method,jint * size_ptr)166 jvmtiError MethodUtil::GetArgumentsSize([[maybe_unused]] jvmtiEnv* env,
167 jmethodID method,
168 jint* size_ptr) {
169 if (method == nullptr) {
170 return ERR(INVALID_METHODID);
171 }
172 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
173
174 if (art_method->IsNative()) {
175 return ERR(NATIVE_METHOD);
176 }
177
178 if (size_ptr == nullptr) {
179 return ERR(NULL_POINTER);
180 }
181
182 art::ScopedObjectAccess soa(art::Thread::Current());
183 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
184 // Use the shorty.
185 art::ArtMethod* base_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
186 size_t arg_count = art::ArtMethod::NumArgRegisters(base_method->GetShortyView());
187 if (!base_method->IsStatic()) {
188 arg_count++;
189 }
190 *size_ptr = static_cast<jint>(arg_count);
191 return ERR(NONE);
192 }
193
194 DCHECK(art_method->HasCodeItem());
195 DCHECK_NE(art_method->GetCodeItem(), nullptr);
196 *size_ptr = art_method->DexInstructionData().InsSize();
197
198 return ERR(NONE);
199 }
200
GetLocalVariableTable(jvmtiEnv * env,jmethodID method,jint * entry_count_ptr,jvmtiLocalVariableEntry ** table_ptr)201 jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
202 jmethodID method,
203 jint* entry_count_ptr,
204 jvmtiLocalVariableEntry** table_ptr) {
205 if (method == nullptr) {
206 return ERR(INVALID_METHODID);
207 }
208 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
209
210 if (art_method->IsNative()) {
211 return ERR(NATIVE_METHOD);
212 }
213
214 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
215 return ERR(NULL_POINTER);
216 }
217
218 art::ScopedObjectAccess soa(art::Thread::Current());
219
220 const art::DexFile* const dex_file = art_method->GetDexFile();
221 if (dex_file == nullptr) {
222 return ERR(ABSENT_INFORMATION);
223 }
224
225 // TODO HasCodeItem == false means that the method is abstract (or native, but we check that
226 // earlier). We should check what is returned by the RI in this situation since it's not clear
227 // what the appropriate return value is from the spec.
228 art::CodeItemDebugInfoAccessor accessor(art_method->DexInstructionDebugInfo());
229 if (!accessor.HasCodeItem()) {
230 return ERR(ABSENT_INFORMATION);
231 }
232
233 std::vector<jvmtiLocalVariableEntry> variables;
234 jvmtiError err = OK;
235
236 auto release = [&](jint* out_entry_count_ptr, jvmtiLocalVariableEntry** out_table_ptr) {
237 jlong table_size = sizeof(jvmtiLocalVariableEntry) * variables.size();
238 if (err != OK ||
239 (err = env->Allocate(table_size,
240 reinterpret_cast<unsigned char**>(out_table_ptr))) != OK) {
241 for (jvmtiLocalVariableEntry& e : variables) {
242 env->Deallocate(reinterpret_cast<unsigned char*>(e.name));
243 env->Deallocate(reinterpret_cast<unsigned char*>(e.signature));
244 env->Deallocate(reinterpret_cast<unsigned char*>(e.generic_signature));
245 }
246 return err;
247 }
248 *out_entry_count_ptr = variables.size();
249 memcpy(*out_table_ptr, variables.data(), table_size);
250 return OK;
251 };
252
253 // To avoid defining visitor in the same line as the `if`. We define the lambda and use std::move.
254 auto visitor = [&](const art::DexFile::LocalInfo& entry) {
255 if (err != OK) {
256 return;
257 }
258 JvmtiUniquePtr<char[]> name_str = CopyString(env, entry.name_, &err);
259 if (err != OK) {
260 return;
261 }
262 JvmtiUniquePtr<char[]> sig_str = CopyString(env, entry.descriptor_, &err);
263 if (err != OK) {
264 return;
265 }
266 JvmtiUniquePtr<char[]> generic_sig_str = CopyString(env, entry.signature_, &err);
267 if (err != OK) {
268 return;
269 }
270 variables.push_back({
271 .start_location = static_cast<jlocation>(entry.start_address_),
272 .length = static_cast<jint>(entry.end_address_ - entry.start_address_),
273 .name = name_str.release(),
274 .signature = sig_str.release(),
275 .generic_signature = generic_sig_str.release(),
276 .slot = entry.reg_,
277 });
278 };
279
280 if (!accessor.DecodeDebugLocalInfo(
281 art_method->IsStatic(), art_method->GetDexMethodIndex(), std::move(visitor))) {
282 // Something went wrong with decoding the debug information. It might as well not be there.
283 return ERR(ABSENT_INFORMATION);
284 }
285 return release(entry_count_ptr, table_ptr);
286 }
287
GetMaxLocals(jvmtiEnv * env,jmethodID method,jint * max_ptr)288 jvmtiError MethodUtil::GetMaxLocals([[maybe_unused]] jvmtiEnv* env,
289 jmethodID method,
290 jint* max_ptr) {
291 if (method == nullptr) {
292 return ERR(INVALID_METHODID);
293 }
294 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
295
296 if (art_method->IsNative()) {
297 return ERR(NATIVE_METHOD);
298 }
299
300 if (max_ptr == nullptr) {
301 return ERR(NULL_POINTER);
302 }
303
304 art::ScopedObjectAccess soa(art::Thread::Current());
305 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
306 // This isn't specified as an error case, so return 0.
307 *max_ptr = 0;
308 return ERR(NONE);
309 }
310
311 DCHECK(art_method->HasCodeItem());
312 DCHECK_NE(art_method->GetCodeItem(), nullptr);
313 *max_ptr = art_method->DexInstructionData().RegistersSize();
314
315 return ERR(NONE);
316 }
317
GetMethodName(jvmtiEnv * env,jmethodID method,char ** name_ptr,char ** signature_ptr,char ** generic_ptr)318 jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
319 jmethodID method,
320 char** name_ptr,
321 char** signature_ptr,
322 char** generic_ptr) {
323 art::ScopedObjectAccess soa(art::Thread::Current());
324 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
325 art_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
326
327 JvmtiUniquePtr<char[]> name_copy;
328 if (name_ptr != nullptr) {
329 const char* method_name = art_method->GetName();
330 if (method_name == nullptr) {
331 method_name = "<error>";
332 }
333 jvmtiError ret;
334 name_copy = CopyString(env, method_name, &ret);
335 if (name_copy == nullptr) {
336 return ret;
337 }
338 *name_ptr = name_copy.get();
339 }
340
341 JvmtiUniquePtr<char[]> signature_copy;
342 if (signature_ptr != nullptr) {
343 const art::Signature sig = art_method->GetSignature();
344 std::string str = sig.ToString();
345 jvmtiError ret;
346 signature_copy = CopyString(env, str.c_str(), &ret);
347 if (signature_copy == nullptr) {
348 return ret;
349 }
350 *signature_ptr = signature_copy.get();
351 }
352
353 if (generic_ptr != nullptr) {
354 *generic_ptr = nullptr;
355 if (!art_method->GetDeclaringClass()->IsProxyClass()) {
356 art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array =
357 art::annotations::GetSignatureAnnotationForMethod(art_method);
358 if (str_array != nullptr) {
359 std::ostringstream oss;
360 for (auto str : str_array->Iterate()) {
361 oss << str->ToModifiedUtf8();
362 }
363 std::string output_string = oss.str();
364 jvmtiError ret;
365 JvmtiUniquePtr<char[]> generic_copy = CopyString(env, output_string.c_str(), &ret);
366 if (generic_copy == nullptr) {
367 return ret;
368 }
369 *generic_ptr = generic_copy.release();
370 } else if (soa.Self()->IsExceptionPending()) {
371 // TODO: Should we report an error here?
372 soa.Self()->ClearException();
373 }
374 }
375 }
376
377 // Everything is fine, release the buffers.
378 name_copy.release();
379 signature_copy.release();
380
381 return ERR(NONE);
382 }
383
GetMethodDeclaringClass(jvmtiEnv * env,jmethodID method,jclass * declaring_class_ptr)384 jvmtiError MethodUtil::GetMethodDeclaringClass([[maybe_unused]] jvmtiEnv* env,
385 jmethodID method,
386 jclass* declaring_class_ptr) {
387 if (declaring_class_ptr == nullptr) {
388 return ERR(NULL_POINTER);
389 }
390
391 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
392 // Note: No GetInterfaceMethodIfProxy, we want to actual class.
393
394 art::ScopedObjectAccess soa(art::Thread::Current());
395 art::ObjPtr<art::mirror::Class> klass = art_method->GetDeclaringClass();
396 *declaring_class_ptr = soa.AddLocalReference<jclass>(klass);
397
398 return ERR(NONE);
399 }
400
GetMethodLocation(jvmtiEnv * env,jmethodID method,jlocation * start_location_ptr,jlocation * end_location_ptr)401 jvmtiError MethodUtil::GetMethodLocation([[maybe_unused]] jvmtiEnv* env,
402 jmethodID method,
403 jlocation* start_location_ptr,
404 jlocation* end_location_ptr) {
405 if (method == nullptr) {
406 return ERR(INVALID_METHODID);
407 }
408 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
409
410 if (art_method->IsNative()) {
411 return ERR(NATIVE_METHOD);
412 }
413
414 if (start_location_ptr == nullptr || end_location_ptr == nullptr) {
415 return ERR(NULL_POINTER);
416 }
417
418 art::ScopedObjectAccess soa(art::Thread::Current());
419 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
420 // This isn't specified as an error case, so return -1/-1 as the RI does.
421 *start_location_ptr = -1;
422 *end_location_ptr = -1;
423 return ERR(NONE);
424 }
425
426 DCHECK(art_method->HasCodeItem());
427 DCHECK_NE(art_method->GetCodeItem(), nullptr);
428 *start_location_ptr = 0;
429 *end_location_ptr = art_method->DexInstructions().InsnsSizeInCodeUnits() - 1;
430
431 return ERR(NONE);
432 }
433
GetMethodModifiers(jvmtiEnv * env,jmethodID method,jint * modifiers_ptr)434 jvmtiError MethodUtil::GetMethodModifiers([[maybe_unused]] jvmtiEnv* env,
435 jmethodID method,
436 jint* modifiers_ptr) {
437 if (modifiers_ptr == nullptr) {
438 return ERR(NULL_POINTER);
439 }
440
441 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
442 uint32_t modifiers = art_method->GetAccessFlags();
443
444 // Note: Keep this code in sync with Executable.fixMethodFlags.
445 if ((modifiers & art::kAccAbstract) != 0) {
446 modifiers &= ~art::kAccNative;
447 }
448 modifiers &= ~art::kAccSynchronized;
449 if ((modifiers & art::kAccDeclaredSynchronized) != 0) {
450 modifiers |= art::kAccSynchronized;
451 }
452 modifiers &= art::kAccJavaFlagsMask;
453
454 *modifiers_ptr = modifiers;
455 return ERR(NONE);
456 }
457
GetLineNumberTable(jvmtiEnv * env,jmethodID method,jint * entry_count_ptr,jvmtiLineNumberEntry ** table_ptr)458 jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
459 jmethodID method,
460 jint* entry_count_ptr,
461 jvmtiLineNumberEntry** table_ptr) {
462 if (method == nullptr) {
463 return ERR(NULL_POINTER);
464 }
465 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
466 DCHECK(!art_method->IsRuntimeMethod());
467
468 art::CodeItemDebugInfoAccessor accessor;
469 const art::DexFile* dex_file;
470 {
471 art::ScopedObjectAccess soa(art::Thread::Current());
472
473 if (art_method->IsProxyMethod()) {
474 return ERR(ABSENT_INFORMATION);
475 }
476 if (art_method->IsNative()) {
477 return ERR(NATIVE_METHOD);
478 }
479 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
480 return ERR(NULL_POINTER);
481 }
482
483 accessor = art::CodeItemDebugInfoAccessor(art_method->DexInstructionDebugInfo());
484 dex_file = art_method->GetDexFile();
485 DCHECK(accessor.HasCodeItem()) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
486 }
487
488 std::vector<jvmtiLineNumberEntry> context;
489 bool success = accessor.DecodeDebugPositionInfo([&](const art::DexFile::PositionInfo& entry) {
490 context.push_back({static_cast<jlocation>(entry.address_), static_cast<jint>(entry.line_)});
491 return false;
492 });
493 if (!success) {
494 return ERR(ABSENT_INFORMATION);
495 }
496
497 unsigned char* data;
498 jlong mem_size = context.size() * sizeof(jvmtiLineNumberEntry);
499 jvmtiError alloc_error = env->Allocate(mem_size, &data);
500 if (alloc_error != ERR(NONE)) {
501 return alloc_error;
502 }
503 *table_ptr = reinterpret_cast<jvmtiLineNumberEntry*>(data);
504 memcpy(*table_ptr, context.data(), mem_size);
505 *entry_count_ptr = static_cast<jint>(context.size());
506
507 return ERR(NONE);
508 }
509
510 template <typename T>
IsMethodT(jvmtiEnv * env,jmethodID method,T test,jboolean * is_t_ptr)511 static jvmtiError IsMethodT([[maybe_unused]] jvmtiEnv* env,
512 jmethodID method,
513 T test,
514 jboolean* is_t_ptr) {
515 if (method == nullptr) {
516 return ERR(INVALID_METHODID);
517 }
518 if (is_t_ptr == nullptr) {
519 return ERR(NULL_POINTER);
520 }
521
522 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
523 *is_t_ptr = test(art_method) ? JNI_TRUE : JNI_FALSE;
524
525 return ERR(NONE);
526 }
527
IsMethodNative(jvmtiEnv * env,jmethodID m,jboolean * is_native_ptr)528 jvmtiError MethodUtil::IsMethodNative(jvmtiEnv* env, jmethodID m, jboolean* is_native_ptr) {
529 auto test = [](art::ArtMethod* method) {
530 return method->IsNative();
531 };
532 return IsMethodT(env, m, test, is_native_ptr);
533 }
534
IsMethodObsolete(jvmtiEnv * env,jmethodID m,jboolean * is_obsolete_ptr)535 jvmtiError MethodUtil::IsMethodObsolete(jvmtiEnv* env, jmethodID m, jboolean* is_obsolete_ptr) {
536 auto test = [](art::ArtMethod* method) {
537 return method->IsObsolete();
538 };
539 return IsMethodT(env, m, test, is_obsolete_ptr);
540 }
541
IsMethodSynthetic(jvmtiEnv * env,jmethodID m,jboolean * is_synthetic_ptr)542 jvmtiError MethodUtil::IsMethodSynthetic(jvmtiEnv* env, jmethodID m, jboolean* is_synthetic_ptr) {
543 auto test = [](art::ArtMethod* method) {
544 return method->IsSynthetic();
545 };
546 return IsMethodT(env, m, test, is_synthetic_ptr);
547 }
548
549 class CommonLocalVariableClosure : public art::Closure {
550 public:
551 // The verifier isn't always able to be as specific as the local-variable-table. We can only get
552 // 32-bit, 64-bit or reference.
553 enum class VerifierPrimitiveType {
554 k32BitValue, // float, int, short, char, boolean, byte
555 k64BitValue, // double, long
556 kReferenceValue, // Object
557 kZeroValue, // null or zero constant. Might be either k32BitValue or kReferenceValue
558 };
559
560 using SlotType = std::variant<art::Primitive::Type, VerifierPrimitiveType>;
561
CommonLocalVariableClosure(jvmtiEnv * jvmti,jint depth,jint slot)562 CommonLocalVariableClosure(jvmtiEnv* jvmti, jint depth, jint slot)
563 : jvmti_(jvmti), result_(ERR(INTERNAL)), depth_(depth), slot_(slot) {}
564
Run(art::Thread * self)565 void Run(art::Thread* self) override REQUIRES_SHARED(art::Locks::mutator_lock_) {
566 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
567 bool needs_instrument;
568 {
569 art::ScopedAssertNoThreadSuspension sants("CommonLocalVariableClosure::Run");
570 std::unique_ptr<art::Context> context(art::Context::Create());
571 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
572 visitor.WalkStack();
573 if (!visitor.FoundFrame()) {
574 // Must have been a bad depth.
575 result_ = ERR(NO_MORE_FRAMES);
576 return;
577 }
578 art::ArtMethod* method = visitor.GetMethod();
579 // Native and 'art' proxy methods don't have registers.
580 if (method->IsNative() || method->IsProxyMethod()) {
581 // TODO It might be useful to fake up support for get at least on proxy frames.
582 result_ = ERR(OPAQUE_FRAME);
583 return;
584 } else if (slot_ >= method->DexInstructionData().RegistersSize() || slot_ < 0) {
585 result_ = ERR(INVALID_SLOT);
586 return;
587 }
588 needs_instrument = !visitor.IsShadowFrame();
589 uint32_t pc = visitor.GetDexPc(/*abort_on_failure=*/false);
590 if (pc == art::dex::kDexNoIndex) {
591 // Cannot figure out current PC.
592 result_ = ERR(OPAQUE_FRAME);
593 return;
594 }
595 std::string descriptor;
596 SlotType slot_type{ art::Primitive::kPrimVoid };
597 jvmtiError err = GetSlotType(method, pc, &descriptor, &slot_type);
598 if (err != OK) {
599 result_ = err;
600 return;
601 }
602
603 err = GetTypeError(method, slot_type, descriptor);
604 if (err != OK) {
605 result_ = err;
606 return;
607 }
608 result_ = Execute(method, visitor);
609 }
610 if (needs_instrument) {
611 DeoptManager::Get()->DeoptimizeThread(self);
612 }
613 }
614
GetResult()615 virtual jvmtiError GetResult() {
616 return result_;
617 }
618
619 protected:
620 virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
621 REQUIRES_SHARED(art::Locks::mutator_lock_) = 0;
622 virtual jvmtiError GetTypeError(art::ArtMethod* method,
623 SlotType type,
624 const std::string& descriptor)
625 REQUIRES_SHARED(art::Locks::mutator_lock_) = 0;
626
627 jvmtiError GetSlotType(art::ArtMethod* method,
628 uint32_t dex_pc,
629 /*out*/std::string* descriptor,
630 /*out*/SlotType* type)
631 REQUIRES_SHARED(art::Locks::mutator_lock_);
632
InferSlotTypeFromVerifier(art::ArtMethod * method,uint32_t dex_pc,std::string * descriptor,SlotType * type)633 jvmtiError InferSlotTypeFromVerifier(art::ArtMethod* method,
634 uint32_t dex_pc,
635 /*out*/ std::string* descriptor,
636 /*out*/ SlotType* type)
637 REQUIRES_SHARED(art::Locks::mutator_lock_) {
638 art::StackHandleScope<2> hs(art::Thread::Current());
639 art::Handle<art::mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
640 art::Handle<art::mirror::ClassLoader> class_loader(hs.NewHandle(method->GetClassLoader()));
641 art::Thread* self = art::Thread::Current();
642 art::Runtime* runtime = art::Runtime::Current();
643 art::ClassLinker* class_linker = runtime->GetClassLinker();
644 art::ArenaPool* arena_pool = runtime->GetArenaPool();
645 art::verifier::RegTypeCache reg_types(self,
646 class_linker,
647 arena_pool,
648 class_loader,
649 dex_cache->GetDexFile(),
650 /* can_load_classes= */ false,
651 /* can_suspend= */ false);
652 std::unique_ptr<art::verifier::MethodVerifier> verifier(
653 art::verifier::MethodVerifier::CalculateVerificationInfo(
654 self,
655 ®_types,
656 method,
657 dex_cache,
658 dex_pc));
659 if (verifier == nullptr) {
660 JVMTI_LOG(WARNING, jvmti_) << "Unable to extract verification information from "
661 << method->PrettyMethod() << " due to hard verification failures! "
662 << "How did this method even get loaded!";
663 return ERR(INTERNAL);
664 }
665 art::verifier::RegisterLine* line = verifier->GetRegLine(dex_pc);
666 if (line == nullptr) {
667 JVMTI_LOG(WARNING, jvmti_) << "Unable to determine register line at dex-pc " << dex_pc
668 << " for method " << method->PrettyMethod();
669 return ERR(OPAQUE_FRAME);
670 }
671 const art::verifier::RegType& rt = line->GetRegisterType(verifier.get(), slot_);
672 if (rt.IsUndefined()) {
673 return ERR(INVALID_SLOT);
674 } else if (rt.IsNonZeroReferenceTypes() || rt.IsNull()) {
675 *descriptor = (rt.HasClass() ? rt.GetDescriptor() : "Ljava/lang/Object;");
676 *type = VerifierPrimitiveType::kReferenceValue;
677 return OK;
678 } else if (rt.IsZero()) {
679 *descriptor = "I";
680 *type = VerifierPrimitiveType::kZeroValue;
681 return OK;
682 } else if (rt.IsCategory1Types()) {
683 *descriptor = "I";
684 *type = VerifierPrimitiveType::k32BitValue;
685 return OK;
686 } else if (rt.IsCategory2Types() && rt.IsLowHalf()) {
687 *descriptor = "J";
688 *type = VerifierPrimitiveType::k64BitValue;
689 return OK;
690 } else {
691 // The slot doesn't have a type. Must not be valid here.
692 return ERR(INVALID_SLOT);
693 }
694 }
695
SquashType(SlotType t)696 constexpr VerifierPrimitiveType SquashType(SlotType t) {
697 if (std::holds_alternative<art::Primitive::Type>(t)) {
698 switch (std::get<art::Primitive::Type>(t)) {
699 // 32-bit primitives
700 case art::Primitive::kPrimByte:
701 case art::Primitive::kPrimChar:
702 case art::Primitive::kPrimInt:
703 case art::Primitive::kPrimShort:
704 case art::Primitive::kPrimBoolean:
705 case art::Primitive::kPrimFloat:
706 return VerifierPrimitiveType::k32BitValue;
707 // 64-bit primitives
708 case art::Primitive::kPrimLong:
709 case art::Primitive::kPrimDouble:
710 return VerifierPrimitiveType::k64BitValue;
711 case art::Primitive::kPrimNot:
712 return VerifierPrimitiveType::kReferenceValue;
713 case art::Primitive::kPrimVoid:
714 LOG(FATAL) << "Got kPrimVoid";
715 UNREACHABLE();
716 }
717 } else {
718 return std::get<VerifierPrimitiveType>(t);
719 }
720 }
721
722 jvmtiEnv* jvmti_;
723 jvmtiError result_;
724 jint depth_;
725 jint slot_;
726
727 private:
728 DISALLOW_COPY_AND_ASSIGN(CommonLocalVariableClosure);
729 };
730
operator <<(std::ostream & os,CommonLocalVariableClosure::VerifierPrimitiveType state)731 std::ostream& operator<<(std::ostream& os,
732 CommonLocalVariableClosure::VerifierPrimitiveType state) {
733 switch (state) {
734 case CommonLocalVariableClosure::VerifierPrimitiveType::k32BitValue:
735 return os << "32BitValue";
736 case CommonLocalVariableClosure::VerifierPrimitiveType::k64BitValue:
737 return os << "64BitValue";
738 case CommonLocalVariableClosure::VerifierPrimitiveType::kReferenceValue:
739 return os << "ReferenceValue";
740 case CommonLocalVariableClosure::VerifierPrimitiveType::kZeroValue:
741 return os << "ZeroValue";
742 }
743 }
744
operator <<(std::ostream & os,CommonLocalVariableClosure::SlotType state)745 std::ostream& operator<<(std::ostream& os, CommonLocalVariableClosure::SlotType state) {
746 if (std::holds_alternative<art::Primitive::Type>(state)) {
747 return os << "Primitive::Type[" << std::get<art::Primitive::Type>(state) << "]";
748 } else {
749 return os << "VerifierPrimitiveType["
750 << std::get<CommonLocalVariableClosure::VerifierPrimitiveType>(state) << "]";
751 }
752 }
753
GetSlotType(art::ArtMethod * method,uint32_t dex_pc,std::string * descriptor,SlotType * type)754 jvmtiError CommonLocalVariableClosure::GetSlotType(art::ArtMethod* method,
755 uint32_t dex_pc,
756 /*out*/ std::string* descriptor,
757 /*out*/ SlotType* type) {
758 const art::DexFile* dex_file = method->GetDexFile();
759 if (dex_file == nullptr) {
760 return ERR(OPAQUE_FRAME);
761 }
762 art::CodeItemDebugInfoAccessor accessor(method->DexInstructionDebugInfo());
763 if (!accessor.HasCodeItem()) {
764 return ERR(OPAQUE_FRAME);
765 }
766 bool found = false;
767 *type = art::Primitive::kPrimVoid;
768 descriptor->clear();
769 // To avoid defining visitor in the same line as the `if`. We define the lambda and use std::move.
770 auto visitor = [&](const art::DexFile::LocalInfo& entry) {
771 if (!found && entry.start_address_ <= dex_pc && entry.end_address_ > dex_pc &&
772 entry.reg_ == slot_) {
773 found = true;
774 *type = art::Primitive::GetType(entry.descriptor_[0]);
775 *descriptor = entry.descriptor_;
776 }
777 };
778 if (!accessor.DecodeDebugLocalInfo(
779 method->IsStatic(), method->GetDexMethodIndex(), std::move(visitor)) ||
780 !found) {
781 // Something went wrong with decoding the debug information. It might as well not be there.
782 // Try to find the type with the verifier.
783 // TODO This is very slow.
784 return InferSlotTypeFromVerifier(method, dex_pc, descriptor, type);
785 } else if (art::kIsDebugBuild) {
786 std::string type_unused;
787 SlotType verifier_type{ art::Primitive::kPrimVoid };
788 DCHECK_EQ(InferSlotTypeFromVerifier(method, dex_pc, &type_unused, &verifier_type), OK)
789 << method->PrettyMethod() << " failed to verify!";
790 if (*type == SlotType{ art::Primitive::kPrimNot }) {
791 // We cannot distinguish between a constant 0 and a null reference so we return that it is a
792 // 32bit value (Due to the way references are read by the interpreter this is safe even if
793 // it's modified, the value will remain null). This is not ideal since it prevents modifying
794 // locals in some circumstances but generally is not a big deal (since one can just modify it
795 // later once it's been determined to be a reference by a later instruction).
796 DCHECK(verifier_type == SlotType { VerifierPrimitiveType::kZeroValue } ||
797 verifier_type == SlotType { VerifierPrimitiveType::kReferenceValue })
798 << "Verifier disagrees on type of slot! debug: " << *type
799 << " verifier: " << verifier_type;
800 } else if (verifier_type == SlotType { VerifierPrimitiveType::kZeroValue }) {
801 DCHECK(VerifierPrimitiveType::k32BitValue == SquashType(*type) ||
802 VerifierPrimitiveType::kReferenceValue == SquashType(*type))
803 << "Verifier disagrees on type of slot! debug: " << *type
804 << " verifier: " << verifier_type;
805 } else {
806 DCHECK_EQ(SquashType(verifier_type), SquashType(*type))
807 << "Verifier disagrees on type of slot! debug: " << *type
808 << " verifier: " << verifier_type;
809 }
810 }
811 return OK;
812 }
813
814 class GetLocalVariableClosure : public CommonLocalVariableClosure {
815 public:
GetLocalVariableClosure(jvmtiEnv * jvmti,jint depth,jint slot,art::Primitive::Type type,jvalue * val)816 GetLocalVariableClosure(jvmtiEnv* jvmti,
817 jint depth,
818 jint slot,
819 art::Primitive::Type type,
820 jvalue* val)
821 : CommonLocalVariableClosure(jvmti, depth, slot),
822 type_(type),
823 val_(val),
824 obj_val_(nullptr) {}
825
GetResult()826 jvmtiError GetResult() override REQUIRES_SHARED(art::Locks::mutator_lock_) {
827 if (result_ == OK && type_ == art::Primitive::kPrimNot) {
828 if (obj_val_ == nullptr) {
829 val_->l = nullptr;
830 } else {
831 art::JNIEnvExt* jni = art::Thread::Current()->GetJniEnv();
832 val_->l = static_cast<JNIEnv*>(jni)->NewLocalRef(obj_val_);
833 jni->DeleteGlobalRef(obj_val_);
834 obj_val_ = nullptr;
835 }
836 }
837 return CommonLocalVariableClosure::GetResult();
838 }
839
840 protected:
841 jvmtiError
GetTypeError(art::ArtMethod * method,SlotType slot_type,const std::string & descriptor)842 GetTypeError(art::ArtMethod* method, SlotType slot_type, const std::string& descriptor) override
843 REQUIRES_SHARED(art::Locks::mutator_lock_) {
844 jvmtiError res = GetTypeErrorInner(method, slot_type, descriptor);
845 if (res == ERR(TYPE_MISMATCH)) {
846 JVMTI_LOG(INFO, jvmti_) << "Unable to Get local variable in slot " << slot_ << ". Expected"
847 << " slot to be of type compatible with " << SlotType { type_ }
848 << " but slot is " << slot_type;
849 } else if (res != OK) {
850 JVMTI_LOG(INFO, jvmti_) << "Unable to get local variable in slot " << slot_ << ".";
851 }
852 return res;
853 }
854
GetTypeErrorInner(art::ArtMethod * method,SlotType slot_type,const std::string & descriptor)855 jvmtiError GetTypeErrorInner([[maybe_unused]] art::ArtMethod* method,
856 SlotType slot_type,
857 [[maybe_unused]] const std::string& descriptor)
858 REQUIRES_SHARED(art::Locks::mutator_lock_) {
859 switch (type_) {
860 case art::Primitive::kPrimFloat:
861 case art::Primitive::kPrimInt: {
862 if (std::holds_alternative<VerifierPrimitiveType>(slot_type)) {
863 return (slot_type == SlotType { VerifierPrimitiveType::k32BitValue } ||
864 slot_type == SlotType { VerifierPrimitiveType::kZeroValue })
865 ? OK
866 : ERR(TYPE_MISMATCH);
867 } else if (type_ == art::Primitive::kPrimFloat ||
868 slot_type == SlotType { art::Primitive::kPrimFloat }) {
869 // Check that we are actually a float.
870 return (SlotType { type_ } == slot_type) ? OK : ERR(TYPE_MISMATCH);
871 } else {
872 // Some smaller int type.
873 return SquashType(slot_type) == SquashType(SlotType { type_ }) ? OK : ERR(TYPE_MISMATCH);
874 }
875 }
876 case art::Primitive::kPrimLong:
877 case art::Primitive::kPrimDouble: {
878 // todo
879 if (std::holds_alternative<VerifierPrimitiveType>(slot_type)) {
880 return (slot_type == SlotType { VerifierPrimitiveType::k64BitValue })
881 ? OK
882 : ERR(TYPE_MISMATCH);
883 } else {
884 return slot_type == SlotType { type_ } ? OK : ERR(TYPE_MISMATCH);
885 }
886 }
887 case art::Primitive::kPrimNot:
888 return (SquashType(slot_type) == VerifierPrimitiveType::kReferenceValue ||
889 SquashType(slot_type) == VerifierPrimitiveType::kZeroValue)
890 ? OK
891 : ERR(TYPE_MISMATCH);
892 case art::Primitive::kPrimShort:
893 case art::Primitive::kPrimChar:
894 case art::Primitive::kPrimByte:
895 case art::Primitive::kPrimBoolean:
896 case art::Primitive::kPrimVoid:
897 LOG(FATAL) << "Unexpected primitive type " << slot_type;
898 UNREACHABLE();
899 }
900 }
901
Execute(art::ArtMethod * method,art::StackVisitor & visitor)902 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
903 override REQUIRES_SHARED(art::Locks::mutator_lock_) {
904 switch (type_) {
905 case art::Primitive::kPrimNot: {
906 uint32_t ptr_val;
907 if (!visitor.GetVReg(method,
908 static_cast<uint16_t>(slot_),
909 art::kReferenceVReg,
910 &ptr_val)) {
911 return ERR(OPAQUE_FRAME);
912 }
913 art::ObjPtr<art::mirror::Object> obj(reinterpret_cast<art::mirror::Object*>(ptr_val));
914 obj_val_ = art::Runtime::Current()->GetJavaVM()->AddGlobalRef(art::Thread::Current(), obj);
915 break;
916 }
917 case art::Primitive::kPrimInt:
918 case art::Primitive::kPrimFloat: {
919 if (!visitor.GetVReg(method,
920 static_cast<uint16_t>(slot_),
921 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg : art::kIntVReg,
922 reinterpret_cast<uint32_t*>(&val_->i))) {
923 return ERR(OPAQUE_FRAME);
924 }
925 break;
926 }
927 case art::Primitive::kPrimDouble:
928 case art::Primitive::kPrimLong: {
929 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
930 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
931 if (!visitor.GetVRegPair(method,
932 static_cast<uint16_t>(slot_),
933 lo_type,
934 high_type,
935 reinterpret_cast<uint64_t*>(&val_->j))) {
936 return ERR(OPAQUE_FRAME);
937 }
938 break;
939 }
940 default: {
941 LOG(FATAL) << "unexpected register type " << type_;
942 UNREACHABLE();
943 }
944 }
945 return OK;
946 }
947
948 private:
949 art::Primitive::Type type_;
950 jvalue* val_;
951 // A global reference to the return value. We use the global reference to safely transfer the
952 // value between threads.
953 jobject obj_val_;
954 };
955
GetLocalVariableGeneric(jvmtiEnv * env,jthread thread,jint depth,jint slot,art::Primitive::Type type,jvalue * val)956 jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env,
957 jthread thread,
958 jint depth,
959 jint slot,
960 art::Primitive::Type type,
961 jvalue* val) {
962 if (depth < 0) {
963 return ERR(ILLEGAL_ARGUMENT);
964 }
965 art::Thread* self = art::Thread::Current();
966 art::ScopedObjectAccess soa(self);
967 art::Locks::thread_list_lock_->ExclusiveLock(self);
968 art::Thread* target = nullptr;
969 jvmtiError err = ERR(INTERNAL);
970 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
971 art::Locks::thread_list_lock_->ExclusiveUnlock(self);
972 return err;
973 }
974 GetLocalVariableClosure c(env, depth, slot, type, val);
975 // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
976 if (!target->RequestSynchronousCheckpoint(&c)) {
977 return ERR(THREAD_NOT_ALIVE);
978 } else {
979 return c.GetResult();
980 }
981 }
982
983 class SetLocalVariableClosure : public CommonLocalVariableClosure {
984 public:
SetLocalVariableClosure(jvmtiEnv * jvmti,art::Thread * caller,jint depth,jint slot,art::Primitive::Type type,jvalue val)985 SetLocalVariableClosure(jvmtiEnv* jvmti,
986 art::Thread* caller,
987 jint depth,
988 jint slot,
989 art::Primitive::Type type,
990 jvalue val)
991 : CommonLocalVariableClosure(jvmti, depth, slot), caller_(caller), type_(type), val_(val) {}
992
993 protected:
994 jvmtiError
GetTypeError(art::ArtMethod * method,SlotType slot_type,const std::string & descriptor)995 GetTypeError(art::ArtMethod* method, SlotType slot_type, const std::string& descriptor) override
996 REQUIRES_SHARED(art::Locks::mutator_lock_) {
997 jvmtiError res = GetTypeErrorInner(method, slot_type, descriptor);
998 if (res != OK) {
999 if (res == ERR(TYPE_MISMATCH)) {
1000 std::ostringstream desc_exp;
1001 std::ostringstream desc_set;
1002 if (type_ == art::Primitive::kPrimNot) {
1003 desc_exp << " (type: " << descriptor << ")";
1004 art::ObjPtr<art::mirror::Object> new_val(art::Thread::Current()->DecodeJObject(val_.l));
1005 desc_set << " (type: "
1006 << (new_val.IsNull() ? "NULL" : new_val->GetClass()->PrettyDescriptor()) << ")";
1007 }
1008 JVMTI_LOG(INFO, jvmti_) << "Unable to Set local variable in slot " << slot_ << ". Expected"
1009 << " slot to be of type compatible with " << SlotType{ type_ }
1010 << desc_set.str() << " but slot is " << slot_type << desc_exp.str();
1011 } else {
1012 JVMTI_LOG(INFO, jvmti_) << "Unable to set local variable in slot " << slot_ << ". "
1013 << err_.str();
1014 }
1015 }
1016 return res;
1017 }
1018
1019 jvmtiError
GetTypeErrorInner(art::ArtMethod * method,SlotType slot_type,const std::string & descriptor)1020 GetTypeErrorInner(art::ArtMethod* method, SlotType slot_type, const std::string& descriptor)
1021 REQUIRES_SHARED(art::Locks::mutator_lock_) {
1022 switch (SquashType(SlotType{ type_ })) {
1023 case VerifierPrimitiveType::k32BitValue: {
1024 if (slot_type == SlotType{ VerifierPrimitiveType::kZeroValue }) {
1025 if (val_.i == 0) {
1026 return OK;
1027 } else {
1028 err_ << "Cannot determine if slot " << slot_ << " is a null reference or 32bit "
1029 << "constant. Cannot allow writing to slot.";
1030 return ERR(INTERNAL);
1031 }
1032 } else if (SquashType(slot_type) != VerifierPrimitiveType::k32BitValue) {
1033 return ERR(TYPE_MISMATCH);
1034 } else if (slot_type == SlotType { VerifierPrimitiveType::k32BitValue } ||
1035 slot_type == SlotType { type_ }) {
1036 return OK;
1037 } else if (type_ == art::Primitive::kPrimFloat ||
1038 slot_type == SlotType { art::Primitive::kPrimFloat }) {
1039 // we should have hit the get == type_ above
1040 return ERR(TYPE_MISMATCH);
1041 } else {
1042 // Some smaller type then int.
1043 return OK;
1044 }
1045 }
1046 case VerifierPrimitiveType::k64BitValue: {
1047 if (slot_type == SlotType { VerifierPrimitiveType::k64BitValue } ||
1048 slot_type == SlotType { type_ }) {
1049 return OK;
1050 } else {
1051 return ERR(TYPE_MISMATCH);
1052 }
1053 }
1054 case VerifierPrimitiveType::kReferenceValue: {
1055 if (SquashType(slot_type) != VerifierPrimitiveType::kReferenceValue &&
1056 SquashType(slot_type) != VerifierPrimitiveType::kZeroValue) {
1057 return ERR(TYPE_MISMATCH);
1058 } else if (val_.l == nullptr) {
1059 return OK;
1060 } else if (slot_type == SlotType { VerifierPrimitiveType::kZeroValue }) {
1061 err_ << "Cannot determine if slot " << slot_ << " is a null "
1062 << "reference or 32bit constant. Cannot allow writing to slot.";
1063 return ERR(INTERNAL);
1064 } else {
1065 art::ClassLinker* cl = art::Runtime::Current()->GetClassLinker();
1066 art::ObjPtr<art::mirror::Class> set_class = caller_->DecodeJObject(val_.l)->GetClass();
1067 art::ObjPtr<art::mirror::ClassLoader> loader =
1068 method->GetDeclaringClass()->GetClassLoader();
1069 art::ObjPtr<art::mirror::Class> slot_class = cl->LookupClass(caller_, descriptor, loader);
1070 DCHECK(!slot_class.IsNull()) << descriptor << " slot: " << slot_type;
1071 return slot_class->IsAssignableFrom(set_class) ? OK : ERR(TYPE_MISMATCH);
1072 }
1073 }
1074 case VerifierPrimitiveType::kZeroValue: {
1075 LOG(FATAL) << "Illegal result from SquashType of art::Primitive::Type " << type_;
1076 UNREACHABLE();
1077 }
1078 }
1079 }
1080
Execute(art::ArtMethod * method,art::StackVisitor & visitor)1081 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
1082 override REQUIRES_SHARED(art::Locks::mutator_lock_) {
1083 switch (type_) {
1084 case art::Primitive::kPrimNot: {
1085 if (!visitor.SetVRegReference(method,
1086 static_cast<uint16_t>(slot_),
1087 caller_->DecodeJObject(val_.l))) {
1088 return ERR(OPAQUE_FRAME);
1089 }
1090 break;
1091 }
1092 case art::Primitive::kPrimInt:
1093 case art::Primitive::kPrimFloat: {
1094 if (!visitor.SetVReg(method,
1095 static_cast<uint16_t>(slot_),
1096 static_cast<uint32_t>(val_.i),
1097 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg
1098 : art::kIntVReg)) {
1099 return ERR(OPAQUE_FRAME);
1100 }
1101 break;
1102 }
1103 case art::Primitive::kPrimDouble:
1104 case art::Primitive::kPrimLong: {
1105 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
1106 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
1107 if (!visitor.SetVRegPair(method,
1108 static_cast<uint16_t>(slot_),
1109 static_cast<uint64_t>(val_.j),
1110 lo_type,
1111 high_type)) {
1112 return ERR(OPAQUE_FRAME);
1113 }
1114 break;
1115 }
1116 default: {
1117 LOG(FATAL) << "unexpected register type " << type_;
1118 UNREACHABLE();
1119 }
1120 }
1121 return OK;
1122 }
1123
1124 private:
1125 art::Thread* caller_;
1126 art::Primitive::Type type_;
1127 jvalue val_;
1128 std::ostringstream err_;
1129 };
1130
SetLocalVariableGeneric(jvmtiEnv * env,jthread thread,jint depth,jint slot,art::Primitive::Type type,jvalue val)1131 jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env,
1132 jthread thread,
1133 jint depth,
1134 jint slot,
1135 art::Primitive::Type type,
1136 jvalue val) {
1137 if (depth < 0) {
1138 return ERR(ILLEGAL_ARGUMENT);
1139 }
1140 // Make sure that we know not to do any OSR anymore.
1141 // TODO We should really keep track of this at the Frame granularity.
1142 DeoptManager::Get()->SetLocalsUpdated();
1143 art::Thread* self = art::Thread::Current();
1144 art::ScopedObjectAccess soa(self);
1145 art::Locks::thread_list_lock_->ExclusiveLock(self);
1146 art::Thread* target = nullptr;
1147 jvmtiError err = ERR(INTERNAL);
1148 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
1149 art::Locks::thread_list_lock_->ExclusiveUnlock(self);
1150 return err;
1151 }
1152 SetLocalVariableClosure c(env, self, depth, slot, type, val);
1153 // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
1154 if (!target->RequestSynchronousCheckpoint(&c)) {
1155 return ERR(THREAD_NOT_ALIVE);
1156 } else {
1157 return c.GetResult();
1158 }
1159 }
1160
1161 class GetLocalInstanceClosure : public art::Closure {
1162 public:
GetLocalInstanceClosure(jint depth)1163 explicit GetLocalInstanceClosure(jint depth)
1164 : result_(ERR(INTERNAL)),
1165 depth_(depth),
1166 val_(nullptr) {}
1167
Run(art::Thread * self)1168 void Run(art::Thread* self) override REQUIRES(art::Locks::mutator_lock_) {
1169 art::ScopedAssertNoThreadSuspension sants("GetLocalInstanceClosure::Run");
1170 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
1171 std::unique_ptr<art::Context> context(art::Context::Create());
1172 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
1173 visitor.WalkStack();
1174 if (!visitor.FoundFrame()) {
1175 // Must have been a bad depth.
1176 result_ = ERR(NO_MORE_FRAMES);
1177 return;
1178 }
1179 result_ = OK;
1180 val_ = art::GcRoot<art::mirror::Object>(visitor.GetThisObject());
1181 }
1182
GetResult(jobject * data_out)1183 jvmtiError GetResult(jobject* data_out) REQUIRES_SHARED(art::Locks::mutator_lock_) {
1184 if (result_ == OK) {
1185 *data_out = val_.IsNull()
1186 ? nullptr
1187 : art::Thread::Current()->GetJniEnv()->AddLocalReference<jobject>(val_.Read());
1188 }
1189 return result_;
1190 }
1191
1192 private:
1193 jvmtiError result_;
1194 jint depth_;
1195 art::GcRoot<art::mirror::Object> val_;
1196 };
1197
GetLocalInstance(jvmtiEnv * env,jthread thread,jint depth,jobject * data)1198 jvmtiError MethodUtil::GetLocalInstance([[maybe_unused]] jvmtiEnv* env,
1199 jthread thread,
1200 jint depth,
1201 jobject* data) {
1202 if (depth < 0) {
1203 return ERR(ILLEGAL_ARGUMENT);
1204 }
1205 art::Thread* self = art::Thread::Current();
1206 art::ScopedObjectAccess soa(self);
1207 art::Locks::thread_list_lock_->ExclusiveLock(self);
1208 art::Thread* target = nullptr;
1209 jvmtiError err = ERR(INTERNAL);
1210 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
1211 art::Locks::thread_list_lock_->ExclusiveUnlock(self);
1212 return err;
1213 }
1214 art::ScopedAssertNoThreadSuspension sants("Performing GetLocalInstance");
1215 GetLocalInstanceClosure c(depth);
1216 // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution. We
1217 // need to avoid suspending as we wait for the checkpoint to occur since we are (potentially)
1218 // transfering a GcRoot across threads.
1219 if (!target->RequestSynchronousCheckpoint(&c, art::ThreadState::kRunnable)) {
1220 return ERR(THREAD_NOT_ALIVE);
1221 } else {
1222 return c.GetResult(data);
1223 }
1224 }
1225
1226 #define FOR_JVMTI_JVALUE_TYPES(fn) \
1227 fn(jint, art::Primitive::kPrimInt, i) \
1228 fn(jlong, art::Primitive::kPrimLong, j) \
1229 fn(jfloat, art::Primitive::kPrimFloat, f) \
1230 fn(jdouble, art::Primitive::kPrimDouble, d) \
1231 fn(jobject, art::Primitive::kPrimNot, l)
1232
1233 namespace impl {
1234
1235 template<typename T> void WriteJvalue(T, jvalue*);
1236 template<typename T> void ReadJvalue(jvalue, T*);
1237 template<typename T> art::Primitive::Type GetJNIType();
1238
1239 #define JNI_TYPE_CHAR(type, prim, id) \
1240 template<> art::Primitive::Type GetJNIType<type>() { \
1241 return prim; \
1242 }
1243
1244 FOR_JVMTI_JVALUE_TYPES(JNI_TYPE_CHAR);
1245
1246 #undef JNI_TYPE_CHAR
1247
1248 #define RW_JVALUE(srctype, prim, id) \
1249 template<> void ReadJvalue<srctype>(jvalue in, std::add_pointer<srctype>::type out) { \
1250 *out = in.id; \
1251 } \
1252 template<> void WriteJvalue<srctype>(srctype in, jvalue* out) { \
1253 out->id = in; \
1254 }
1255
1256 FOR_JVMTI_JVALUE_TYPES(RW_JVALUE);
1257
1258 #undef RW_JVALUE
1259
1260 } // namespace impl
1261
1262 template<typename T>
SetLocalVariable(jvmtiEnv * env,jthread thread,jint depth,jint slot,T data)1263 jvmtiError MethodUtil::SetLocalVariable(jvmtiEnv* env,
1264 jthread thread,
1265 jint depth,
1266 jint slot,
1267 T data) {
1268 jvalue v = {.j = 0};
1269 art::Primitive::Type type = impl::GetJNIType<T>();
1270 impl::WriteJvalue(data, &v);
1271 return SetLocalVariableGeneric(env, thread, depth, slot, type, v);
1272 }
1273
1274 template<typename T>
GetLocalVariable(jvmtiEnv * env,jthread thread,jint depth,jint slot,T * data)1275 jvmtiError MethodUtil::GetLocalVariable(jvmtiEnv* env,
1276 jthread thread,
1277 jint depth,
1278 jint slot,
1279 T* data) {
1280 if (data == nullptr) {
1281 return ERR(NULL_POINTER);
1282 }
1283 jvalue v = {.j = 0};
1284 art::Primitive::Type type = impl::GetJNIType<T>();
1285 jvmtiError err = GetLocalVariableGeneric(env, thread, depth, slot, type, &v);
1286 if (err != OK) {
1287 return err;
1288 } else {
1289 impl::ReadJvalue(v, data);
1290 return OK;
1291 }
1292 }
1293
1294 #define GET_SET_LV(srctype, prim, id) \
1295 template jvmtiError MethodUtil::GetLocalVariable<srctype>(jvmtiEnv*, \
1296 jthread, \
1297 jint, \
1298 jint, \
1299 std::add_pointer<srctype>::type); \
1300 template jvmtiError MethodUtil::SetLocalVariable<srctype>(jvmtiEnv*, \
1301 jthread, \
1302 jint, \
1303 jint, \
1304 srctype);
1305
1306 FOR_JVMTI_JVALUE_TYPES(GET_SET_LV);
1307
1308 #undef GET_SET_LV
1309
1310 #undef FOR_JVMTI_JVALUE_TYPES
1311
1312 } // namespace openjdkjvmti
1313