blob: 35f2f0cb0764e36660bbb04069bf873eafb5e651 [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"
Andreas Gampe13b27842016-11-07 16:48:23 -080042#include "jni_internal.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070043#include "mirror/class-inl.h"
44#include "mirror/class_loader.h"
45#include "mirror/object-inl.h"
Andreas Gampe27dfa052017-02-16 15:04:36 -080046#include "mirror/object_array-inl.h"
Andreas Gampe36bcd4f2016-10-28 18:07:18 -070047#include "modifiers.h"
Steven Morelande431e272017-07-18 16:53:49 -070048#include "nativehelper/ScopedLocalRef.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070049#include "runtime_callbacks.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070050#include "scoped_thread_state_change-inl.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070051#include "stack.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070052#include "thread-current-inl.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070053#include "thread_list.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070054#include "ti_thread.h"
Alex Light0af8cde2017-04-20 13:35:05 -070055#include "ti_phase.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070056
57namespace openjdkjvmti {
58
Alex Lightd78ddec2017-04-18 15:20:38 -070059struct TiMethodCallback : public art::MethodCallback {
60 void RegisterNativeMethod(art::ArtMethod* method,
61 const void* cur_method,
62 /*out*/void** new_method)
63 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
64 if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kNativeMethodBind)) {
65 art::Thread* thread = art::Thread::Current();
Alex Light0af8cde2017-04-20 13:35:05 -070066 art::JNIEnvExt* jnienv = thread->GetJniEnv();
Alex Lightd78ddec2017-04-18 15:20:38 -070067 ScopedLocalRef<jthread> thread_jni(
Alex Light0af8cde2017-04-20 13:35:05 -070068 jnienv, PhaseUtil::IsLivePhase() ? jnienv->AddLocalReference<jthread>(thread->GetPeer())
69 : nullptr);
Alex Lightd78ddec2017-04-18 15:20:38 -070070 art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
71 event_handler->DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(
72 thread,
Alex Light0af8cde2017-04-20 13:35:05 -070073 static_cast<JNIEnv*>(jnienv),
Alex Lightd78ddec2017-04-18 15:20:38 -070074 thread_jni.get(),
75 art::jni::EncodeArtMethod(method),
76 const_cast<void*>(cur_method),
77 new_method);
78 }
79 }
80
81 EventHandler* event_handler = nullptr;
82};
83
84TiMethodCallback gMethodCallback;
85
86void MethodUtil::Register(EventHandler* handler) {
87 gMethodCallback.event_handler = handler;
88 art::ScopedThreadStateChange stsc(art::Thread::Current(),
89 art::ThreadState::kWaitingForDebuggerToAttach);
90 art::ScopedSuspendAll ssa("Add method callback");
91 art::Runtime::Current()->GetRuntimeCallbacks()->AddMethodCallback(&gMethodCallback);
92}
93
94void MethodUtil::Unregister() {
95 art::ScopedThreadStateChange stsc(art::Thread::Current(),
96 art::ThreadState::kWaitingForDebuggerToAttach);
97 art::ScopedSuspendAll ssa("Remove method callback");
98 art::Runtime* runtime = art::Runtime::Current();
99 runtime->GetRuntimeCallbacks()->RemoveMethodCallback(&gMethodCallback);
100}
101
Alex Light4c174282017-07-05 10:18:18 -0700102jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
103 jmethodID method,
104 jint* size_ptr,
105 unsigned char** bytecode_ptr) {
106 if (method == nullptr) {
107 return ERR(INVALID_METHODID);
108 }
109 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
110
111 if (art_method->IsNative()) {
112 return ERR(NATIVE_METHOD);
113 }
114
115 if (size_ptr == nullptr || bytecode_ptr == nullptr) {
116 return ERR(NULL_POINTER);
117 }
118
119 art::ScopedObjectAccess soa(art::Thread::Current());
120 const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
121 if (code_item == nullptr) {
122 *size_ptr = 0;
123 *bytecode_ptr = nullptr;
124 return OK;
125 }
126 // 2 bytes per instruction for dex code.
127 *size_ptr = code_item->insns_size_in_code_units_ * 2;
128 jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr);
129 if (err != OK) {
130 return err;
131 }
132 memcpy(*bytecode_ptr, code_item->insns_, *size_ptr);
133 return OK;
134}
135
Andreas Gampef71832e2017-01-09 11:38:04 -0800136jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
137 jmethodID method,
138 jint* size_ptr) {
139 if (method == nullptr) {
140 return ERR(INVALID_METHODID);
141 }
142 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
143
144 if (art_method->IsNative()) {
145 return ERR(NATIVE_METHOD);
146 }
147
148 if (size_ptr == nullptr) {
149 return ERR(NULL_POINTER);
150 }
151
152 art::ScopedObjectAccess soa(art::Thread::Current());
153 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
Andreas Gampee1f79b62017-04-12 21:11:28 -0700154 // Use the shorty.
155 art::ArtMethod* base_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
156 size_t arg_count = art::ArtMethod::NumArgRegisters(base_method->GetShorty());
157 if (!base_method->IsStatic()) {
158 arg_count++;
159 }
160 *size_ptr = static_cast<jint>(arg_count);
Andreas Gampef71832e2017-01-09 11:38:04 -0800161 return ERR(NONE);
162 }
163
164 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
165 *size_ptr = art_method->GetCodeItem()->ins_size_;
166
167 return ERR(NONE);
168}
169
Alex Lightce68cc62017-07-26 10:30:38 -0700170jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
171 jmethodID method,
172 jint* entry_count_ptr,
173 jvmtiLocalVariableEntry** table_ptr) {
174 if (method == nullptr) {
175 return ERR(INVALID_METHODID);
176 }
177 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
178
179 if (art_method->IsNative()) {
180 return ERR(NATIVE_METHOD);
181 }
182
183 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
184 return ERR(NULL_POINTER);
185 }
186
187 art::ScopedObjectAccess soa(art::Thread::Current());
188 const art::DexFile* dex_file = art_method->GetDexFile();
189 const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
190 // TODO code_item == nullptr means that the method is abstract (or native, but we check that
191 // earlier). We should check what is returned by the RI in this situation since it's not clear
192 // what the appropriate return value is from the spec.
193 if (dex_file == nullptr || code_item == nullptr) {
194 return ERR(ABSENT_INFORMATION);
195 }
196
197 struct LocalVariableContext {
198 explicit LocalVariableContext(jvmtiEnv* jenv) : env_(jenv), variables_(), err_(OK) {}
199
200 static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
201 reinterpret_cast<LocalVariableContext*>(raw_ctx)->Insert(entry);
202 }
203
204 void Insert(const art::DexFile::LocalInfo& entry) {
205 if (err_ != OK) {
206 return;
207 }
208 JvmtiUniquePtr<char[]> name_str = CopyString(env_, entry.name_, &err_);
209 if (err_ != OK) {
210 return;
211 }
212 JvmtiUniquePtr<char[]> sig_str = CopyString(env_, entry.descriptor_, &err_);
213 if (err_ != OK) {
214 return;
215 }
216 JvmtiUniquePtr<char[]> generic_sig_str = CopyString(env_, entry.signature_, &err_);
217 if (err_ != OK) {
218 return;
219 }
220 variables_.push_back({
221 .start_location = static_cast<jlocation>(entry.start_address_),
222 .length = static_cast<jint>(entry.end_address_ - entry.start_address_),
223 .name = name_str.release(),
224 .signature = sig_str.release(),
225 .generic_signature = generic_sig_str.release(),
226 .slot = entry.reg_,
227 });
228 }
229
230 jvmtiError Release(jint* out_entry_count_ptr, jvmtiLocalVariableEntry** out_table_ptr) {
231 jlong table_size = sizeof(jvmtiLocalVariableEntry) * variables_.size();
232 if (err_ != OK ||
233 (err_ = env_->Allocate(table_size,
234 reinterpret_cast<unsigned char**>(out_table_ptr))) != OK) {
235 Cleanup();
236 return err_;
237 } else {
238 *out_entry_count_ptr = variables_.size();
239 memcpy(*out_table_ptr, variables_.data(), table_size);
240 return OK;
241 }
242 }
243
244 void Cleanup() {
245 for (jvmtiLocalVariableEntry& e : variables_) {
246 env_->Deallocate(reinterpret_cast<unsigned char*>(e.name));
247 env_->Deallocate(reinterpret_cast<unsigned char*>(e.signature));
248 env_->Deallocate(reinterpret_cast<unsigned char*>(e.generic_signature));
249 }
250 }
251
252 jvmtiEnv* env_;
253 std::vector<jvmtiLocalVariableEntry> variables_;
254 jvmtiError err_;
255 };
256
257 LocalVariableContext context(env);
258 if (!dex_file->DecodeDebugLocalInfo(code_item,
259 art_method->IsStatic(),
260 art_method->GetDexMethodIndex(),
261 LocalVariableContext::Callback,
262 &context)) {
263 // Something went wrong with decoding the debug information. It might as well not be there.
264 return ERR(ABSENT_INFORMATION);
265 } else {
266 return context.Release(entry_count_ptr, table_ptr);
267 }
268}
269
Andreas Gampef71832e2017-01-09 11:38:04 -0800270jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
271 jmethodID method,
272 jint* max_ptr) {
273 if (method == nullptr) {
274 return ERR(INVALID_METHODID);
275 }
276 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
277
278 if (art_method->IsNative()) {
279 return ERR(NATIVE_METHOD);
280 }
281
282 if (max_ptr == nullptr) {
283 return ERR(NULL_POINTER);
284 }
285
286 art::ScopedObjectAccess soa(art::Thread::Current());
287 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
288 // This isn't specified as an error case, so return 0.
289 *max_ptr = 0;
290 return ERR(NONE);
291 }
292
293 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
294 *max_ptr = art_method->GetCodeItem()->registers_size_;
295
296 return ERR(NONE);
297}
298
Andreas Gampe3c252f02016-10-27 18:25:17 -0700299jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
300 jmethodID method,
301 char** name_ptr,
302 char** signature_ptr,
303 char** generic_ptr) {
304 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe13b27842016-11-07 16:48:23 -0800305 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe3c252f02016-10-27 18:25:17 -0700306 art_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
307
Andreas Gampe54711412017-02-21 12:41:43 -0800308 JvmtiUniquePtr<char[]> name_copy;
Andreas Gampe3c252f02016-10-27 18:25:17 -0700309 if (name_ptr != nullptr) {
310 const char* method_name = art_method->GetName();
311 if (method_name == nullptr) {
312 method_name = "<error>";
313 }
Andreas Gampe54711412017-02-21 12:41:43 -0800314 jvmtiError ret;
315 name_copy = CopyString(env, method_name, &ret);
316 if (name_copy == nullptr) {
Andreas Gampe3c252f02016-10-27 18:25:17 -0700317 return ret;
318 }
Andreas Gampe54711412017-02-21 12:41:43 -0800319 *name_ptr = name_copy.get();
Andreas Gampe3c252f02016-10-27 18:25:17 -0700320 }
321
Andreas Gampe54711412017-02-21 12:41:43 -0800322 JvmtiUniquePtr<char[]> signature_copy;
Andreas Gampe3c252f02016-10-27 18:25:17 -0700323 if (signature_ptr != nullptr) {
324 const art::Signature sig = art_method->GetSignature();
325 std::string str = sig.ToString();
Andreas Gampe54711412017-02-21 12:41:43 -0800326 jvmtiError ret;
327 signature_copy = CopyString(env, str.c_str(), &ret);
328 if (signature_copy == nullptr) {
Andreas Gampe3c252f02016-10-27 18:25:17 -0700329 return ret;
330 }
Andreas Gampe54711412017-02-21 12:41:43 -0800331 *signature_ptr = signature_copy.get();
Andreas Gampe3c252f02016-10-27 18:25:17 -0700332 }
333
Andreas Gampe862bdd82016-11-18 13:31:13 -0800334 if (generic_ptr != nullptr) {
335 *generic_ptr = nullptr;
Andreas Gampe27dfa052017-02-16 15:04:36 -0800336 if (!art_method->GetDeclaringClass()->IsProxyClass()) {
337 art::mirror::ObjectArray<art::mirror::String>* str_array =
338 art::annotations::GetSignatureAnnotationForMethod(art_method);
339 if (str_array != nullptr) {
340 std::ostringstream oss;
341 for (int32_t i = 0; i != str_array->GetLength(); ++i) {
342 oss << str_array->Get(i)->ToModifiedUtf8();
343 }
344 std::string output_string = oss.str();
Andreas Gampe54711412017-02-21 12:41:43 -0800345 jvmtiError ret;
346 JvmtiUniquePtr<char[]> generic_copy = CopyString(env, output_string.c_str(), &ret);
347 if (generic_copy == nullptr) {
Andreas Gampe27dfa052017-02-16 15:04:36 -0800348 return ret;
349 }
Andreas Gampe54711412017-02-21 12:41:43 -0800350 *generic_ptr = generic_copy.release();
Andreas Gampe27dfa052017-02-16 15:04:36 -0800351 } else if (soa.Self()->IsExceptionPending()) {
352 // TODO: Should we report an error here?
353 soa.Self()->ClearException();
354 }
355 }
Andreas Gampe862bdd82016-11-18 13:31:13 -0800356 }
Andreas Gampe3c252f02016-10-27 18:25:17 -0700357
358 // Everything is fine, release the buffers.
359 name_copy.release();
360 signature_copy.release();
361
362 return ERR(NONE);
363}
364
Andreas Gampe368a2082016-10-28 17:33:13 -0700365jvmtiError MethodUtil::GetMethodDeclaringClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
366 jmethodID method,
367 jclass* declaring_class_ptr) {
368 if (declaring_class_ptr == nullptr) {
369 return ERR(NULL_POINTER);
370 }
371
Andreas Gampe13b27842016-11-07 16:48:23 -0800372 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe368a2082016-10-28 17:33:13 -0700373 // Note: No GetInterfaceMethodIfProxy, we want to actual class.
374
Andreas Gampe13b27842016-11-07 16:48:23 -0800375 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe368a2082016-10-28 17:33:13 -0700376 art::mirror::Class* klass = art_method->GetDeclaringClass();
377 *declaring_class_ptr = soa.AddLocalReference<jclass>(klass);
378
379 return ERR(NONE);
380}
381
Andreas Gampef71832e2017-01-09 11:38:04 -0800382jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
383 jmethodID method,
384 jlocation* start_location_ptr,
385 jlocation* end_location_ptr) {
386 if (method == nullptr) {
387 return ERR(INVALID_METHODID);
388 }
389 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
390
391 if (art_method->IsNative()) {
392 return ERR(NATIVE_METHOD);
393 }
394
395 if (start_location_ptr == nullptr || end_location_ptr == nullptr) {
396 return ERR(NULL_POINTER);
397 }
398
399 art::ScopedObjectAccess soa(art::Thread::Current());
400 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
Andreas Gampee1f79b62017-04-12 21:11:28 -0700401 // This isn't specified as an error case, so return -1/-1 as the RI does.
402 *start_location_ptr = -1;
403 *end_location_ptr = -1;
Andreas Gampef71832e2017-01-09 11:38:04 -0800404 return ERR(NONE);
405 }
406
407 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
408 *start_location_ptr = 0;
409 *end_location_ptr = art_method->GetCodeItem()->insns_size_in_code_units_ - 1;
410
411 return ERR(NONE);
412}
413
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700414jvmtiError MethodUtil::GetMethodModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
415 jmethodID method,
416 jint* modifiers_ptr) {
417 if (modifiers_ptr == nullptr) {
418 return ERR(NULL_POINTER);
419 }
420
Andreas Gampe13b27842016-11-07 16:48:23 -0800421 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700422 uint32_t modifiers = art_method->GetAccessFlags();
423
424 // Note: Keep this code in sync with Executable.fixMethodFlags.
425 if ((modifiers & art::kAccAbstract) != 0) {
426 modifiers &= ~art::kAccNative;
427 }
428 modifiers &= ~art::kAccSynchronized;
429 if ((modifiers & art::kAccDeclaredSynchronized) != 0) {
430 modifiers |= art::kAccSynchronized;
431 }
432 modifiers &= art::kAccJavaFlagsMask;
433
434 *modifiers_ptr = modifiers;
435 return ERR(NONE);
436}
437
Andreas Gampeda3e5612016-12-13 19:00:53 -0800438using LineNumberContext = std::vector<jvmtiLineNumberEntry>;
439
440static bool CollectLineNumbers(void* void_context, const art::DexFile::PositionInfo& entry) {
441 LineNumberContext* context = reinterpret_cast<LineNumberContext*>(void_context);
442 jvmtiLineNumberEntry jvmti_entry = { static_cast<jlocation>(entry.address_),
443 static_cast<jint>(entry.line_) };
444 context->push_back(jvmti_entry);
445 return false; // Collect all, no early exit.
446}
447
448jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
449 jmethodID method,
450 jint* entry_count_ptr,
451 jvmtiLineNumberEntry** table_ptr) {
452 if (method == nullptr) {
453 return ERR(NULL_POINTER);
454 }
455 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
456 DCHECK(!art_method->IsRuntimeMethod());
457
458 const art::DexFile::CodeItem* code_item;
459 const art::DexFile* dex_file;
460 {
461 art::ScopedObjectAccess soa(art::Thread::Current());
462
463 if (art_method->IsProxyMethod()) {
464 return ERR(ABSENT_INFORMATION);
465 }
466 if (art_method->IsNative()) {
467 return ERR(NATIVE_METHOD);
468 }
469 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
470 return ERR(NULL_POINTER);
471 }
472
473 code_item = art_method->GetCodeItem();
474 dex_file = art_method->GetDexFile();
475 DCHECK(code_item != nullptr) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
476 }
477
478 LineNumberContext context;
479 bool success = dex_file->DecodeDebugPositionInfo(code_item, CollectLineNumbers, &context);
480 if (!success) {
481 return ERR(ABSENT_INFORMATION);
482 }
483
484 unsigned char* data;
485 jlong mem_size = context.size() * sizeof(jvmtiLineNumberEntry);
486 jvmtiError alloc_error = env->Allocate(mem_size, &data);
487 if (alloc_error != ERR(NONE)) {
488 return alloc_error;
489 }
490 *table_ptr = reinterpret_cast<jvmtiLineNumberEntry*>(data);
491 memcpy(*table_ptr, context.data(), mem_size);
492 *entry_count_ptr = static_cast<jint>(context.size());
493
494 return ERR(NONE);
495}
496
Andreas Gampefdeef522017-01-09 14:40:25 -0800497template <typename T>
498static jvmtiError IsMethodT(jvmtiEnv* env ATTRIBUTE_UNUSED,
499 jmethodID method,
500 T test,
501 jboolean* is_t_ptr) {
502 if (method == nullptr) {
503 return ERR(INVALID_METHODID);
504 }
505 if (is_t_ptr == nullptr) {
506 return ERR(NULL_POINTER);
507 }
508
509 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
510 *is_t_ptr = test(art_method) ? JNI_TRUE : JNI_FALSE;
511
512 return ERR(NONE);
513}
514
515jvmtiError MethodUtil::IsMethodNative(jvmtiEnv* env, jmethodID m, jboolean* is_native_ptr) {
516 auto test = [](art::ArtMethod* method) {
517 return method->IsNative();
518 };
519 return IsMethodT(env, m, test, is_native_ptr);
520}
521
522jvmtiError MethodUtil::IsMethodObsolete(jvmtiEnv* env, jmethodID m, jboolean* is_obsolete_ptr) {
523 auto test = [](art::ArtMethod* method) {
524 return method->IsObsolete();
525 };
526 return IsMethodT(env, m, test, is_obsolete_ptr);
527}
528
529jvmtiError MethodUtil::IsMethodSynthetic(jvmtiEnv* env, jmethodID m, jboolean* is_synthetic_ptr) {
530 auto test = [](art::ArtMethod* method) {
531 return method->IsSynthetic();
532 };
533 return IsMethodT(env, m, test, is_synthetic_ptr);
534}
535
Alex Lightbebd7bd2017-07-25 14:05:52 -0700536struct FindFrameAtDepthVisitor : art::StackVisitor {
537 public:
538 FindFrameAtDepthVisitor(art::Thread* target, art::Context* ctx, jint depth)
539 REQUIRES_SHARED(art::Locks::mutator_lock_)
540 : art::StackVisitor(target, ctx, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames),
541 found_frame_(false),
542 cnt_(0),
543 depth_(static_cast<size_t>(depth)) { }
544
545 bool FoundFrame() {
546 return found_frame_;
547 }
548
549 bool VisitFrame() NO_THREAD_SAFETY_ANALYSIS {
550 if (GetMethod()->IsRuntimeMethod()) {
551 return true;
552 }
553 if (cnt_ == depth_) {
554 // We found our frame, exit.
555 found_frame_ = true;
556 return false;
557 } else {
558 cnt_++;
559 return true;
560 }
561 }
562
563 private:
564 bool found_frame_;
565 size_t cnt_;
566 size_t depth_;
567};
568
569class CommonLocalVariableClosure : public art::Closure {
570 public:
571 CommonLocalVariableClosure(art::Thread* caller,
572 jint depth,
573 jint slot)
574 : result_(ERR(INTERNAL)), caller_(caller), depth_(depth), slot_(slot) {}
575
576 void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
577 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
578 std::unique_ptr<art::Context> context(art::Context::Create());
579 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
580 visitor.WalkStack();
581 if (!visitor.FoundFrame()) {
582 // Must have been a bad depth.
583 result_ = ERR(NO_MORE_FRAMES);
584 return;
585 }
586 art::ArtMethod* method = visitor.GetMethod();
587 if (method->IsNative() || !visitor.IsShadowFrame()) {
588 // TODO We really should support get/set for non-shadow frames.
589 result_ = ERR(OPAQUE_FRAME);
590 return;
591 } else if (method->GetCodeItem()->registers_size_ <= slot_) {
592 result_ = ERR(INVALID_SLOT);
593 return;
594 }
595 uint32_t pc = visitor.GetDexPc(/*abort_on_failure*/ false);
596 if (pc == art::DexFile::kDexNoIndex) {
597 // Cannot figure out current PC.
598 result_ = ERR(OPAQUE_FRAME);
599 return;
600 }
601 std::string descriptor;
602 art::Primitive::Type slot_type = art::Primitive::kPrimVoid;
603 jvmtiError err = GetSlotType(method, pc, &descriptor, &slot_type);
604 if (err != OK) {
605 result_ = err;
606 return;
607 }
608
609 err = GetTypeError(method, slot_type, descriptor);
610 if (err != OK) {
611 result_ = err;
612 return;
613 }
614 result_ = Execute(method, visitor);
615 }
616
617 jvmtiError GetResult() const {
618 return result_;
619 }
620
621 protected:
622 virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
623 REQUIRES(art::Locks::mutator_lock_) = 0;
624 virtual jvmtiError GetTypeError(art::ArtMethod* method,
625 art::Primitive::Type type,
626 const std::string& descriptor)
627 REQUIRES(art::Locks::mutator_lock_) = 0;
628
629 jvmtiError GetSlotType(art::ArtMethod* method,
630 uint32_t dex_pc,
631 /*out*/std::string* descriptor,
632 /*out*/art::Primitive::Type* type)
633 REQUIRES(art::Locks::mutator_lock_) {
634 const art::DexFile* dex_file = method->GetDexFile();
635 const art::DexFile::CodeItem* code_item = method->GetCodeItem();
636 if (dex_file == nullptr || code_item == nullptr) {
637 return ERR(OPAQUE_FRAME);
638 }
639
640 struct GetLocalVariableInfoContext {
641 explicit GetLocalVariableInfoContext(jint slot,
642 uint32_t pc,
643 std::string* out_descriptor,
644 art::Primitive::Type* out_type)
645 : found_(false), jslot_(slot), pc_(pc), descriptor_(out_descriptor), type_(out_type) {
646 *descriptor_ = "";
647 *type_ = art::Primitive::kPrimVoid;
648 }
649
650 static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
651 reinterpret_cast<GetLocalVariableInfoContext*>(raw_ctx)->Handle(entry);
652 }
653
654 void Handle(const art::DexFile::LocalInfo& entry) {
655 if (found_) {
656 return;
657 } else if (entry.start_address_ <= pc_ &&
658 entry.end_address_ > pc_ &&
659 entry.reg_ == jslot_) {
660 found_ = true;
661 *type_ = art::Primitive::GetType(entry.descriptor_[0]);
662 *descriptor_ = entry.descriptor_;
663 }
664 return;
665 }
666
667 bool found_;
668 jint jslot_;
669 uint32_t pc_;
670 std::string* descriptor_;
671 art::Primitive::Type* type_;
672 };
673
674 GetLocalVariableInfoContext context(slot_, dex_pc, descriptor, type);
675 if (!dex_file->DecodeDebugLocalInfo(code_item,
676 method->IsStatic(),
677 method->GetDexMethodIndex(),
678 GetLocalVariableInfoContext::Callback,
679 &context) || !context.found_) {
680 // Something went wrong with decoding the debug information. It might as well not be there.
681 return ERR(INVALID_SLOT);
682 } else {
683 return OK;
684 }
685 }
686
687 jvmtiError result_;
688 art::Thread* caller_;
689 jint depth_;
690 jint slot_;
691};
692
693class GetLocalVariableClosure : public CommonLocalVariableClosure {
694 public:
695 GetLocalVariableClosure(art::Thread* caller,
696 jint depth,
697 jint slot,
698 art::Primitive::Type type,
699 jvalue* val)
700 : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
701
702 protected:
703 jvmtiError GetTypeError(art::ArtMethod* method ATTRIBUTE_UNUSED,
704 art::Primitive::Type slot_type,
705 const std::string& descriptor ATTRIBUTE_UNUSED)
706 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
707 switch (slot_type) {
708 case art::Primitive::kPrimByte:
709 case art::Primitive::kPrimChar:
710 case art::Primitive::kPrimInt:
711 case art::Primitive::kPrimShort:
712 case art::Primitive::kPrimBoolean:
713 return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
714 case art::Primitive::kPrimLong:
715 case art::Primitive::kPrimFloat:
716 case art::Primitive::kPrimDouble:
717 case art::Primitive::kPrimNot:
718 return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
719 case art::Primitive::kPrimVoid:
720 LOG(FATAL) << "Unexpected primitive type " << slot_type;
721 UNREACHABLE();
722 }
723 }
724
725 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
726 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
727 switch (type_) {
728 case art::Primitive::kPrimNot: {
729 uint32_t ptr_val;
730 if (!visitor.GetVReg(method,
731 static_cast<uint16_t>(slot_),
732 art::kReferenceVReg,
733 &ptr_val)) {
734 return ERR(OPAQUE_FRAME);
735 }
736 art::ObjPtr<art::mirror::Object> obj(reinterpret_cast<art::mirror::Object*>(ptr_val));
737 val_->l = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
738 break;
739 }
740 case art::Primitive::kPrimInt:
741 case art::Primitive::kPrimFloat: {
742 if (!visitor.GetVReg(method,
743 static_cast<uint16_t>(slot_),
744 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg : art::kIntVReg,
745 reinterpret_cast<uint32_t*>(&val_->i))) {
746 return ERR(OPAQUE_FRAME);
747 }
748 break;
749 }
750 case art::Primitive::kPrimDouble:
751 case art::Primitive::kPrimLong: {
752 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
753 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
754 if (!visitor.GetVRegPair(method,
755 static_cast<uint16_t>(slot_),
756 lo_type,
757 high_type,
758 reinterpret_cast<uint64_t*>(&val_->j))) {
759 return ERR(OPAQUE_FRAME);
760 }
761 break;
762 }
763 default: {
764 LOG(FATAL) << "unexpected register type " << type_;
765 UNREACHABLE();
766 }
767 }
768 return OK;
769 }
770
771 private:
772 art::Primitive::Type type_;
773 jvalue* val_;
774};
775
776jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
777 jthread thread,
778 jint depth,
779 jint slot,
780 art::Primitive::Type type,
781 jvalue* val) {
782 if (depth < 0) {
783 return ERR(ILLEGAL_ARGUMENT);
784 }
785 art::Thread* self = art::Thread::Current();
786 art::ScopedObjectAccess soa(self);
Alex Light3ae82532017-07-26 13:59:07 -0700787 art::MutexLock mu(self, *art::Locks::thread_list_lock_);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700788 art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
789 if (target == nullptr && thread == nullptr) {
790 return ERR(INVALID_THREAD);
791 }
792 if (target == nullptr) {
793 return ERR(THREAD_NOT_ALIVE);
794 }
795 GetLocalVariableClosure c(self, depth, slot, type, val);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700796 if (!target->RequestSynchronousCheckpoint(&c)) {
797 return ERR(THREAD_NOT_ALIVE);
798 } else {
799 return c.GetResult();
800 }
801}
802
803class SetLocalVariableClosure : public CommonLocalVariableClosure {
804 public:
805 SetLocalVariableClosure(art::Thread* caller,
806 jint depth,
807 jint slot,
808 art::Primitive::Type type,
809 jvalue val)
810 : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
811
812 protected:
813 jvmtiError GetTypeError(art::ArtMethod* method,
814 art::Primitive::Type slot_type,
815 const std::string& descriptor)
816 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
817 switch (slot_type) {
818 case art::Primitive::kPrimNot: {
819 if (type_ != art::Primitive::kPrimNot) {
820 return ERR(TYPE_MISMATCH);
821 } else if (val_.l == nullptr) {
822 return OK;
823 } else {
824 art::ClassLinker* cl = art::Runtime::Current()->GetClassLinker();
825 art::ObjPtr<art::mirror::Class> set_class =
826 caller_->DecodeJObject(val_.l)->GetClass();
827 art::ObjPtr<art::mirror::ClassLoader> loader =
828 method->GetDeclaringClass()->GetClassLoader();
829 art::ObjPtr<art::mirror::Class> slot_class =
830 cl->LookupClass(caller_, descriptor.c_str(), loader);
831 DCHECK(!slot_class.IsNull());
832 return slot_class->IsAssignableFrom(set_class) ? OK : ERR(TYPE_MISMATCH);
833 }
834 }
835 case art::Primitive::kPrimByte:
836 case art::Primitive::kPrimChar:
837 case art::Primitive::kPrimInt:
838 case art::Primitive::kPrimShort:
839 case art::Primitive::kPrimBoolean:
840 return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
841 case art::Primitive::kPrimLong:
842 case art::Primitive::kPrimFloat:
843 case art::Primitive::kPrimDouble:
844 return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
845 case art::Primitive::kPrimVoid:
846 LOG(FATAL) << "Unexpected primitive type " << slot_type;
847 UNREACHABLE();
848 }
849 }
850
851 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
852 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
853 switch (type_) {
854 case art::Primitive::kPrimNot: {
855 uint32_t ptr_val;
856 art::ObjPtr<art::mirror::Object> obj(caller_->DecodeJObject(val_.l));
857 ptr_val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(obj.Ptr()));
858 if (!visitor.SetVReg(method,
859 static_cast<uint16_t>(slot_),
860 ptr_val,
861 art::kReferenceVReg)) {
862 return ERR(OPAQUE_FRAME);
863 }
864 break;
865 }
866 case art::Primitive::kPrimInt:
867 case art::Primitive::kPrimFloat: {
868 if (!visitor.SetVReg(method,
869 static_cast<uint16_t>(slot_),
870 static_cast<uint32_t>(val_.i),
871 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg
872 : art::kIntVReg)) {
873 return ERR(OPAQUE_FRAME);
874 }
875 break;
876 }
877 case art::Primitive::kPrimDouble:
878 case art::Primitive::kPrimLong: {
879 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
880 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
881 if (!visitor.SetVRegPair(method,
882 static_cast<uint16_t>(slot_),
883 static_cast<uint64_t>(val_.j),
884 lo_type,
885 high_type)) {
886 return ERR(OPAQUE_FRAME);
887 }
888 break;
889 }
890 default: {
891 LOG(FATAL) << "unexpected register type " << type_;
892 UNREACHABLE();
893 }
894 }
895 return OK;
896 }
897
898 private:
899 art::Primitive::Type type_;
900 jvalue val_;
901};
902
903jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
904 jthread thread,
905 jint depth,
906 jint slot,
907 art::Primitive::Type type,
908 jvalue val) {
909 if (depth < 0) {
910 return ERR(ILLEGAL_ARGUMENT);
911 }
912 art::Thread* self = art::Thread::Current();
913 art::ScopedObjectAccess soa(self);
Alex Light3ae82532017-07-26 13:59:07 -0700914 art::MutexLock mu(self, *art::Locks::thread_list_lock_);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700915 art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
916 if (target == nullptr && thread == nullptr) {
917 return ERR(INVALID_THREAD);
918 }
919 if (target == nullptr) {
920 return ERR(THREAD_NOT_ALIVE);
921 }
922 SetLocalVariableClosure c(self, depth, slot, type, val);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700923 if (!target->RequestSynchronousCheckpoint(&c)) {
924 return ERR(THREAD_NOT_ALIVE);
925 } else {
926 return c.GetResult();
927 }
928}
929
930class GetLocalInstanceClosure : public art::Closure {
931 public:
932 GetLocalInstanceClosure(art::Thread* caller, jint depth, jobject* val)
933 : result_(ERR(INTERNAL)),
934 caller_(caller),
935 depth_(depth),
936 val_(val) {}
937
938 void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
939 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
940 std::unique_ptr<art::Context> context(art::Context::Create());
941 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
942 visitor.WalkStack();
943 if (!visitor.FoundFrame()) {
944 // Must have been a bad depth.
945 result_ = ERR(NO_MORE_FRAMES);
946 return;
947 }
948 art::ArtMethod* method = visitor.GetMethod();
949 if (!visitor.IsShadowFrame() && !method->IsNative() && !method->IsProxyMethod()) {
950 // TODO We really should support get/set for non-shadow frames.
951 result_ = ERR(OPAQUE_FRAME);
952 return;
953 }
954 result_ = OK;
955 art::ObjPtr<art::mirror::Object> obj = visitor.GetThisObject();
956 *val_ = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
957 }
958
959 jvmtiError GetResult() const {
960 return result_;
961 }
962
963 private:
964 jvmtiError result_;
965 art::Thread* caller_;
966 jint depth_;
967 jobject* val_;
968};
969
970jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED,
971 jthread thread,
972 jint depth,
973 jobject* data) {
974 if (depth < 0) {
975 return ERR(ILLEGAL_ARGUMENT);
976 }
977 art::Thread* self = art::Thread::Current();
978 art::ScopedObjectAccess soa(self);
Alex Light3ae82532017-07-26 13:59:07 -0700979 art::MutexLock mu(self, *art::Locks::thread_list_lock_);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700980 art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
981 if (target == nullptr && thread == nullptr) {
982 return ERR(INVALID_THREAD);
983 }
984 if (target == nullptr) {
985 return ERR(THREAD_NOT_ALIVE);
986 }
987 GetLocalInstanceClosure c(self, depth, data);
Alex Lightbebd7bd2017-07-25 14:05:52 -0700988 if (!target->RequestSynchronousCheckpoint(&c)) {
989 return ERR(THREAD_NOT_ALIVE);
990 } else {
991 return c.GetResult();
992 }
993}
994
995#define FOR_JVMTI_JVALUE_TYPES(fn) \
996 fn(jint, art::Primitive::kPrimInt, i) \
997 fn(jlong, art::Primitive::kPrimLong, j) \
998 fn(jfloat, art::Primitive::kPrimFloat, f) \
999 fn(jdouble, art::Primitive::kPrimDouble, d) \
1000 fn(jobject, art::Primitive::kPrimNot, l)
1001
1002namespace impl {
1003
1004template<typename T> void WriteJvalue(T, jvalue*);
1005template<typename T> void ReadJvalue(jvalue, T*);
1006template<typename T> art::Primitive::Type GetJNIType();
1007
1008#define JNI_TYPE_CHAR(type, prim, id) \
1009template<> art::Primitive::Type GetJNIType<type>() { \
1010 return prim; \
1011}
1012
1013FOR_JVMTI_JVALUE_TYPES(JNI_TYPE_CHAR);
1014
1015#undef JNI_TYPE_CHAR
1016
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001017#define RW_JVALUE(srctype, prim, id) \
1018 template<> void ReadJvalue<srctype>(jvalue in, std::add_pointer<srctype>::type out) { \
Alex Lightbebd7bd2017-07-25 14:05:52 -07001019 *out = in.id; \
1020 } \
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001021 template<> void WriteJvalue<srctype>(srctype in, jvalue* out) { \
Alex Lightbebd7bd2017-07-25 14:05:52 -07001022 out->id = in; \
1023 }
1024
1025FOR_JVMTI_JVALUE_TYPES(RW_JVALUE);
1026
1027#undef RW_JVALUE
1028
1029} // namespace impl
1030
1031template<typename T>
1032jvmtiError MethodUtil::SetLocalVariable(jvmtiEnv* env,
1033 jthread thread,
1034 jint depth,
1035 jint slot,
1036 T data) {
1037 jvalue v = {.j = 0};
1038 art::Primitive::Type type = impl::GetJNIType<T>();
1039 impl::WriteJvalue(data, &v);
1040 return SetLocalVariableGeneric(env, thread, depth, slot, type, v);
1041}
1042
1043template<typename T>
1044jvmtiError MethodUtil::GetLocalVariable(jvmtiEnv* env,
1045 jthread thread,
1046 jint depth,
1047 jint slot,
1048 T* data) {
1049 if (data == nullptr) {
1050 return ERR(NULL_POINTER);
1051 }
1052 jvalue v = {.j = 0};
1053 art::Primitive::Type type = impl::GetJNIType<T>();
1054 jvmtiError err = GetLocalVariableGeneric(env, thread, depth, slot, type, &v);
1055 if (err != OK) {
1056 return err;
1057 } else {
1058 impl::ReadJvalue(v, data);
1059 return OK;
1060 }
1061}
1062
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001063#define GET_SET_LV(srctype, prim, id) \
1064 template jvmtiError MethodUtil::GetLocalVariable<srctype>(jvmtiEnv*, \
1065 jthread, \
1066 jint, \
1067 jint, \
1068 std::add_pointer<srctype>::type); \
1069 template jvmtiError MethodUtil::SetLocalVariable<srctype>(jvmtiEnv*, \
1070 jthread, \
1071 jint, \
1072 jint, \
1073 srctype);
Alex Lightbebd7bd2017-07-25 14:05:52 -07001074
1075FOR_JVMTI_JVALUE_TYPES(GET_SET_LV);
1076
1077#undef GET_SET_LV
1078
1079#undef FOR_JVMTI_JVALUE_TYPES
1080
Andreas Gampe3c252f02016-10-27 18:25:17 -07001081} // namespace openjdkjvmti