blob: 05943e70a4aaa01895068af95e18cf94daa97a95 [file] [log] [blame]
Andreas Gampe3c252f02016-10-27 18:25:17 -07001/* Copyright (C) 2016 The Android Open Source Project
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This file implements interfaces from the file jvmti.h. This implementation
5 * is licensed under the same terms as the file jvmti.h. The
6 * copyright and license information for the file jvmti.h follows.
7 *
8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10 *
11 * This code is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 only, as
13 * published by the Free Software Foundation. Oracle designates this
14 * particular file as subject to the "Classpath" exception as provided
15 * by Oracle in the LICENSE file that accompanied this code.
16 *
17 * This code is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * version 2 for more details (a copy is included in the LICENSE file that
21 * accompanied this code).
22 *
23 * You should have received a copy of the GNU General Public License version
24 * 2 along with this work; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28 * or visit www.oracle.com if you need additional information or have any
29 * questions.
30 */
31
32#include "ti_method.h"
33
Andreas Gampe49fc60e2017-08-24 13:19:59 -070034#include <type_traits>
35
Andreas Gampe3c252f02016-10-27 18:25:17 -070036#include "art_jvmti.h"
37#include "art_method-inl.h"
38#include "base/enums.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070039#include "base/mutex-inl.h"
Andreas Gampe27dfa052017-02-16 15:04:36 -080040#include "dex_file_annotations.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070041#include "events-inl.h"
Alex Light0a5ec3d2017-07-25 16:50:26 -070042#include "jit/jit.h"
Andreas Gampe13b27842016-11-07 16:48:23 -080043#include "jni_internal.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070044#include "mirror/class-inl.h"
45#include "mirror/class_loader.h"
46#include "mirror/object-inl.h"
Andreas Gampe27dfa052017-02-16 15:04:36 -080047#include "mirror/object_array-inl.h"
Andreas Gampe36bcd4f2016-10-28 18:07:18 -070048#include "modifiers.h"
Steven Morelande431e272017-07-18 16:53:49 -070049#include "nativehelper/ScopedLocalRef.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070050#include "runtime_callbacks.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070051#include "scoped_thread_state_change-inl.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070052#include "stack.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070053#include "thread-current-inl.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070054#include "thread_list.h"
Alex Lighte814f9d2017-07-31 16:14:39 -070055#include "ti_stack.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070056#include "ti_thread.h"
Alex Light0af8cde2017-04-20 13:35:05 -070057#include "ti_phase.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070058
59namespace openjdkjvmti {
60
Alex Lightd78ddec2017-04-18 15:20:38 -070061struct TiMethodCallback : public art::MethodCallback {
62 void RegisterNativeMethod(art::ArtMethod* method,
63 const void* cur_method,
64 /*out*/void** new_method)
65 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
66 if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kNativeMethodBind)) {
67 art::Thread* thread = art::Thread::Current();
Alex Light0af8cde2017-04-20 13:35:05 -070068 art::JNIEnvExt* jnienv = thread->GetJniEnv();
Alex Lightd78ddec2017-04-18 15:20:38 -070069 ScopedLocalRef<jthread> thread_jni(
Alex Light0af8cde2017-04-20 13:35:05 -070070 jnienv, PhaseUtil::IsLivePhase() ? jnienv->AddLocalReference<jthread>(thread->GetPeer())
71 : nullptr);
Alex Lightd78ddec2017-04-18 15:20:38 -070072 art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
73 event_handler->DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(
74 thread,
Alex Light0af8cde2017-04-20 13:35:05 -070075 static_cast<JNIEnv*>(jnienv),
Alex Lightd78ddec2017-04-18 15:20:38 -070076 thread_jni.get(),
77 art::jni::EncodeArtMethod(method),
78 const_cast<void*>(cur_method),
79 new_method);
80 }
81 }
82
83 EventHandler* event_handler = nullptr;
84};
85
86TiMethodCallback gMethodCallback;
87
88void MethodUtil::Register(EventHandler* handler) {
89 gMethodCallback.event_handler = handler;
90 art::ScopedThreadStateChange stsc(art::Thread::Current(),
91 art::ThreadState::kWaitingForDebuggerToAttach);
92 art::ScopedSuspendAll ssa("Add method callback");
93 art::Runtime::Current()->GetRuntimeCallbacks()->AddMethodCallback(&gMethodCallback);
94}
95
96void MethodUtil::Unregister() {
97 art::ScopedThreadStateChange stsc(art::Thread::Current(),
98 art::ThreadState::kWaitingForDebuggerToAttach);
99 art::ScopedSuspendAll ssa("Remove method callback");
100 art::Runtime* runtime = art::Runtime::Current();
101 runtime->GetRuntimeCallbacks()->RemoveMethodCallback(&gMethodCallback);
102}
103
Alex Light4c174282017-07-05 10:18:18 -0700104jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
105 jmethodID method,
106 jint* size_ptr,
107 unsigned char** bytecode_ptr) {
108 if (method == nullptr) {
109 return ERR(INVALID_METHODID);
110 }
111 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
112
113 if (art_method->IsNative()) {
114 return ERR(NATIVE_METHOD);
115 }
116
117 if (size_ptr == nullptr || bytecode_ptr == nullptr) {
118 return ERR(NULL_POINTER);
119 }
120
121 art::ScopedObjectAccess soa(art::Thread::Current());
122 const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
123 if (code_item == nullptr) {
124 *size_ptr = 0;
125 *bytecode_ptr = nullptr;
126 return OK;
127 }
128 // 2 bytes per instruction for dex code.
129 *size_ptr = code_item->insns_size_in_code_units_ * 2;
130 jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr);
131 if (err != OK) {
132 return err;
133 }
134 memcpy(*bytecode_ptr, code_item->insns_, *size_ptr);
135 return OK;
136}
137
Andreas Gampef71832e2017-01-09 11:38:04 -0800138jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
139 jmethodID method,
140 jint* size_ptr) {
141 if (method == nullptr) {
142 return ERR(INVALID_METHODID);
143 }
144 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
145
146 if (art_method->IsNative()) {
147 return ERR(NATIVE_METHOD);
148 }
149
150 if (size_ptr == nullptr) {
151 return ERR(NULL_POINTER);
152 }
153
154 art::ScopedObjectAccess soa(art::Thread::Current());
155 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
Andreas Gampee1f79b62017-04-12 21:11:28 -0700156 // Use the shorty.
157 art::ArtMethod* base_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
158 size_t arg_count = art::ArtMethod::NumArgRegisters(base_method->GetShorty());
159 if (!base_method->IsStatic()) {
160 arg_count++;
161 }
162 *size_ptr = static_cast<jint>(arg_count);
Andreas Gampef71832e2017-01-09 11:38:04 -0800163 return ERR(NONE);
164 }
165
166 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
167 *size_ptr = art_method->GetCodeItem()->ins_size_;
168
169 return ERR(NONE);
170}
171
Alex Lightce68cc62017-07-26 10:30:38 -0700172jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
173 jmethodID method,
174 jint* entry_count_ptr,
175 jvmtiLocalVariableEntry** table_ptr) {
176 if (method == nullptr) {
177 return ERR(INVALID_METHODID);
178 }
179 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
180
181 if (art_method->IsNative()) {
182 return ERR(NATIVE_METHOD);
183 }
184
185 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
186 return ERR(NULL_POINTER);
187 }
188
189 art::ScopedObjectAccess soa(art::Thread::Current());
190 const art::DexFile* dex_file = art_method->GetDexFile();
191 const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
192 // TODO code_item == nullptr means that the method is abstract (or native, but we check that
193 // earlier). We should check what is returned by the RI in this situation since it's not clear
194 // what the appropriate return value is from the spec.
195 if (dex_file == nullptr || code_item == nullptr) {
196 return ERR(ABSENT_INFORMATION);
197 }
198
199 struct LocalVariableContext {
200 explicit LocalVariableContext(jvmtiEnv* jenv) : env_(jenv), variables_(), err_(OK) {}
201
202 static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
203 reinterpret_cast<LocalVariableContext*>(raw_ctx)->Insert(entry);
204 }
205
206 void Insert(const art::DexFile::LocalInfo& entry) {
207 if (err_ != OK) {
208 return;
209 }
210 JvmtiUniquePtr<char[]> name_str = CopyString(env_, entry.name_, &err_);
211 if (err_ != OK) {
212 return;
213 }
214 JvmtiUniquePtr<char[]> sig_str = CopyString(env_, entry.descriptor_, &err_);
215 if (err_ != OK) {
216 return;
217 }
218 JvmtiUniquePtr<char[]> generic_sig_str = CopyString(env_, entry.signature_, &err_);
219 if (err_ != OK) {
220 return;
221 }
222 variables_.push_back({
223 .start_location = static_cast<jlocation>(entry.start_address_),
224 .length = static_cast<jint>(entry.end_address_ - entry.start_address_),
225 .name = name_str.release(),
226 .signature = sig_str.release(),
227 .generic_signature = generic_sig_str.release(),
228 .slot = entry.reg_,
229 });
230 }
231
232 jvmtiError Release(jint* out_entry_count_ptr, jvmtiLocalVariableEntry** out_table_ptr) {
233 jlong table_size = sizeof(jvmtiLocalVariableEntry) * variables_.size();
234 if (err_ != OK ||
235 (err_ = env_->Allocate(table_size,
236 reinterpret_cast<unsigned char**>(out_table_ptr))) != OK) {
237 Cleanup();
238 return err_;
239 } else {
240 *out_entry_count_ptr = variables_.size();
241 memcpy(*out_table_ptr, variables_.data(), table_size);
242 return OK;
243 }
244 }
245
246 void Cleanup() {
247 for (jvmtiLocalVariableEntry& e : variables_) {
248 env_->Deallocate(reinterpret_cast<unsigned char*>(e.name));
249 env_->Deallocate(reinterpret_cast<unsigned char*>(e.signature));
250 env_->Deallocate(reinterpret_cast<unsigned char*>(e.generic_signature));
251 }
252 }
253
254 jvmtiEnv* env_;
255 std::vector<jvmtiLocalVariableEntry> variables_;
256 jvmtiError err_;
257 };
258
259 LocalVariableContext context(env);
260 if (!dex_file->DecodeDebugLocalInfo(code_item,
261 art_method->IsStatic(),
262 art_method->GetDexMethodIndex(),
263 LocalVariableContext::Callback,
264 &context)) {
265 // Something went wrong with decoding the debug information. It might as well not be there.
266 return ERR(ABSENT_INFORMATION);
267 } else {
268 return context.Release(entry_count_ptr, table_ptr);
269 }
270}
271
Andreas Gampef71832e2017-01-09 11:38:04 -0800272jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
273 jmethodID method,
274 jint* max_ptr) {
275 if (method == nullptr) {
276 return ERR(INVALID_METHODID);
277 }
278 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
279
280 if (art_method->IsNative()) {
281 return ERR(NATIVE_METHOD);
282 }
283
284 if (max_ptr == nullptr) {
285 return ERR(NULL_POINTER);
286 }
287
288 art::ScopedObjectAccess soa(art::Thread::Current());
289 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
290 // This isn't specified as an error case, so return 0.
291 *max_ptr = 0;
292 return ERR(NONE);
293 }
294
295 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
296 *max_ptr = art_method->GetCodeItem()->registers_size_;
297
298 return ERR(NONE);
299}
300
Andreas Gampe3c252f02016-10-27 18:25:17 -0700301jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
302 jmethodID method,
303 char** name_ptr,
304 char** signature_ptr,
305 char** generic_ptr) {
306 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe13b27842016-11-07 16:48:23 -0800307 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe3c252f02016-10-27 18:25:17 -0700308 art_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
309
Andreas Gampe54711412017-02-21 12:41:43 -0800310 JvmtiUniquePtr<char[]> name_copy;
Andreas Gampe3c252f02016-10-27 18:25:17 -0700311 if (name_ptr != nullptr) {
312 const char* method_name = art_method->GetName();
313 if (method_name == nullptr) {
314 method_name = "<error>";
315 }
Andreas Gampe54711412017-02-21 12:41:43 -0800316 jvmtiError ret;
317 name_copy = CopyString(env, method_name, &ret);
318 if (name_copy == nullptr) {
Andreas Gampe3c252f02016-10-27 18:25:17 -0700319 return ret;
320 }
Andreas Gampe54711412017-02-21 12:41:43 -0800321 *name_ptr = name_copy.get();
Andreas Gampe3c252f02016-10-27 18:25:17 -0700322 }
323
Andreas Gampe54711412017-02-21 12:41:43 -0800324 JvmtiUniquePtr<char[]> signature_copy;
Andreas Gampe3c252f02016-10-27 18:25:17 -0700325 if (signature_ptr != nullptr) {
326 const art::Signature sig = art_method->GetSignature();
327 std::string str = sig.ToString();
Andreas Gampe54711412017-02-21 12:41:43 -0800328 jvmtiError ret;
329 signature_copy = CopyString(env, str.c_str(), &ret);
330 if (signature_copy == nullptr) {
Andreas Gampe3c252f02016-10-27 18:25:17 -0700331 return ret;
332 }
Andreas Gampe54711412017-02-21 12:41:43 -0800333 *signature_ptr = signature_copy.get();
Andreas Gampe3c252f02016-10-27 18:25:17 -0700334 }
335
Andreas Gampe862bdd82016-11-18 13:31:13 -0800336 if (generic_ptr != nullptr) {
337 *generic_ptr = nullptr;
Andreas Gampe27dfa052017-02-16 15:04:36 -0800338 if (!art_method->GetDeclaringClass()->IsProxyClass()) {
339 art::mirror::ObjectArray<art::mirror::String>* str_array =
340 art::annotations::GetSignatureAnnotationForMethod(art_method);
341 if (str_array != nullptr) {
342 std::ostringstream oss;
343 for (int32_t i = 0; i != str_array->GetLength(); ++i) {
344 oss << str_array->Get(i)->ToModifiedUtf8();
345 }
346 std::string output_string = oss.str();
Andreas Gampe54711412017-02-21 12:41:43 -0800347 jvmtiError ret;
348 JvmtiUniquePtr<char[]> generic_copy = CopyString(env, output_string.c_str(), &ret);
349 if (generic_copy == nullptr) {
Andreas Gampe27dfa052017-02-16 15:04:36 -0800350 return ret;
351 }
Andreas Gampe54711412017-02-21 12:41:43 -0800352 *generic_ptr = generic_copy.release();
Andreas Gampe27dfa052017-02-16 15:04:36 -0800353 } else if (soa.Self()->IsExceptionPending()) {
354 // TODO: Should we report an error here?
355 soa.Self()->ClearException();
356 }
357 }
Andreas Gampe862bdd82016-11-18 13:31:13 -0800358 }
Andreas Gampe3c252f02016-10-27 18:25:17 -0700359
360 // Everything is fine, release the buffers.
361 name_copy.release();
362 signature_copy.release();
363
364 return ERR(NONE);
365}
366
Andreas Gampe368a2082016-10-28 17:33:13 -0700367jvmtiError MethodUtil::GetMethodDeclaringClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
368 jmethodID method,
369 jclass* declaring_class_ptr) {
370 if (declaring_class_ptr == nullptr) {
371 return ERR(NULL_POINTER);
372 }
373
Andreas Gampe13b27842016-11-07 16:48:23 -0800374 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe368a2082016-10-28 17:33:13 -0700375 // Note: No GetInterfaceMethodIfProxy, we want to actual class.
376
Andreas Gampe13b27842016-11-07 16:48:23 -0800377 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe368a2082016-10-28 17:33:13 -0700378 art::mirror::Class* klass = art_method->GetDeclaringClass();
379 *declaring_class_ptr = soa.AddLocalReference<jclass>(klass);
380
381 return ERR(NONE);
382}
383
Andreas Gampef71832e2017-01-09 11:38:04 -0800384jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
385 jmethodID method,
386 jlocation* start_location_ptr,
387 jlocation* end_location_ptr) {
388 if (method == nullptr) {
389 return ERR(INVALID_METHODID);
390 }
391 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
392
393 if (art_method->IsNative()) {
394 return ERR(NATIVE_METHOD);
395 }
396
397 if (start_location_ptr == nullptr || end_location_ptr == nullptr) {
398 return ERR(NULL_POINTER);
399 }
400
401 art::ScopedObjectAccess soa(art::Thread::Current());
402 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
Andreas Gampee1f79b62017-04-12 21:11:28 -0700403 // This isn't specified as an error case, so return -1/-1 as the RI does.
404 *start_location_ptr = -1;
405 *end_location_ptr = -1;
Andreas Gampef71832e2017-01-09 11:38:04 -0800406 return ERR(NONE);
407 }
408
409 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
410 *start_location_ptr = 0;
411 *end_location_ptr = art_method->GetCodeItem()->insns_size_in_code_units_ - 1;
412
413 return ERR(NONE);
414}
415
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700416jvmtiError MethodUtil::GetMethodModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
417 jmethodID method,
418 jint* modifiers_ptr) {
419 if (modifiers_ptr == nullptr) {
420 return ERR(NULL_POINTER);
421 }
422
Andreas Gampe13b27842016-11-07 16:48:23 -0800423 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700424 uint32_t modifiers = art_method->GetAccessFlags();
425
426 // Note: Keep this code in sync with Executable.fixMethodFlags.
427 if ((modifiers & art::kAccAbstract) != 0) {
428 modifiers &= ~art::kAccNative;
429 }
430 modifiers &= ~art::kAccSynchronized;
431 if ((modifiers & art::kAccDeclaredSynchronized) != 0) {
432 modifiers |= art::kAccSynchronized;
433 }
434 modifiers &= art::kAccJavaFlagsMask;
435
436 *modifiers_ptr = modifiers;
437 return ERR(NONE);
438}
439
Andreas Gampeda3e5612016-12-13 19:00:53 -0800440using LineNumberContext = std::vector<jvmtiLineNumberEntry>;
441
442static bool CollectLineNumbers(void* void_context, const art::DexFile::PositionInfo& entry) {
443 LineNumberContext* context = reinterpret_cast<LineNumberContext*>(void_context);
444 jvmtiLineNumberEntry jvmti_entry = { static_cast<jlocation>(entry.address_),
445 static_cast<jint>(entry.line_) };
446 context->push_back(jvmti_entry);
447 return false; // Collect all, no early exit.
448}
449
450jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
451 jmethodID method,
452 jint* entry_count_ptr,
453 jvmtiLineNumberEntry** table_ptr) {
454 if (method == nullptr) {
455 return ERR(NULL_POINTER);
456 }
457 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
458 DCHECK(!art_method->IsRuntimeMethod());
459
460 const art::DexFile::CodeItem* code_item;
461 const art::DexFile* dex_file;
462 {
463 art::ScopedObjectAccess soa(art::Thread::Current());
464
465 if (art_method->IsProxyMethod()) {
466 return ERR(ABSENT_INFORMATION);
467 }
468 if (art_method->IsNative()) {
469 return ERR(NATIVE_METHOD);
470 }
471 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
472 return ERR(NULL_POINTER);
473 }
474
475 code_item = art_method->GetCodeItem();
476 dex_file = art_method->GetDexFile();
477 DCHECK(code_item != nullptr) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
478 }
479
480 LineNumberContext context;
481 bool success = dex_file->DecodeDebugPositionInfo(code_item, CollectLineNumbers, &context);
482 if (!success) {
483 return ERR(ABSENT_INFORMATION);
484 }
485
486 unsigned char* data;
487 jlong mem_size = context.size() * sizeof(jvmtiLineNumberEntry);
488 jvmtiError alloc_error = env->Allocate(mem_size, &data);
489 if (alloc_error != ERR(NONE)) {
490 return alloc_error;
491 }
492 *table_ptr = reinterpret_cast<jvmtiLineNumberEntry*>(data);
493 memcpy(*table_ptr, context.data(), mem_size);
494 *entry_count_ptr = static_cast<jint>(context.size());
495
496 return ERR(NONE);
497}
498
Andreas Gampefdeef522017-01-09 14:40:25 -0800499template <typename T>
500static jvmtiError IsMethodT(jvmtiEnv* env ATTRIBUTE_UNUSED,
501 jmethodID method,
502 T test,
503 jboolean* is_t_ptr) {
504 if (method == nullptr) {
505 return ERR(INVALID_METHODID);
506 }
507 if (is_t_ptr == nullptr) {
508 return ERR(NULL_POINTER);
509 }
510
511 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
512 *is_t_ptr = test(art_method) ? JNI_TRUE : JNI_FALSE;
513
514 return ERR(NONE);
515}
516
517jvmtiError MethodUtil::IsMethodNative(jvmtiEnv* env, jmethodID m, jboolean* is_native_ptr) {
518 auto test = [](art::ArtMethod* method) {
519 return method->IsNative();
520 };
521 return IsMethodT(env, m, test, is_native_ptr);
522}
523
524jvmtiError MethodUtil::IsMethodObsolete(jvmtiEnv* env, jmethodID m, jboolean* is_obsolete_ptr) {
525 auto test = [](art::ArtMethod* method) {
526 return method->IsObsolete();
527 };
528 return IsMethodT(env, m, test, is_obsolete_ptr);
529}
530
531jvmtiError MethodUtil::IsMethodSynthetic(jvmtiEnv* env, jmethodID m, jboolean* is_synthetic_ptr) {
532 auto test = [](art::ArtMethod* method) {
533 return method->IsSynthetic();
534 };
535 return IsMethodT(env, m, test, is_synthetic_ptr);
536}
537
Alex Lightbebd7bd2017-07-25 14:05:52 -0700538class CommonLocalVariableClosure : public art::Closure {
539 public:
540 CommonLocalVariableClosure(art::Thread* caller,
541 jint depth,
542 jint slot)
543 : result_(ERR(INTERNAL)), caller_(caller), depth_(depth), slot_(slot) {}
544
545 void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
546 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
547 std::unique_ptr<art::Context> context(art::Context::Create());
548 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
549 visitor.WalkStack();
550 if (!visitor.FoundFrame()) {
551 // Must have been a bad depth.
552 result_ = ERR(NO_MORE_FRAMES);
553 return;
554 }
555 art::ArtMethod* method = visitor.GetMethod();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700556 if (method->IsNative()) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700557 // TODO We really should support get/set for non-shadow frames.
558 result_ = ERR(OPAQUE_FRAME);
559 return;
560 } else if (method->GetCodeItem()->registers_size_ <= slot_) {
561 result_ = ERR(INVALID_SLOT);
562 return;
563 }
Alex Light0a5ec3d2017-07-25 16:50:26 -0700564 bool needs_instrument = !visitor.IsShadowFrame();
Alex Lightbebd7bd2017-07-25 14:05:52 -0700565 uint32_t pc = visitor.GetDexPc(/*abort_on_failure*/ false);
566 if (pc == art::DexFile::kDexNoIndex) {
567 // Cannot figure out current PC.
568 result_ = ERR(OPAQUE_FRAME);
569 return;
570 }
571 std::string descriptor;
572 art::Primitive::Type slot_type = art::Primitive::kPrimVoid;
573 jvmtiError err = GetSlotType(method, pc, &descriptor, &slot_type);
574 if (err != OK) {
575 result_ = err;
576 return;
577 }
578
579 err = GetTypeError(method, slot_type, descriptor);
580 if (err != OK) {
581 result_ = err;
582 return;
583 }
584 result_ = Execute(method, visitor);
Alex Light0a5ec3d2017-07-25 16:50:26 -0700585 if (needs_instrument) {
586 art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(self);
587 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700588 }
589
590 jvmtiError GetResult() const {
591 return result_;
592 }
593
594 protected:
595 virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
596 REQUIRES(art::Locks::mutator_lock_) = 0;
597 virtual jvmtiError GetTypeError(art::ArtMethod* method,
598 art::Primitive::Type type,
599 const std::string& descriptor)
600 REQUIRES(art::Locks::mutator_lock_) = 0;
601
602 jvmtiError GetSlotType(art::ArtMethod* method,
603 uint32_t dex_pc,
604 /*out*/std::string* descriptor,
605 /*out*/art::Primitive::Type* type)
606 REQUIRES(art::Locks::mutator_lock_) {
607 const art::DexFile* dex_file = method->GetDexFile();
608 const art::DexFile::CodeItem* code_item = method->GetCodeItem();
609 if (dex_file == nullptr || code_item == nullptr) {
610 return ERR(OPAQUE_FRAME);
611 }
612
613 struct GetLocalVariableInfoContext {
614 explicit GetLocalVariableInfoContext(jint slot,
615 uint32_t pc,
616 std::string* out_descriptor,
617 art::Primitive::Type* out_type)
618 : found_(false), jslot_(slot), pc_(pc), descriptor_(out_descriptor), type_(out_type) {
619 *descriptor_ = "";
620 *type_ = art::Primitive::kPrimVoid;
621 }
622
623 static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
624 reinterpret_cast<GetLocalVariableInfoContext*>(raw_ctx)->Handle(entry);
625 }
626
627 void Handle(const art::DexFile::LocalInfo& entry) {
628 if (found_) {
629 return;
630 } else if (entry.start_address_ <= pc_ &&
631 entry.end_address_ > pc_ &&
632 entry.reg_ == jslot_) {
633 found_ = true;
634 *type_ = art::Primitive::GetType(entry.descriptor_[0]);
635 *descriptor_ = entry.descriptor_;
636 }
637 return;
638 }
639
640 bool found_;
641 jint jslot_;
642 uint32_t pc_;
643 std::string* descriptor_;
644 art::Primitive::Type* type_;
645 };
646
647 GetLocalVariableInfoContext context(slot_, dex_pc, descriptor, type);
648 if (!dex_file->DecodeDebugLocalInfo(code_item,
649 method->IsStatic(),
650 method->GetDexMethodIndex(),
651 GetLocalVariableInfoContext::Callback,
652 &context) || !context.found_) {
653 // Something went wrong with decoding the debug information. It might as well not be there.
654 return ERR(INVALID_SLOT);
655 } else {
656 return OK;
657 }
658 }
659
660 jvmtiError result_;
661 art::Thread* caller_;
662 jint depth_;
663 jint slot_;
664};
665
666class GetLocalVariableClosure : public CommonLocalVariableClosure {
667 public:
668 GetLocalVariableClosure(art::Thread* caller,
669 jint depth,
670 jint slot,
671 art::Primitive::Type type,
672 jvalue* val)
673 : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
674
675 protected:
676 jvmtiError GetTypeError(art::ArtMethod* method ATTRIBUTE_UNUSED,
677 art::Primitive::Type slot_type,
678 const std::string& descriptor ATTRIBUTE_UNUSED)
679 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
680 switch (slot_type) {
681 case art::Primitive::kPrimByte:
682 case art::Primitive::kPrimChar:
683 case art::Primitive::kPrimInt:
684 case art::Primitive::kPrimShort:
685 case art::Primitive::kPrimBoolean:
686 return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
687 case art::Primitive::kPrimLong:
688 case art::Primitive::kPrimFloat:
689 case art::Primitive::kPrimDouble:
690 case art::Primitive::kPrimNot:
691 return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
692 case art::Primitive::kPrimVoid:
693 LOG(FATAL) << "Unexpected primitive type " << slot_type;
694 UNREACHABLE();
695 }
696 }
697
698 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
699 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
700 switch (type_) {
701 case art::Primitive::kPrimNot: {
702 uint32_t ptr_val;
703 if (!visitor.GetVReg(method,
704 static_cast<uint16_t>(slot_),
705 art::kReferenceVReg,
706 &ptr_val)) {
707 return ERR(OPAQUE_FRAME);
708 }
709 art::ObjPtr<art::mirror::Object> obj(reinterpret_cast<art::mirror::Object*>(ptr_val));
710 val_->l = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
711 break;
712 }
713 case art::Primitive::kPrimInt:
714 case art::Primitive::kPrimFloat: {
715 if (!visitor.GetVReg(method,
716 static_cast<uint16_t>(slot_),
717 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg : art::kIntVReg,
718 reinterpret_cast<uint32_t*>(&val_->i))) {
719 return ERR(OPAQUE_FRAME);
720 }
721 break;
722 }
723 case art::Primitive::kPrimDouble:
724 case art::Primitive::kPrimLong: {
725 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
726 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
727 if (!visitor.GetVRegPair(method,
728 static_cast<uint16_t>(slot_),
729 lo_type,
730 high_type,
731 reinterpret_cast<uint64_t*>(&val_->j))) {
732 return ERR(OPAQUE_FRAME);
733 }
734 break;
735 }
736 default: {
737 LOG(FATAL) << "unexpected register type " << type_;
738 UNREACHABLE();
739 }
740 }
741 return OK;
742 }
743
744 private:
745 art::Primitive::Type type_;
746 jvalue* val_;
747};
748
749jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
750 jthread thread,
751 jint depth,
752 jint slot,
753 art::Primitive::Type type,
754 jvalue* val) {
755 if (depth < 0) {
756 return ERR(ILLEGAL_ARGUMENT);
757 }
758 art::Thread* self = art::Thread::Current();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700759 // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
760 art::jit::ScopedJitSuspend suspend_jit;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700761 art::ScopedObjectAccess soa(self);
Alex Light3ae82532017-07-26 13:59:07 -0700762 art::MutexLock mu(self, *art::Locks::thread_list_lock_);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700763 art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
764 if (target == nullptr && thread == nullptr) {
765 return ERR(INVALID_THREAD);
766 }
767 if (target == nullptr) {
768 return ERR(THREAD_NOT_ALIVE);
769 }
770 GetLocalVariableClosure c(self, depth, slot, type, val);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700771 if (!target->RequestSynchronousCheckpoint(&c)) {
772 return ERR(THREAD_NOT_ALIVE);
773 } else {
774 return c.GetResult();
775 }
776}
777
778class SetLocalVariableClosure : public CommonLocalVariableClosure {
779 public:
780 SetLocalVariableClosure(art::Thread* caller,
781 jint depth,
782 jint slot,
783 art::Primitive::Type type,
784 jvalue val)
785 : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
786
787 protected:
788 jvmtiError GetTypeError(art::ArtMethod* method,
789 art::Primitive::Type slot_type,
790 const std::string& descriptor)
791 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
792 switch (slot_type) {
793 case art::Primitive::kPrimNot: {
794 if (type_ != art::Primitive::kPrimNot) {
795 return ERR(TYPE_MISMATCH);
796 } else if (val_.l == nullptr) {
797 return OK;
798 } else {
799 art::ClassLinker* cl = art::Runtime::Current()->GetClassLinker();
800 art::ObjPtr<art::mirror::Class> set_class =
801 caller_->DecodeJObject(val_.l)->GetClass();
802 art::ObjPtr<art::mirror::ClassLoader> loader =
803 method->GetDeclaringClass()->GetClassLoader();
804 art::ObjPtr<art::mirror::Class> slot_class =
805 cl->LookupClass(caller_, descriptor.c_str(), loader);
806 DCHECK(!slot_class.IsNull());
807 return slot_class->IsAssignableFrom(set_class) ? OK : ERR(TYPE_MISMATCH);
808 }
809 }
810 case art::Primitive::kPrimByte:
811 case art::Primitive::kPrimChar:
812 case art::Primitive::kPrimInt:
813 case art::Primitive::kPrimShort:
814 case art::Primitive::kPrimBoolean:
815 return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
816 case art::Primitive::kPrimLong:
817 case art::Primitive::kPrimFloat:
818 case art::Primitive::kPrimDouble:
819 return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
820 case art::Primitive::kPrimVoid:
821 LOG(FATAL) << "Unexpected primitive type " << slot_type;
822 UNREACHABLE();
823 }
824 }
825
826 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
827 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
828 switch (type_) {
829 case art::Primitive::kPrimNot: {
830 uint32_t ptr_val;
831 art::ObjPtr<art::mirror::Object> obj(caller_->DecodeJObject(val_.l));
832 ptr_val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(obj.Ptr()));
833 if (!visitor.SetVReg(method,
834 static_cast<uint16_t>(slot_),
835 ptr_val,
836 art::kReferenceVReg)) {
837 return ERR(OPAQUE_FRAME);
838 }
839 break;
840 }
841 case art::Primitive::kPrimInt:
842 case art::Primitive::kPrimFloat: {
843 if (!visitor.SetVReg(method,
844 static_cast<uint16_t>(slot_),
845 static_cast<uint32_t>(val_.i),
846 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg
847 : art::kIntVReg)) {
848 return ERR(OPAQUE_FRAME);
849 }
850 break;
851 }
852 case art::Primitive::kPrimDouble:
853 case art::Primitive::kPrimLong: {
854 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
855 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
856 if (!visitor.SetVRegPair(method,
857 static_cast<uint16_t>(slot_),
858 static_cast<uint64_t>(val_.j),
859 lo_type,
860 high_type)) {
861 return ERR(OPAQUE_FRAME);
862 }
863 break;
864 }
865 default: {
866 LOG(FATAL) << "unexpected register type " << type_;
867 UNREACHABLE();
868 }
869 }
870 return OK;
871 }
872
873 private:
874 art::Primitive::Type type_;
875 jvalue val_;
876};
877
878jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
879 jthread thread,
880 jint depth,
881 jint slot,
882 art::Primitive::Type type,
883 jvalue val) {
884 if (depth < 0) {
885 return ERR(ILLEGAL_ARGUMENT);
886 }
887 art::Thread* self = art::Thread::Current();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700888 // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
889 art::jit::ScopedJitSuspend suspend_jit;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700890 art::ScopedObjectAccess soa(self);
Alex Light3ae82532017-07-26 13:59:07 -0700891 art::MutexLock mu(self, *art::Locks::thread_list_lock_);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700892 art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
893 if (target == nullptr && thread == nullptr) {
894 return ERR(INVALID_THREAD);
895 }
896 if (target == nullptr) {
897 return ERR(THREAD_NOT_ALIVE);
898 }
899 SetLocalVariableClosure c(self, depth, slot, type, val);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700900 if (!target->RequestSynchronousCheckpoint(&c)) {
901 return ERR(THREAD_NOT_ALIVE);
902 } else {
903 return c.GetResult();
904 }
905}
906
907class GetLocalInstanceClosure : public art::Closure {
908 public:
909 GetLocalInstanceClosure(art::Thread* caller, jint depth, jobject* val)
910 : result_(ERR(INTERNAL)),
911 caller_(caller),
912 depth_(depth),
913 val_(val) {}
914
915 void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
916 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
917 std::unique_ptr<art::Context> context(art::Context::Create());
918 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
919 visitor.WalkStack();
920 if (!visitor.FoundFrame()) {
921 // Must have been a bad depth.
922 result_ = ERR(NO_MORE_FRAMES);
923 return;
924 }
925 art::ArtMethod* method = visitor.GetMethod();
926 if (!visitor.IsShadowFrame() && !method->IsNative() && !method->IsProxyMethod()) {
927 // TODO We really should support get/set for non-shadow frames.
928 result_ = ERR(OPAQUE_FRAME);
929 return;
930 }
931 result_ = OK;
932 art::ObjPtr<art::mirror::Object> obj = visitor.GetThisObject();
933 *val_ = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
934 }
935
936 jvmtiError GetResult() const {
937 return result_;
938 }
939
940 private:
941 jvmtiError result_;
942 art::Thread* caller_;
943 jint depth_;
944 jobject* val_;
945};
946
947jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED,
948 jthread thread,
949 jint depth,
950 jobject* data) {
951 if (depth < 0) {
952 return ERR(ILLEGAL_ARGUMENT);
953 }
954 art::Thread* self = art::Thread::Current();
955 art::ScopedObjectAccess soa(self);
Alex Light3ae82532017-07-26 13:59:07 -0700956 art::MutexLock mu(self, *art::Locks::thread_list_lock_);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700957 art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
958 if (target == nullptr && thread == nullptr) {
959 return ERR(INVALID_THREAD);
960 }
961 if (target == nullptr) {
962 return ERR(THREAD_NOT_ALIVE);
963 }
964 GetLocalInstanceClosure c(self, depth, data);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700965 if (!target->RequestSynchronousCheckpoint(&c)) {
966 return ERR(THREAD_NOT_ALIVE);
967 } else {
968 return c.GetResult();
969 }
970}
971
972#define FOR_JVMTI_JVALUE_TYPES(fn) \
973 fn(jint, art::Primitive::kPrimInt, i) \
974 fn(jlong, art::Primitive::kPrimLong, j) \
975 fn(jfloat, art::Primitive::kPrimFloat, f) \
976 fn(jdouble, art::Primitive::kPrimDouble, d) \
977 fn(jobject, art::Primitive::kPrimNot, l)
978
979namespace impl {
980
981template<typename T> void WriteJvalue(T, jvalue*);
982template<typename T> void ReadJvalue(jvalue, T*);
983template<typename T> art::Primitive::Type GetJNIType();
984
985#define JNI_TYPE_CHAR(type, prim, id) \
986template<> art::Primitive::Type GetJNIType<type>() { \
987 return prim; \
988}
989
990FOR_JVMTI_JVALUE_TYPES(JNI_TYPE_CHAR);
991
992#undef JNI_TYPE_CHAR
993
Andreas Gampe49fc60e2017-08-24 13:19:59 -0700994#define RW_JVALUE(srctype, prim, id) \
995 template<> void ReadJvalue<srctype>(jvalue in, std::add_pointer<srctype>::type out) { \
Alex Lightbebd7bd2017-07-25 14:05:52 -0700996 *out = in.id; \
997 } \
Andreas Gampe49fc60e2017-08-24 13:19:59 -0700998 template<> void WriteJvalue<srctype>(srctype in, jvalue* out) { \
Alex Lightbebd7bd2017-07-25 14:05:52 -0700999 out->id = in; \
1000 }
1001
1002FOR_JVMTI_JVALUE_TYPES(RW_JVALUE);
1003
1004#undef RW_JVALUE
1005
1006} // namespace impl
1007
1008template<typename T>
1009jvmtiError MethodUtil::SetLocalVariable(jvmtiEnv* env,
1010 jthread thread,
1011 jint depth,
1012 jint slot,
1013 T data) {
1014 jvalue v = {.j = 0};
1015 art::Primitive::Type type = impl::GetJNIType<T>();
1016 impl::WriteJvalue(data, &v);
1017 return SetLocalVariableGeneric(env, thread, depth, slot, type, v);
1018}
1019
1020template<typename T>
1021jvmtiError MethodUtil::GetLocalVariable(jvmtiEnv* env,
1022 jthread thread,
1023 jint depth,
1024 jint slot,
1025 T* data) {
1026 if (data == nullptr) {
1027 return ERR(NULL_POINTER);
1028 }
1029 jvalue v = {.j = 0};
1030 art::Primitive::Type type = impl::GetJNIType<T>();
1031 jvmtiError err = GetLocalVariableGeneric(env, thread, depth, slot, type, &v);
1032 if (err != OK) {
1033 return err;
1034 } else {
1035 impl::ReadJvalue(v, data);
1036 return OK;
1037 }
1038}
1039
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001040#define GET_SET_LV(srctype, prim, id) \
1041 template jvmtiError MethodUtil::GetLocalVariable<srctype>(jvmtiEnv*, \
1042 jthread, \
1043 jint, \
1044 jint, \
1045 std::add_pointer<srctype>::type); \
1046 template jvmtiError MethodUtil::SetLocalVariable<srctype>(jvmtiEnv*, \
1047 jthread, \
1048 jint, \
1049 jint, \
1050 srctype);
Alex Lightbebd7bd2017-07-25 14:05:52 -07001051
1052FOR_JVMTI_JVALUE_TYPES(GET_SET_LV);
1053
1054#undef GET_SET_LV
1055
1056#undef FOR_JVMTI_JVALUE_TYPES
1057
Andreas Gampe3c252f02016-10-27 18:25:17 -07001058} // namespace openjdkjvmti