• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <type_traits>
35 
36 #include "arch/context.h"
37 #include "art_jvmti.h"
38 #include "art_method-inl.h"
39 #include "base/enums.h"
40 #include "base/mutex-inl.h"
41 #include "deopt_manager.h"
42 #include "dex/code_item_accessors-inl.h"
43 #include "dex/dex_file_annotations.h"
44 #include "dex/dex_file_types.h"
45 #include "dex/modifiers.h"
46 #include "events-inl.h"
47 #include "gc_root-inl.h"
48 #include "jit/jit.h"
49 #include "jni/jni_internal.h"
50 #include "mirror/class-inl.h"
51 #include "mirror/class_loader.h"
52 #include "mirror/object-inl.h"
53 #include "mirror/object_array-inl.h"
54 #include "nativehelper/scoped_local_ref.h"
55 #include "oat_file.h"
56 #include "obj_ptr.h"
57 #include "runtime_callbacks.h"
58 #include "scoped_thread_state_change-inl.h"
59 #include "stack.h"
60 #include "thread-current-inl.h"
61 #include "thread.h"
62 #include "thread_list.h"
63 #include "ti_stack.h"
64 #include "ti_thread.h"
65 #include "ti_phase.h"
66 
67 namespace openjdkjvmti {
68 
69 struct TiMethodCallback : public art::MethodCallback {
RegisterNativeMethodopenjdkjvmti::TiMethodCallback70   void RegisterNativeMethod(art::ArtMethod* method,
71                             const void* cur_method,
72                             /*out*/void** new_method)
73       override REQUIRES_SHARED(art::Locks::mutator_lock_) {
74     if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kNativeMethodBind)) {
75       art::Thread* thread = art::Thread::Current();
76       art::JNIEnvExt* jnienv = thread->GetJniEnv();
77       ScopedLocalRef<jthread> thread_jni(
78           jnienv, PhaseUtil::IsLivePhase() ? jnienv->AddLocalReference<jthread>(thread->GetPeer())
79                                            : nullptr);
80       art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
81       event_handler->DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(
82           thread,
83           static_cast<JNIEnv*>(jnienv),
84           thread_jni.get(),
85           art::jni::EncodeArtMethod(method),
86           const_cast<void*>(cur_method),
87           new_method);
88     }
89   }
90 
91   EventHandler* event_handler = nullptr;
92 };
93 
94 TiMethodCallback gMethodCallback;
95 
Register(EventHandler * handler)96 void MethodUtil::Register(EventHandler* handler) {
97   gMethodCallback.event_handler = handler;
98   art::ScopedThreadStateChange stsc(art::Thread::Current(),
99                                     art::ThreadState::kWaitingForDebuggerToAttach);
100   art::ScopedSuspendAll ssa("Add method callback");
101   art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
102   callbacks->AddMethodCallback(&gMethodCallback);
103 }
104 
Unregister()105 void MethodUtil::Unregister() {
106   art::ScopedThreadStateChange stsc(art::Thread::Current(),
107                                     art::ThreadState::kWaitingForDebuggerToAttach);
108   art::ScopedSuspendAll ssa("Remove method callback");
109   art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
110   callbacks->RemoveMethodCallback(&gMethodCallback);
111 }
112 
GetBytecodes(jvmtiEnv * env,jmethodID method,jint * size_ptr,unsigned char ** bytecode_ptr)113 jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
114                                     jmethodID method,
115                                     jint* size_ptr,
116                                     unsigned char** bytecode_ptr) {
117   if (method == nullptr) {
118     return ERR(INVALID_METHODID);
119   }
120   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
121 
122   if (art_method->IsNative()) {
123     return ERR(NATIVE_METHOD);
124   }
125 
126   if (size_ptr == nullptr || bytecode_ptr == nullptr) {
127     return ERR(NULL_POINTER);
128   }
129 
130   art::ScopedObjectAccess soa(art::Thread::Current());
131   art::CodeItemInstructionAccessor accessor(art_method->DexInstructions());
132   if (!accessor.HasCodeItem()) {
133     *size_ptr = 0;
134     *bytecode_ptr = nullptr;
135     return OK;
136   }
137   // 2 bytes per instruction for dex code.
138   *size_ptr = accessor.InsnsSizeInCodeUnits() * 2;
139   jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr);
140   if (err != OK) {
141     return err;
142   }
143   memcpy(*bytecode_ptr, accessor.Insns(), *size_ptr);
144   return OK;
145 }
146 
GetArgumentsSize(jvmtiEnv * env ATTRIBUTE_UNUSED,jmethodID method,jint * size_ptr)147 jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
148                                         jmethodID method,
149                                         jint* size_ptr) {
150   if (method == nullptr) {
151     return ERR(INVALID_METHODID);
152   }
153   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
154 
155   if (art_method->IsNative()) {
156     return ERR(NATIVE_METHOD);
157   }
158 
159   if (size_ptr == nullptr) {
160     return ERR(NULL_POINTER);
161   }
162 
163   art::ScopedObjectAccess soa(art::Thread::Current());
164   if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
165     // Use the shorty.
166     art::ArtMethod* base_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
167     size_t arg_count = art::ArtMethod::NumArgRegisters(base_method->GetShorty());
168     if (!base_method->IsStatic()) {
169       arg_count++;
170     }
171     *size_ptr = static_cast<jint>(arg_count);
172     return ERR(NONE);
173   }
174 
175   DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
176   *size_ptr = art_method->DexInstructionData().InsSize();
177 
178   return ERR(NONE);
179 }
180 
GetLocalVariableTable(jvmtiEnv * env,jmethodID method,jint * entry_count_ptr,jvmtiLocalVariableEntry ** table_ptr)181 jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
182                                              jmethodID method,
183                                              jint* entry_count_ptr,
184                                              jvmtiLocalVariableEntry** table_ptr) {
185   if (method == nullptr) {
186     return ERR(INVALID_METHODID);
187   }
188   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
189 
190   if (art_method->IsNative()) {
191     return ERR(NATIVE_METHOD);
192   }
193 
194   if (entry_count_ptr == nullptr || table_ptr == nullptr) {
195     return ERR(NULL_POINTER);
196   }
197 
198   art::ScopedObjectAccess soa(art::Thread::Current());
199 
200   const art::DexFile* const dex_file = art_method->GetDexFile();
201   if (dex_file == nullptr) {
202     return ERR(ABSENT_INFORMATION);
203   }
204 
205   // TODO HasCodeItem == false means that the method is abstract (or native, but we check that
206   // earlier). We should check what is returned by the RI in this situation since it's not clear
207   // what the appropriate return value is from the spec.
208   art::CodeItemDebugInfoAccessor accessor(art_method->DexInstructionDebugInfo());
209   if (!accessor.HasCodeItem()) {
210     return ERR(ABSENT_INFORMATION);
211   }
212 
213   std::vector<jvmtiLocalVariableEntry> variables;
214   jvmtiError err = OK;
215 
216   auto release = [&](jint* out_entry_count_ptr, jvmtiLocalVariableEntry** out_table_ptr) {
217     jlong table_size = sizeof(jvmtiLocalVariableEntry) * variables.size();
218     if (err != OK ||
219         (err = env->Allocate(table_size,
220                               reinterpret_cast<unsigned char**>(out_table_ptr))) != OK) {
221       for (jvmtiLocalVariableEntry& e : variables) {
222         env->Deallocate(reinterpret_cast<unsigned char*>(e.name));
223         env->Deallocate(reinterpret_cast<unsigned char*>(e.signature));
224         env->Deallocate(reinterpret_cast<unsigned char*>(e.generic_signature));
225       }
226       return err;
227     }
228     *out_entry_count_ptr = variables.size();
229     memcpy(*out_table_ptr, variables.data(), table_size);
230     return OK;
231   };
232 
233   auto visitor = [&](const art::DexFile::LocalInfo& entry) {
234     if (err != OK) {
235       return;
236     }
237     JvmtiUniquePtr<char[]> name_str = CopyString(env, entry.name_, &err);
238     if (err != OK) {
239       return;
240     }
241     JvmtiUniquePtr<char[]> sig_str = CopyString(env, entry.descriptor_, &err);
242     if (err != OK) {
243       return;
244     }
245     JvmtiUniquePtr<char[]> generic_sig_str = CopyString(env, entry.signature_, &err);
246     if (err != OK) {
247       return;
248     }
249     variables.push_back({
250       .start_location = static_cast<jlocation>(entry.start_address_),
251       .length = static_cast<jint>(entry.end_address_ - entry.start_address_),
252       .name = name_str.release(),
253       .signature = sig_str.release(),
254       .generic_signature = generic_sig_str.release(),
255       .slot = entry.reg_,
256     });
257   };
258 
259   if (!accessor.DecodeDebugLocalInfo(art_method->IsStatic(),
260                                      art_method->GetDexMethodIndex(),
261                                      visitor)) {
262     // Something went wrong with decoding the debug information. It might as well not be there.
263     return ERR(ABSENT_INFORMATION);
264   }
265   return release(entry_count_ptr, table_ptr);
266 }
267 
GetMaxLocals(jvmtiEnv * env ATTRIBUTE_UNUSED,jmethodID method,jint * max_ptr)268 jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
269                                     jmethodID method,
270                                     jint* max_ptr) {
271   if (method == nullptr) {
272     return ERR(INVALID_METHODID);
273   }
274   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
275 
276   if (art_method->IsNative()) {
277     return ERR(NATIVE_METHOD);
278   }
279 
280   if (max_ptr == nullptr) {
281     return ERR(NULL_POINTER);
282   }
283 
284   art::ScopedObjectAccess soa(art::Thread::Current());
285   if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
286     // This isn't specified as an error case, so return 0.
287     *max_ptr = 0;
288     return ERR(NONE);
289   }
290 
291   DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
292   *max_ptr = art_method->DexInstructionData().RegistersSize();
293 
294   return ERR(NONE);
295 }
296 
GetMethodName(jvmtiEnv * env,jmethodID method,char ** name_ptr,char ** signature_ptr,char ** generic_ptr)297 jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
298                                      jmethodID method,
299                                      char** name_ptr,
300                                      char** signature_ptr,
301                                      char** generic_ptr) {
302   art::ScopedObjectAccess soa(art::Thread::Current());
303   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
304   art_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
305 
306   JvmtiUniquePtr<char[]> name_copy;
307   if (name_ptr != nullptr) {
308     const char* method_name = art_method->GetName();
309     if (method_name == nullptr) {
310       method_name = "<error>";
311     }
312     jvmtiError ret;
313     name_copy = CopyString(env, method_name, &ret);
314     if (name_copy == nullptr) {
315       return ret;
316     }
317     *name_ptr = name_copy.get();
318   }
319 
320   JvmtiUniquePtr<char[]> signature_copy;
321   if (signature_ptr != nullptr) {
322     const art::Signature sig = art_method->GetSignature();
323     std::string str = sig.ToString();
324     jvmtiError ret;
325     signature_copy = CopyString(env, str.c_str(), &ret);
326     if (signature_copy == nullptr) {
327       return ret;
328     }
329     *signature_ptr = signature_copy.get();
330   }
331 
332   if (generic_ptr != nullptr) {
333     *generic_ptr = nullptr;
334     if (!art_method->GetDeclaringClass()->IsProxyClass()) {
335       art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array =
336           art::annotations::GetSignatureAnnotationForMethod(art_method);
337       if (str_array != nullptr) {
338         std::ostringstream oss;
339         for (int32_t i = 0; i != str_array->GetLength(); ++i) {
340           oss << str_array->Get(i)->ToModifiedUtf8();
341         }
342         std::string output_string = oss.str();
343         jvmtiError ret;
344         JvmtiUniquePtr<char[]> generic_copy = CopyString(env, output_string.c_str(), &ret);
345         if (generic_copy == nullptr) {
346           return ret;
347         }
348         *generic_ptr = generic_copy.release();
349       } else if (soa.Self()->IsExceptionPending()) {
350         // TODO: Should we report an error here?
351         soa.Self()->ClearException();
352       }
353     }
354   }
355 
356   // Everything is fine, release the buffers.
357   name_copy.release();
358   signature_copy.release();
359 
360   return ERR(NONE);
361 }
362 
GetMethodDeclaringClass(jvmtiEnv * env ATTRIBUTE_UNUSED,jmethodID method,jclass * declaring_class_ptr)363 jvmtiError MethodUtil::GetMethodDeclaringClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
364                                                jmethodID method,
365                                                jclass* declaring_class_ptr) {
366   if (declaring_class_ptr == nullptr) {
367     return ERR(NULL_POINTER);
368   }
369 
370   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
371   // Note: No GetInterfaceMethodIfProxy, we want to actual class.
372 
373   art::ScopedObjectAccess soa(art::Thread::Current());
374   art::ObjPtr<art::mirror::Class> klass = art_method->GetDeclaringClass();
375   *declaring_class_ptr = soa.AddLocalReference<jclass>(klass);
376 
377   return ERR(NONE);
378 }
379 
GetMethodLocation(jvmtiEnv * env ATTRIBUTE_UNUSED,jmethodID method,jlocation * start_location_ptr,jlocation * end_location_ptr)380 jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
381                                          jmethodID method,
382                                          jlocation* start_location_ptr,
383                                          jlocation* end_location_ptr) {
384   if (method == nullptr) {
385     return ERR(INVALID_METHODID);
386   }
387   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
388 
389   if (art_method->IsNative()) {
390     return ERR(NATIVE_METHOD);
391   }
392 
393   if (start_location_ptr == nullptr || end_location_ptr == nullptr) {
394     return ERR(NULL_POINTER);
395   }
396 
397   art::ScopedObjectAccess soa(art::Thread::Current());
398   if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
399     // This isn't specified as an error case, so return -1/-1 as the RI does.
400     *start_location_ptr = -1;
401     *end_location_ptr = -1;
402     return ERR(NONE);
403   }
404 
405   DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
406   *start_location_ptr = 0;
407   *end_location_ptr = art_method->DexInstructions().InsnsSizeInCodeUnits() - 1;
408 
409   return ERR(NONE);
410 }
411 
GetMethodModifiers(jvmtiEnv * env ATTRIBUTE_UNUSED,jmethodID method,jint * modifiers_ptr)412 jvmtiError MethodUtil::GetMethodModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
413                                           jmethodID method,
414                                           jint* modifiers_ptr) {
415   if (modifiers_ptr == nullptr) {
416     return ERR(NULL_POINTER);
417   }
418 
419   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
420   uint32_t modifiers = art_method->GetAccessFlags();
421 
422   // Note: Keep this code in sync with Executable.fixMethodFlags.
423   if ((modifiers & art::kAccAbstract) != 0) {
424     modifiers &= ~art::kAccNative;
425   }
426   modifiers &= ~art::kAccSynchronized;
427   if ((modifiers & art::kAccDeclaredSynchronized) != 0) {
428     modifiers |= art::kAccSynchronized;
429   }
430   modifiers &= art::kAccJavaFlagsMask;
431 
432   *modifiers_ptr = modifiers;
433   return ERR(NONE);
434 }
435 
GetLineNumberTable(jvmtiEnv * env,jmethodID method,jint * entry_count_ptr,jvmtiLineNumberEntry ** table_ptr)436 jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
437                                           jmethodID method,
438                                           jint* entry_count_ptr,
439                                           jvmtiLineNumberEntry** table_ptr) {
440   if (method == nullptr) {
441     return ERR(NULL_POINTER);
442   }
443   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
444   DCHECK(!art_method->IsRuntimeMethod());
445 
446   art::CodeItemDebugInfoAccessor accessor;
447   const art::DexFile* dex_file;
448   {
449     art::ScopedObjectAccess soa(art::Thread::Current());
450 
451     if (art_method->IsProxyMethod()) {
452       return ERR(ABSENT_INFORMATION);
453     }
454     if (art_method->IsNative()) {
455       return ERR(NATIVE_METHOD);
456     }
457     if (entry_count_ptr == nullptr || table_ptr == nullptr) {
458       return ERR(NULL_POINTER);
459     }
460 
461     accessor = art::CodeItemDebugInfoAccessor(art_method->DexInstructionDebugInfo());
462     dex_file = art_method->GetDexFile();
463     DCHECK(accessor.HasCodeItem()) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
464   }
465 
466   std::vector<jvmtiLineNumberEntry> context;
467   bool success = accessor.DecodeDebugPositionInfo([&](const art::DexFile::PositionInfo& entry) {
468     context.push_back({static_cast<jlocation>(entry.address_), static_cast<jint>(entry.line_)});
469     return false;
470   });
471   if (!success) {
472     return ERR(ABSENT_INFORMATION);
473   }
474 
475   unsigned char* data;
476   jlong mem_size = context.size() * sizeof(jvmtiLineNumberEntry);
477   jvmtiError alloc_error = env->Allocate(mem_size, &data);
478   if (alloc_error != ERR(NONE)) {
479     return alloc_error;
480   }
481   *table_ptr = reinterpret_cast<jvmtiLineNumberEntry*>(data);
482   memcpy(*table_ptr, context.data(), mem_size);
483   *entry_count_ptr = static_cast<jint>(context.size());
484 
485   return ERR(NONE);
486 }
487 
488 template <typename T>
IsMethodT(jvmtiEnv * env ATTRIBUTE_UNUSED,jmethodID method,T test,jboolean * is_t_ptr)489 static jvmtiError IsMethodT(jvmtiEnv* env ATTRIBUTE_UNUSED,
490                             jmethodID method,
491                             T test,
492                             jboolean* is_t_ptr) {
493   if (method == nullptr) {
494     return ERR(INVALID_METHODID);
495   }
496   if (is_t_ptr == nullptr) {
497     return ERR(NULL_POINTER);
498   }
499 
500   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
501   *is_t_ptr = test(art_method) ? JNI_TRUE : JNI_FALSE;
502 
503   return ERR(NONE);
504 }
505 
IsMethodNative(jvmtiEnv * env,jmethodID m,jboolean * is_native_ptr)506 jvmtiError MethodUtil::IsMethodNative(jvmtiEnv* env, jmethodID m, jboolean* is_native_ptr) {
507   auto test = [](art::ArtMethod* method) {
508     return method->IsNative();
509   };
510   return IsMethodT(env, m, test, is_native_ptr);
511 }
512 
IsMethodObsolete(jvmtiEnv * env,jmethodID m,jboolean * is_obsolete_ptr)513 jvmtiError MethodUtil::IsMethodObsolete(jvmtiEnv* env, jmethodID m, jboolean* is_obsolete_ptr) {
514   auto test = [](art::ArtMethod* method) {
515     return method->IsObsolete();
516   };
517   return IsMethodT(env, m, test, is_obsolete_ptr);
518 }
519 
IsMethodSynthetic(jvmtiEnv * env,jmethodID m,jboolean * is_synthetic_ptr)520 jvmtiError MethodUtil::IsMethodSynthetic(jvmtiEnv* env, jmethodID m, jboolean* is_synthetic_ptr) {
521   auto test = [](art::ArtMethod* method) {
522     return method->IsSynthetic();
523   };
524   return IsMethodT(env, m, test, is_synthetic_ptr);
525 }
526 
527 class CommonLocalVariableClosure : public art::Closure {
528  public:
CommonLocalVariableClosure(jint depth,jint slot)529   CommonLocalVariableClosure(jint depth, jint slot)
530       : result_(ERR(INTERNAL)), depth_(depth), slot_(slot) {}
531 
Run(art::Thread * self)532   void Run(art::Thread* self) override REQUIRES(art::Locks::mutator_lock_) {
533     art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
534     bool needs_instrument;
535     {
536       art::ScopedAssertNoThreadSuspension sants("CommonLocalVariableClosure::Run");
537       std::unique_ptr<art::Context> context(art::Context::Create());
538       FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
539       visitor.WalkStack();
540       if (!visitor.FoundFrame()) {
541         // Must have been a bad depth.
542         result_ = ERR(NO_MORE_FRAMES);
543         return;
544       }
545       art::ArtMethod* method = visitor.GetMethod();
546       // Native and 'art' proxy methods don't have registers.
547       if (method->IsNative() || method->IsProxyMethod()) {
548         // TODO It might be useful to fake up support for get at least on proxy frames.
549         result_ = ERR(OPAQUE_FRAME);
550         return;
551       } else if (method->DexInstructionData().RegistersSize() <= slot_) {
552         result_ = ERR(INVALID_SLOT);
553         return;
554       }
555       needs_instrument = !visitor.IsShadowFrame();
556       uint32_t pc = visitor.GetDexPc(/*abort_on_failure=*/false);
557       if (pc == art::dex::kDexNoIndex) {
558         // Cannot figure out current PC.
559         result_ = ERR(OPAQUE_FRAME);
560         return;
561       }
562       std::string descriptor;
563       art::Primitive::Type slot_type = art::Primitive::kPrimVoid;
564       jvmtiError err = GetSlotType(method, pc, &descriptor, &slot_type);
565       if (err != OK) {
566         result_ = err;
567         return;
568       }
569 
570       err = GetTypeError(method, slot_type, descriptor);
571       if (err != OK) {
572         result_ = err;
573         return;
574       }
575       result_ = Execute(method, visitor);
576     }
577     if (needs_instrument) {
578       DeoptManager::Get()->DeoptimizeThread(self);
579     }
580   }
581 
GetResult()582   virtual jvmtiError GetResult() {
583     return result_;
584   }
585 
586  protected:
587   virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
588       REQUIRES_SHARED(art::Locks::mutator_lock_) = 0;
589   virtual jvmtiError GetTypeError(art::ArtMethod* method,
590                                   art::Primitive::Type type,
591                                   const std::string& descriptor)
592       REQUIRES_SHARED(art::Locks::mutator_lock_)  = 0;
593 
GetSlotType(art::ArtMethod * method,uint32_t dex_pc,std::string * descriptor,art::Primitive::Type * type)594   jvmtiError GetSlotType(art::ArtMethod* method,
595                          uint32_t dex_pc,
596                          /*out*/std::string* descriptor,
597                          /*out*/art::Primitive::Type* type)
598       REQUIRES(art::Locks::mutator_lock_) {
599     const art::DexFile* dex_file = method->GetDexFile();
600     if (dex_file == nullptr) {
601       return ERR(OPAQUE_FRAME);
602     }
603     art::CodeItemDebugInfoAccessor accessor(method->DexInstructionDebugInfo());
604     if (!accessor.HasCodeItem()) {
605       return ERR(OPAQUE_FRAME);
606     }
607     bool found = false;
608     *type = art::Primitive::kPrimVoid;
609     descriptor->clear();
610     auto visitor = [&](const art::DexFile::LocalInfo& entry) {
611       if (!found &&
612           entry.start_address_ <= dex_pc &&
613           entry.end_address_ > dex_pc &&
614           entry.reg_ == slot_) {
615         found = true;
616         *type = art::Primitive::GetType(entry.descriptor_[0]);
617         *descriptor = entry.descriptor_;
618       }
619     };
620     if (!accessor.DecodeDebugLocalInfo(method->IsStatic(), method->GetDexMethodIndex(), visitor) ||
621         !found) {
622       // Something went wrong with decoding the debug information. It might as well not be there.
623       return ERR(INVALID_SLOT);
624     }
625     return OK;
626   }
627 
628   jvmtiError result_;
629   jint depth_;
630   jint slot_;
631 };
632 
633 class GetLocalVariableClosure : public CommonLocalVariableClosure {
634  public:
GetLocalVariableClosure(jint depth,jint slot,art::Primitive::Type type,jvalue * val)635   GetLocalVariableClosure(jint depth,
636                           jint slot,
637                           art::Primitive::Type type,
638                           jvalue* val)
639       : CommonLocalVariableClosure(depth, slot),
640         type_(type),
641         val_(val),
642         obj_val_(nullptr) {}
643 
GetResult()644   jvmtiError GetResult() override REQUIRES_SHARED(art::Locks::mutator_lock_) {
645     if (result_ == OK && type_ == art::Primitive::kPrimNot) {
646       if (obj_val_ == nullptr) {
647         val_->l = nullptr;
648       } else {
649         art::JNIEnvExt* jni = art::Thread::Current()->GetJniEnv();
650         val_->l = static_cast<JNIEnv*>(jni)->NewLocalRef(obj_val_);
651         jni->DeleteGlobalRef(obj_val_);
652         obj_val_ = nullptr;
653       }
654     }
655     return CommonLocalVariableClosure::GetResult();
656   }
657 
658  protected:
GetTypeError(art::ArtMethod * method ATTRIBUTE_UNUSED,art::Primitive::Type slot_type,const std::string & descriptor ATTRIBUTE_UNUSED)659   jvmtiError GetTypeError(art::ArtMethod* method ATTRIBUTE_UNUSED,
660                           art::Primitive::Type slot_type,
661                           const std::string& descriptor ATTRIBUTE_UNUSED)
662       override REQUIRES_SHARED(art::Locks::mutator_lock_) {
663     switch (slot_type) {
664       case art::Primitive::kPrimByte:
665       case art::Primitive::kPrimChar:
666       case art::Primitive::kPrimInt:
667       case art::Primitive::kPrimShort:
668       case art::Primitive::kPrimBoolean:
669         return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
670       case art::Primitive::kPrimLong:
671       case art::Primitive::kPrimFloat:
672       case art::Primitive::kPrimDouble:
673       case art::Primitive::kPrimNot:
674         return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
675       case art::Primitive::kPrimVoid:
676         LOG(FATAL) << "Unexpected primitive type " << slot_type;
677         UNREACHABLE();
678     }
679   }
680 
Execute(art::ArtMethod * method,art::StackVisitor & visitor)681   jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
682       override REQUIRES_SHARED(art::Locks::mutator_lock_) {
683     switch (type_) {
684       case art::Primitive::kPrimNot: {
685         uint32_t ptr_val;
686         if (!visitor.GetVReg(method,
687                              static_cast<uint16_t>(slot_),
688                              art::kReferenceVReg,
689                              &ptr_val)) {
690           return ERR(OPAQUE_FRAME);
691         }
692         art::JNIEnvExt* jni = art::Thread::Current()->GetJniEnv();
693         art::ObjPtr<art::mirror::Object> obj(reinterpret_cast<art::mirror::Object*>(ptr_val));
694         ScopedLocalRef<jobject> local(
695             jni, obj.IsNull() ? nullptr : jni->AddLocalReference<jobject>(obj));
696         obj_val_ = jni->NewGlobalRef(local.get());
697         break;
698       }
699       case art::Primitive::kPrimInt:
700       case art::Primitive::kPrimFloat: {
701         if (!visitor.GetVReg(method,
702                              static_cast<uint16_t>(slot_),
703                              type_ == art::Primitive::kPrimFloat ? art::kFloatVReg : art::kIntVReg,
704                              reinterpret_cast<uint32_t*>(&val_->i))) {
705           return ERR(OPAQUE_FRAME);
706         }
707         break;
708       }
709       case art::Primitive::kPrimDouble:
710       case art::Primitive::kPrimLong: {
711         auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
712         auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
713         if (!visitor.GetVRegPair(method,
714                                  static_cast<uint16_t>(slot_),
715                                  lo_type,
716                                  high_type,
717                                  reinterpret_cast<uint64_t*>(&val_->j))) {
718           return ERR(OPAQUE_FRAME);
719         }
720         break;
721       }
722       default: {
723         LOG(FATAL) << "unexpected register type " << type_;
724         UNREACHABLE();
725       }
726     }
727     return OK;
728   }
729 
730  private:
731   art::Primitive::Type type_;
732   jvalue* val_;
733   // A global reference to the return value. We use the global reference to safely transfer the
734   // value between threads.
735   jobject obj_val_;
736 };
737 
GetLocalVariableGeneric(jvmtiEnv * env ATTRIBUTE_UNUSED,jthread thread,jint depth,jint slot,art::Primitive::Type type,jvalue * val)738 jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
739                                                jthread thread,
740                                                jint depth,
741                                                jint slot,
742                                                art::Primitive::Type type,
743                                                jvalue* val) {
744   if (depth < 0) {
745     return ERR(ILLEGAL_ARGUMENT);
746   }
747   art::Thread* self = art::Thread::Current();
748   art::ScopedObjectAccess soa(self);
749   art::Locks::thread_list_lock_->ExclusiveLock(self);
750   art::Thread* target = nullptr;
751   jvmtiError err = ERR(INTERNAL);
752   if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
753     art::Locks::thread_list_lock_->ExclusiveUnlock(self);
754     return err;
755   }
756   GetLocalVariableClosure c(depth, slot, type, val);
757   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
758   if (!target->RequestSynchronousCheckpoint(&c)) {
759     return ERR(THREAD_NOT_ALIVE);
760   } else {
761     return c.GetResult();
762   }
763 }
764 
765 class SetLocalVariableClosure : public CommonLocalVariableClosure {
766  public:
SetLocalVariableClosure(art::Thread * caller,jint depth,jint slot,art::Primitive::Type type,jvalue val)767   SetLocalVariableClosure(art::Thread* caller,
768                           jint depth,
769                           jint slot,
770                           art::Primitive::Type type,
771                           jvalue val)
772       : CommonLocalVariableClosure(depth, slot), caller_(caller), type_(type), val_(val) {}
773 
774  protected:
GetTypeError(art::ArtMethod * method,art::Primitive::Type slot_type,const std::string & descriptor)775   jvmtiError GetTypeError(art::ArtMethod* method,
776                           art::Primitive::Type slot_type,
777                           const std::string& descriptor)
778       override REQUIRES_SHARED(art::Locks::mutator_lock_) {
779     switch (slot_type) {
780       case art::Primitive::kPrimNot: {
781         if (type_ != art::Primitive::kPrimNot) {
782           return ERR(TYPE_MISMATCH);
783         } else if (val_.l == nullptr) {
784           return OK;
785         } else {
786           art::ClassLinker* cl = art::Runtime::Current()->GetClassLinker();
787           art::ObjPtr<art::mirror::Class> set_class =
788               caller_->DecodeJObject(val_.l)->GetClass();
789           art::ObjPtr<art::mirror::ClassLoader> loader =
790               method->GetDeclaringClass()->GetClassLoader();
791           art::ObjPtr<art::mirror::Class> slot_class =
792               cl->LookupClass(caller_, descriptor.c_str(), loader);
793           DCHECK(!slot_class.IsNull());
794           return slot_class->IsAssignableFrom(set_class) ? OK : ERR(TYPE_MISMATCH);
795         }
796       }
797       case art::Primitive::kPrimByte:
798       case art::Primitive::kPrimChar:
799       case art::Primitive::kPrimInt:
800       case art::Primitive::kPrimShort:
801       case art::Primitive::kPrimBoolean:
802         return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
803       case art::Primitive::kPrimLong:
804       case art::Primitive::kPrimFloat:
805       case art::Primitive::kPrimDouble:
806         return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
807       case art::Primitive::kPrimVoid:
808         LOG(FATAL) << "Unexpected primitive type " << slot_type;
809         UNREACHABLE();
810     }
811   }
812 
Execute(art::ArtMethod * method,art::StackVisitor & visitor)813   jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
814       override REQUIRES_SHARED(art::Locks::mutator_lock_) {
815     switch (type_) {
816       case art::Primitive::kPrimNot: {
817         uint32_t ptr_val;
818         art::ObjPtr<art::mirror::Object> obj(caller_->DecodeJObject(val_.l));
819         ptr_val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(obj.Ptr()));
820         if (!visitor.SetVReg(method,
821                              static_cast<uint16_t>(slot_),
822                              ptr_val,
823                              art::kReferenceVReg)) {
824           return ERR(OPAQUE_FRAME);
825         }
826         break;
827       }
828       case art::Primitive::kPrimInt:
829       case art::Primitive::kPrimFloat: {
830         if (!visitor.SetVReg(method,
831                              static_cast<uint16_t>(slot_),
832                              static_cast<uint32_t>(val_.i),
833                              type_ == art::Primitive::kPrimFloat ? art::kFloatVReg
834                                                                  : art::kIntVReg)) {
835           return ERR(OPAQUE_FRAME);
836         }
837         break;
838       }
839       case art::Primitive::kPrimDouble:
840       case art::Primitive::kPrimLong: {
841         auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
842         auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
843         if (!visitor.SetVRegPair(method,
844                                  static_cast<uint16_t>(slot_),
845                                  static_cast<uint64_t>(val_.j),
846                                  lo_type,
847                                  high_type)) {
848           return ERR(OPAQUE_FRAME);
849         }
850         break;
851       }
852       default: {
853         LOG(FATAL) << "unexpected register type " << type_;
854         UNREACHABLE();
855       }
856     }
857     return OK;
858   }
859 
860  private:
861   art::Thread* caller_;
862   art::Primitive::Type type_;
863   jvalue val_;
864 };
865 
SetLocalVariableGeneric(jvmtiEnv * env ATTRIBUTE_UNUSED,jthread thread,jint depth,jint slot,art::Primitive::Type type,jvalue val)866 jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
867                                                jthread thread,
868                                                jint depth,
869                                                jint slot,
870                                                art::Primitive::Type type,
871                                                jvalue val) {
872   if (depth < 0) {
873     return ERR(ILLEGAL_ARGUMENT);
874   }
875   // Make sure that we know not to do any OSR anymore.
876   // TODO We should really keep track of this at the Frame granularity.
877   DeoptManager::Get()->SetLocalsUpdated();
878   art::Thread* self = art::Thread::Current();
879   art::ScopedObjectAccess soa(self);
880   art::Locks::thread_list_lock_->ExclusiveLock(self);
881   art::Thread* target = nullptr;
882   jvmtiError err = ERR(INTERNAL);
883   if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
884     art::Locks::thread_list_lock_->ExclusiveUnlock(self);
885     return err;
886   }
887   SetLocalVariableClosure c(self, depth, slot, type, val);
888   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
889   if (!target->RequestSynchronousCheckpoint(&c)) {
890     return ERR(THREAD_NOT_ALIVE);
891   } else {
892     return c.GetResult();
893   }
894 }
895 
896 class GetLocalInstanceClosure : public art::Closure {
897  public:
GetLocalInstanceClosure(jint depth)898   explicit GetLocalInstanceClosure(jint depth)
899       : result_(ERR(INTERNAL)),
900         depth_(depth),
901         val_(nullptr) {}
902 
Run(art::Thread * self)903   void Run(art::Thread* self) override REQUIRES(art::Locks::mutator_lock_) {
904     art::ScopedAssertNoThreadSuspension sants("GetLocalInstanceClosure::Run");
905     art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
906     std::unique_ptr<art::Context> context(art::Context::Create());
907     FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
908     visitor.WalkStack();
909     if (!visitor.FoundFrame()) {
910       // Must have been a bad depth.
911       result_ = ERR(NO_MORE_FRAMES);
912       return;
913     }
914     result_ = OK;
915     val_ = art::GcRoot<art::mirror::Object>(visitor.GetThisObject());
916   }
917 
GetResult(jobject * data_out)918   jvmtiError GetResult(jobject* data_out) REQUIRES_SHARED(art::Locks::mutator_lock_) {
919     if (result_ == OK) {
920       *data_out = val_.IsNull()
921           ? nullptr
922           : art::Thread::Current()->GetJniEnv()->AddLocalReference<jobject>(val_.Read());
923     }
924     return result_;
925   }
926 
927  private:
928   jvmtiError result_;
929   jint depth_;
930   art::GcRoot<art::mirror::Object> val_;
931 };
932 
GetLocalInstance(jvmtiEnv * env ATTRIBUTE_UNUSED,jthread thread,jint depth,jobject * data)933 jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED,
934                                         jthread thread,
935                                         jint depth,
936                                         jobject* data) {
937   if (depth < 0) {
938     return ERR(ILLEGAL_ARGUMENT);
939   }
940   art::Thread* self = art::Thread::Current();
941   art::ScopedObjectAccess soa(self);
942   art::Locks::thread_list_lock_->ExclusiveLock(self);
943   art::Thread* target = nullptr;
944   jvmtiError err = ERR(INTERNAL);
945   if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
946     art::Locks::thread_list_lock_->ExclusiveUnlock(self);
947     return err;
948   }
949   art::ScopedAssertNoThreadSuspension sants("Performing GetLocalInstance");
950   GetLocalInstanceClosure c(depth);
951   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.  We
952   // need to avoid suspending as we wait for the checkpoint to occur since we are (potentially)
953   // transfering a GcRoot across threads.
954   if (!target->RequestSynchronousCheckpoint(&c, art::ThreadState::kRunnable)) {
955     return ERR(THREAD_NOT_ALIVE);
956   } else {
957     return c.GetResult(data);
958   }
959 }
960 
961 #define FOR_JVMTI_JVALUE_TYPES(fn) \
962     fn(jint, art::Primitive::kPrimInt, i) \
963     fn(jlong, art::Primitive::kPrimLong, j) \
964     fn(jfloat, art::Primitive::kPrimFloat, f) \
965     fn(jdouble, art::Primitive::kPrimDouble, d) \
966     fn(jobject, art::Primitive::kPrimNot, l)
967 
968 namespace impl {
969 
970 template<typename T> void WriteJvalue(T, jvalue*);
971 template<typename T> void ReadJvalue(jvalue, T*);
972 template<typename T> art::Primitive::Type GetJNIType();
973 
974 #define JNI_TYPE_CHAR(type, prim, id) \
975 template<> art::Primitive::Type GetJNIType<type>() { \
976   return prim; \
977 }
978 
979 FOR_JVMTI_JVALUE_TYPES(JNI_TYPE_CHAR);
980 
981 #undef JNI_TYPE_CHAR
982 
983 #define RW_JVALUE(srctype, prim, id) \
984     template<> void ReadJvalue<srctype>(jvalue in, std::add_pointer<srctype>::type out) { \
985       *out = in.id; \
986     } \
987     template<> void WriteJvalue<srctype>(srctype in, jvalue* out) { \
988       out->id = in; \
989     }
990 
991 FOR_JVMTI_JVALUE_TYPES(RW_JVALUE);
992 
993 #undef RW_JVALUE
994 
995 }  // namespace impl
996 
997 template<typename T>
SetLocalVariable(jvmtiEnv * env,jthread thread,jint depth,jint slot,T data)998 jvmtiError MethodUtil::SetLocalVariable(jvmtiEnv* env,
999                                         jthread thread,
1000                                         jint depth,
1001                                         jint slot,
1002                                         T data) {
1003   jvalue v = {.j = 0};
1004   art::Primitive::Type type = impl::GetJNIType<T>();
1005   impl::WriteJvalue(data, &v);
1006   return SetLocalVariableGeneric(env, thread, depth, slot, type, v);
1007 }
1008 
1009 template<typename T>
GetLocalVariable(jvmtiEnv * env,jthread thread,jint depth,jint slot,T * data)1010 jvmtiError MethodUtil::GetLocalVariable(jvmtiEnv* env,
1011                                         jthread thread,
1012                                         jint depth,
1013                                         jint slot,
1014                                         T* data) {
1015   if (data == nullptr) {
1016     return ERR(NULL_POINTER);
1017   }
1018   jvalue v = {.j = 0};
1019   art::Primitive::Type type = impl::GetJNIType<T>();
1020   jvmtiError err = GetLocalVariableGeneric(env, thread, depth, slot, type, &v);
1021   if (err != OK) {
1022     return err;
1023   } else {
1024     impl::ReadJvalue(v, data);
1025     return OK;
1026   }
1027 }
1028 
1029 #define GET_SET_LV(srctype, prim, id) \
1030     template jvmtiError MethodUtil::GetLocalVariable<srctype>(jvmtiEnv*, \
1031                                                               jthread, \
1032                                                               jint, \
1033                                                               jint, \
1034                                                               std::add_pointer<srctype>::type); \
1035     template jvmtiError MethodUtil::SetLocalVariable<srctype>(jvmtiEnv*, \
1036                                                               jthread, \
1037                                                               jint, \
1038                                                               jint, \
1039                                                               srctype);
1040 
1041 FOR_JVMTI_JVALUE_TYPES(GET_SET_LV);
1042 
1043 #undef GET_SET_LV
1044 
1045 #undef FOR_JVMTI_JVALUE_TYPES
1046 
1047 }  // namespace openjdkjvmti
1048