blob: a6cfcc12bc301cd18b08452ca6bb06923260c995 [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"
Andreas Gampe27dfa052017-02-16 15:04:36 -080037#include "dex_file_annotations.h"
Andreas Gampe13b27842016-11-07 16:48:23 -080038#include "jni_internal.h"
Andreas Gampe27dfa052017-02-16 15:04:36 -080039#include "mirror/object_array-inl.h"
Andreas Gampe36bcd4f2016-10-28 18:07:18 -070040#include "modifiers.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070041#include "scoped_thread_state_change-inl.h"
Andreas Gampeab2f0d02017-01-05 17:23:45 -080042#include "thread-inl.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070043
44namespace openjdkjvmti {
45
Andreas Gampef71832e2017-01-09 11:38:04 -080046jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
47 jmethodID method,
48 jint* size_ptr) {
49 if (method == nullptr) {
50 return ERR(INVALID_METHODID);
51 }
52 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
53
54 if (art_method->IsNative()) {
55 return ERR(NATIVE_METHOD);
56 }
57
58 if (size_ptr == nullptr) {
59 return ERR(NULL_POINTER);
60 }
61
62 art::ScopedObjectAccess soa(art::Thread::Current());
63 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
64 // This isn't specified as an error case, so return 0.
65 *size_ptr = 0;
66 return ERR(NONE);
67 }
68
69 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
70 *size_ptr = art_method->GetCodeItem()->ins_size_;
71
72 return ERR(NONE);
73}
74
75jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
76 jmethodID method,
77 jint* max_ptr) {
78 if (method == nullptr) {
79 return ERR(INVALID_METHODID);
80 }
81 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
82
83 if (art_method->IsNative()) {
84 return ERR(NATIVE_METHOD);
85 }
86
87 if (max_ptr == nullptr) {
88 return ERR(NULL_POINTER);
89 }
90
91 art::ScopedObjectAccess soa(art::Thread::Current());
92 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
93 // This isn't specified as an error case, so return 0.
94 *max_ptr = 0;
95 return ERR(NONE);
96 }
97
98 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
99 *max_ptr = art_method->GetCodeItem()->registers_size_;
100
101 return ERR(NONE);
102}
103
Andreas Gampe3c252f02016-10-27 18:25:17 -0700104jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
105 jmethodID method,
106 char** name_ptr,
107 char** signature_ptr,
108 char** generic_ptr) {
109 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe13b27842016-11-07 16:48:23 -0800110 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe3c252f02016-10-27 18:25:17 -0700111 art_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
112
113 JvmtiUniquePtr name_copy;
114 if (name_ptr != nullptr) {
115 const char* method_name = art_method->GetName();
116 if (method_name == nullptr) {
117 method_name = "<error>";
118 }
119 unsigned char* tmp;
120 jvmtiError ret = CopyString(env, method_name, &tmp);
121 if (ret != ERR(NONE)) {
122 return ret;
123 }
124 name_copy = MakeJvmtiUniquePtr(env, tmp);
125 *name_ptr = reinterpret_cast<char*>(tmp);
126 }
127
128 JvmtiUniquePtr signature_copy;
129 if (signature_ptr != nullptr) {
130 const art::Signature sig = art_method->GetSignature();
131 std::string str = sig.ToString();
132 unsigned char* tmp;
133 jvmtiError ret = CopyString(env, str.c_str(), &tmp);
134 if (ret != ERR(NONE)) {
135 return ret;
136 }
137 signature_copy = MakeJvmtiUniquePtr(env, tmp);
138 *signature_ptr = reinterpret_cast<char*>(tmp);
139 }
140
141 // TODO: Support generic signature.
Andreas Gampe862bdd82016-11-18 13:31:13 -0800142 if (generic_ptr != nullptr) {
143 *generic_ptr = nullptr;
Andreas Gampe27dfa052017-02-16 15:04:36 -0800144 if (!art_method->GetDeclaringClass()->IsProxyClass()) {
145 art::mirror::ObjectArray<art::mirror::String>* str_array =
146 art::annotations::GetSignatureAnnotationForMethod(art_method);
147 if (str_array != nullptr) {
148 std::ostringstream oss;
149 for (int32_t i = 0; i != str_array->GetLength(); ++i) {
150 oss << str_array->Get(i)->ToModifiedUtf8();
151 }
152 std::string output_string = oss.str();
153 unsigned char* tmp;
154 jvmtiError ret = CopyString(env, output_string.c_str(), &tmp);
155 if (ret != ERR(NONE)) {
156 return ret;
157 }
158 *generic_ptr = reinterpret_cast<char*>(tmp);
159 } else if (soa.Self()->IsExceptionPending()) {
160 // TODO: Should we report an error here?
161 soa.Self()->ClearException();
162 }
163 }
Andreas Gampe862bdd82016-11-18 13:31:13 -0800164 }
Andreas Gampe3c252f02016-10-27 18:25:17 -0700165
166 // Everything is fine, release the buffers.
167 name_copy.release();
168 signature_copy.release();
169
170 return ERR(NONE);
171}
172
Andreas Gampe368a2082016-10-28 17:33:13 -0700173jvmtiError MethodUtil::GetMethodDeclaringClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
174 jmethodID method,
175 jclass* declaring_class_ptr) {
176 if (declaring_class_ptr == nullptr) {
177 return ERR(NULL_POINTER);
178 }
179
Andreas Gampe13b27842016-11-07 16:48:23 -0800180 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe368a2082016-10-28 17:33:13 -0700181 // Note: No GetInterfaceMethodIfProxy, we want to actual class.
182
Andreas Gampe13b27842016-11-07 16:48:23 -0800183 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe368a2082016-10-28 17:33:13 -0700184 art::mirror::Class* klass = art_method->GetDeclaringClass();
185 *declaring_class_ptr = soa.AddLocalReference<jclass>(klass);
186
187 return ERR(NONE);
188}
189
Andreas Gampef71832e2017-01-09 11:38:04 -0800190jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
191 jmethodID method,
192 jlocation* start_location_ptr,
193 jlocation* end_location_ptr) {
194 if (method == nullptr) {
195 return ERR(INVALID_METHODID);
196 }
197 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
198
199 if (art_method->IsNative()) {
200 return ERR(NATIVE_METHOD);
201 }
202
203 if (start_location_ptr == nullptr || end_location_ptr == nullptr) {
204 return ERR(NULL_POINTER);
205 }
206
207 art::ScopedObjectAccess soa(art::Thread::Current());
208 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
209 // This isn't specified as an error case, so return 0/0.
210 *start_location_ptr = 0;
211 *end_location_ptr = 0;
212 return ERR(NONE);
213 }
214
215 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
216 *start_location_ptr = 0;
217 *end_location_ptr = art_method->GetCodeItem()->insns_size_in_code_units_ - 1;
218
219 return ERR(NONE);
220}
221
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700222jvmtiError MethodUtil::GetMethodModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
223 jmethodID method,
224 jint* modifiers_ptr) {
225 if (modifiers_ptr == nullptr) {
226 return ERR(NULL_POINTER);
227 }
228
Andreas Gampe13b27842016-11-07 16:48:23 -0800229 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700230 uint32_t modifiers = art_method->GetAccessFlags();
231
232 // Note: Keep this code in sync with Executable.fixMethodFlags.
233 if ((modifiers & art::kAccAbstract) != 0) {
234 modifiers &= ~art::kAccNative;
235 }
236 modifiers &= ~art::kAccSynchronized;
237 if ((modifiers & art::kAccDeclaredSynchronized) != 0) {
238 modifiers |= art::kAccSynchronized;
239 }
240 modifiers &= art::kAccJavaFlagsMask;
241
242 *modifiers_ptr = modifiers;
243 return ERR(NONE);
244}
245
Andreas Gampeda3e5612016-12-13 19:00:53 -0800246using LineNumberContext = std::vector<jvmtiLineNumberEntry>;
247
248static bool CollectLineNumbers(void* void_context, const art::DexFile::PositionInfo& entry) {
249 LineNumberContext* context = reinterpret_cast<LineNumberContext*>(void_context);
250 jvmtiLineNumberEntry jvmti_entry = { static_cast<jlocation>(entry.address_),
251 static_cast<jint>(entry.line_) };
252 context->push_back(jvmti_entry);
253 return false; // Collect all, no early exit.
254}
255
256jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
257 jmethodID method,
258 jint* entry_count_ptr,
259 jvmtiLineNumberEntry** table_ptr) {
260 if (method == nullptr) {
261 return ERR(NULL_POINTER);
262 }
263 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
264 DCHECK(!art_method->IsRuntimeMethod());
265
266 const art::DexFile::CodeItem* code_item;
267 const art::DexFile* dex_file;
268 {
269 art::ScopedObjectAccess soa(art::Thread::Current());
270
271 if (art_method->IsProxyMethod()) {
272 return ERR(ABSENT_INFORMATION);
273 }
274 if (art_method->IsNative()) {
275 return ERR(NATIVE_METHOD);
276 }
277 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
278 return ERR(NULL_POINTER);
279 }
280
281 code_item = art_method->GetCodeItem();
282 dex_file = art_method->GetDexFile();
283 DCHECK(code_item != nullptr) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
284 }
285
286 LineNumberContext context;
287 bool success = dex_file->DecodeDebugPositionInfo(code_item, CollectLineNumbers, &context);
288 if (!success) {
289 return ERR(ABSENT_INFORMATION);
290 }
291
292 unsigned char* data;
293 jlong mem_size = context.size() * sizeof(jvmtiLineNumberEntry);
294 jvmtiError alloc_error = env->Allocate(mem_size, &data);
295 if (alloc_error != ERR(NONE)) {
296 return alloc_error;
297 }
298 *table_ptr = reinterpret_cast<jvmtiLineNumberEntry*>(data);
299 memcpy(*table_ptr, context.data(), mem_size);
300 *entry_count_ptr = static_cast<jint>(context.size());
301
302 return ERR(NONE);
303}
304
Andreas Gampefdeef522017-01-09 14:40:25 -0800305template <typename T>
306static jvmtiError IsMethodT(jvmtiEnv* env ATTRIBUTE_UNUSED,
307 jmethodID method,
308 T test,
309 jboolean* is_t_ptr) {
310 if (method == nullptr) {
311 return ERR(INVALID_METHODID);
312 }
313 if (is_t_ptr == nullptr) {
314 return ERR(NULL_POINTER);
315 }
316
317 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
318 *is_t_ptr = test(art_method) ? JNI_TRUE : JNI_FALSE;
319
320 return ERR(NONE);
321}
322
323jvmtiError MethodUtil::IsMethodNative(jvmtiEnv* env, jmethodID m, jboolean* is_native_ptr) {
324 auto test = [](art::ArtMethod* method) {
325 return method->IsNative();
326 };
327 return IsMethodT(env, m, test, is_native_ptr);
328}
329
330jvmtiError MethodUtil::IsMethodObsolete(jvmtiEnv* env, jmethodID m, jboolean* is_obsolete_ptr) {
331 auto test = [](art::ArtMethod* method) {
332 return method->IsObsolete();
333 };
334 return IsMethodT(env, m, test, is_obsolete_ptr);
335}
336
337jvmtiError MethodUtil::IsMethodSynthetic(jvmtiEnv* env, jmethodID m, jboolean* is_synthetic_ptr) {
338 auto test = [](art::ArtMethod* method) {
339 return method->IsSynthetic();
340 };
341 return IsMethodT(env, m, test, is_synthetic_ptr);
342}
343
Andreas Gampe3c252f02016-10-27 18:25:17 -0700344} // namespace openjdkjvmti