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