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