xref: /aosp_15_r20/art/openjdkjvmti/ti_method.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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             &reg_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