1 /* Copyright (C) 2016 The Android Open Source Project
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This file implements interfaces from the file jvmti.h. This implementation
5 * is licensed under the same terms as the file jvmti.h. The
6 * copyright and license information for the file jvmti.h follows.
7 *
8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10 *
11 * This code is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 only, as
13 * published by the Free Software Foundation. Oracle designates this
14 * particular file as subject to the "Classpath" exception as provided
15 * by Oracle in the LICENSE file that accompanied this code.
16 *
17 * This code is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * version 2 for more details (a copy is included in the LICENSE file that
21 * accompanied this code).
22 *
23 * You should have received a copy of the GNU General Public License version
24 * 2 along with this work; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28 * or visit www.oracle.com if you need additional information or have any
29 * questions.
30 */
31
32 #include "ti_class.h"
33
34 #include "android-base/stringprintf.h"
35
36 #include <mutex>
37 #include <unordered_set>
38
39 #include "art_jvmti.h"
40 #include "base/array_ref.h"
41 #include "base/macros.h"
42 #include "base/utils.h"
43 #include "class_linker.h"
44 #include "class_loader_utils.h"
45 #include "class_table-inl.h"
46 #include "common_throws.h"
47 #include "dex/art_dex_file_loader.h"
48 #include "dex/dex_file_annotations.h"
49 #include "dex/dex_file_loader.h"
50 #include "dex/primitive.h"
51 #include "events-inl.h"
52 #include "fixed_up_dex_file.h"
53 #include "gc/heap-visit-objects-inl.h"
54 #include "gc/heap.h"
55 #include "gc_root.h"
56 #include "handle.h"
57 #include "jni_env_ext-inl.h"
58 #include "jni_internal.h"
59 #include "mirror/array-inl.h"
60 #include "mirror/class-inl.h"
61 #include "mirror/class_ext.h"
62 #include "mirror/object-inl.h"
63 #include "mirror/object-refvisitor-inl.h"
64 #include "mirror/object_array-inl.h"
65 #include "mirror/object_reference.h"
66 #include "mirror/reference.h"
67 #include "nativehelper/scoped_local_ref.h"
68 #include "reflection.h"
69 #include "runtime.h"
70 #include "runtime_callbacks.h"
71 #include "scoped_thread_state_change-inl.h"
72 #include "thread-current-inl.h"
73 #include "thread_list.h"
74 #include "ti_class_loader-inl.h"
75 #include "ti_phase.h"
76 #include "ti_redefine.h"
77 #include "well_known_classes.h"
78
79 namespace openjdkjvmti {
80
81 using android::base::StringPrintf;
82
MakeSingleDexFile(art::Thread * self,const char * descriptor,const std::string & orig_location,jint final_len,const unsigned char * final_dex_data)83 static std::unique_ptr<const art::DexFile> MakeSingleDexFile(art::Thread* self,
84 const char* descriptor,
85 const std::string& orig_location,
86 jint final_len,
87 const unsigned char* final_dex_data)
88 REQUIRES_SHARED(art::Locks::mutator_lock_) {
89 // Make the mmap
90 std::string error_msg;
91 art::ArrayRef<const unsigned char> final_data(final_dex_data, final_len);
92 std::unique_ptr<art::MemMap> map(Redefiner::MoveDataToMemMap(orig_location,
93 final_data,
94 &error_msg));
95 if (map.get() == nullptr) {
96 LOG(WARNING) << "Unable to allocate mmap for redefined dex file! Error was: " << error_msg;
97 self->ThrowOutOfMemoryError(StringPrintf(
98 "Unable to allocate dex file for transformation of %s", descriptor).c_str());
99 return nullptr;
100 }
101
102 // Make a dex-file
103 if (map->Size() < sizeof(art::DexFile::Header)) {
104 LOG(WARNING) << "Could not read dex file header because dex_data was too short";
105 art::ThrowClassFormatError(nullptr,
106 "Unable to read transformed dex file of %s",
107 descriptor);
108 return nullptr;
109 }
110 uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_;
111 std::string map_name = map->GetName();
112 const art::ArtDexFileLoader dex_file_loader;
113 std::unique_ptr<const art::DexFile> dex_file(dex_file_loader.Open(map_name,
114 checksum,
115 std::move(map),
116 /*verify*/true,
117 /*verify_checksum*/true,
118 &error_msg));
119 if (dex_file.get() == nullptr) {
120 LOG(WARNING) << "Unable to load modified dex file for " << descriptor << ": " << error_msg;
121 art::ThrowClassFormatError(nullptr,
122 "Unable to read transformed dex file of %s because %s",
123 descriptor,
124 error_msg.c_str());
125 return nullptr;
126 }
127 if (dex_file->NumClassDefs() != 1) {
128 LOG(WARNING) << "Dex file contains more than 1 class_def. Ignoring.";
129 // TODO Throw some other sort of error here maybe?
130 art::ThrowClassFormatError(
131 nullptr,
132 "Unable to use transformed dex file of %s because it contained too many classes",
133 descriptor);
134 return nullptr;
135 }
136 return dex_file;
137 }
138
139 // A deleter that acts like the jvmtiEnv->Deallocate so that asan does not get tripped up.
140 // TODO We should everything use the actual jvmtiEnv->Allocate/Deallocate functions once we can
141 // figure out which env to use.
142 template <typename T>
143 class FakeJvmtiDeleter {
144 public:
FakeJvmtiDeleter()145 FakeJvmtiDeleter() {}
146
147 FakeJvmtiDeleter(FakeJvmtiDeleter&) = default;
148 FakeJvmtiDeleter(FakeJvmtiDeleter&&) = default;
149 FakeJvmtiDeleter& operator=(const FakeJvmtiDeleter&) = default;
150
operator ()(const U * ptr) const151 template <typename U> void operator()(const U* ptr) const {
152 if (ptr != nullptr) {
153 free(const_cast<U*>(ptr));
154 }
155 }
156 };
157
158 struct ClassCallback : public art::ClassLoadCallback {
ClassPreDefineopenjdkjvmti::ClassCallback159 void ClassPreDefine(const char* descriptor,
160 art::Handle<art::mirror::Class> klass,
161 art::Handle<art::mirror::ClassLoader> class_loader,
162 const art::DexFile& initial_dex_file,
163 const art::DexFile::ClassDef& initial_class_def ATTRIBUTE_UNUSED,
164 /*out*/art::DexFile const** final_dex_file,
165 /*out*/art::DexFile::ClassDef const** final_class_def)
166 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
167 bool is_enabled =
168 event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kClassFileLoadHookRetransformable) ||
169 event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
170 if (!is_enabled) {
171 return;
172 }
173 if (descriptor[0] != 'L') {
174 // It is a primitive or array. Just return
175 return;
176 }
177 jvmtiPhase phase = PhaseUtil::GetPhaseUnchecked();
178 if (UNLIKELY(phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE)) {
179 // We want to wait until we are at least in the START phase so that all WellKnownClasses and
180 // mirror classes have been initialized and loaded. The runtime relies on these classes having
181 // specific fields and methods present. Since PreDefine hooks don't need to abide by this
182 // restriction we will simply not send the event for these classes.
183 LOG(WARNING) << "Ignoring load of class <" << descriptor << "> as it is being loaded during "
184 << "runtime initialization.";
185 return;
186 }
187
188 art::Thread* self = art::Thread::Current();
189 ArtClassDefinition def;
190 def.InitFirstLoad(descriptor, class_loader, initial_dex_file);
191
192 // Call all non-retransformable agents.
193 Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
194 event_handler, self, &def);
195
196 std::vector<unsigned char> post_non_retransform;
197 if (def.IsModified()) {
198 // Copy the dex data after the non-retransformable events.
199 post_non_retransform.resize(def.GetDexData().size());
200 memcpy(post_non_retransform.data(), def.GetDexData().data(), post_non_retransform.size());
201 }
202
203 // Call all retransformable agents.
204 Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
205 event_handler, self, &def);
206
207 if (def.IsModified()) {
208 LOG(WARNING) << "Changing class " << descriptor;
209 art::StackHandleScope<2> hs(self);
210 // Save the results of all the non-retransformable agents.
211 // First allocate the ClassExt
212 art::Handle<art::mirror::ClassExt> ext(hs.NewHandle(klass->EnsureExtDataPresent(self)));
213 // Make sure we have a ClassExt. This is fine even though we are a temporary since it will
214 // get copied.
215 if (ext.IsNull()) {
216 // We will just return failure if we fail to allocate
217 LOG(WARNING) << "Could not allocate ext-data for class '" << descriptor << "'. "
218 << "Aborting transformation since we will be unable to store it.";
219 self->AssertPendingOOMException();
220 return;
221 }
222
223 // Allocate the byte array to store the dex file bytes in.
224 art::MutableHandle<art::mirror::Object> arr(hs.NewHandle<art::mirror::Object>(nullptr));
225 if (post_non_retransform.empty() && strcmp(descriptor, "Ljava/lang/Long;") != 0) {
226 // we didn't have any non-retransformable agents. We can just cache a pointer to the
227 // initial_dex_file. It will be kept live by the class_loader.
228 jlong dex_ptr = reinterpret_cast<uintptr_t>(&initial_dex_file);
229 art::JValue val;
230 val.SetJ(dex_ptr);
231 arr.Assign(art::BoxPrimitive(art::Primitive::kPrimLong, val));
232 } else {
233 arr.Assign(art::mirror::ByteArray::AllocateAndFill(
234 self,
235 reinterpret_cast<const signed char*>(post_non_retransform.data()),
236 post_non_retransform.size()));
237 }
238 if (arr.IsNull()) {
239 LOG(WARNING) << "Unable to allocate memory for initial dex-file. Aborting transformation";
240 self->AssertPendingOOMException();
241 return;
242 }
243
244 std::unique_ptr<const art::DexFile> dex_file(MakeSingleDexFile(self,
245 descriptor,
246 initial_dex_file.GetLocation(),
247 def.GetDexData().size(),
248 def.GetDexData().data()));
249 if (dex_file.get() == nullptr) {
250 return;
251 }
252
253 // TODO Check Redefined dex file for all invariants.
254 LOG(WARNING) << "Dex file created by class-definition time transformation of "
255 << descriptor << " is not checked for all retransformation invariants.";
256
257 if (!ClassLoaderHelper::AddToClassLoader(self, class_loader, dex_file.get())) {
258 LOG(ERROR) << "Unable to add " << descriptor << " to class loader!";
259 return;
260 }
261
262 // Actually set the ClassExt's original bytes once we have actually succeeded.
263 ext->SetOriginalDexFile(arr.Get());
264 // Set the return values
265 *final_class_def = &dex_file->GetClassDef(0);
266 *final_dex_file = dex_file.release();
267 }
268 }
269
ClassLoadopenjdkjvmti::ClassCallback270 void ClassLoad(art::Handle<art::mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_) {
271 if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kClassLoad)) {
272 art::Thread* thread = art::Thread::Current();
273 ScopedLocalRef<jclass> jklass(thread->GetJniEnv(),
274 thread->GetJniEnv()->AddLocalReference<jclass>(klass.Get()));
275 art::ObjPtr<art::mirror::Object> peer(thread->GetPeer());
276 ScopedLocalRef<jthread> thread_jni(
277 thread->GetJniEnv(),
278 peer.IsNull() ? nullptr : thread->GetJniEnv()->AddLocalReference<jthread>(peer));
279 event_handler->DispatchEvent<ArtJvmtiEvent::kClassLoad>(
280 thread,
281 static_cast<JNIEnv*>(thread->GetJniEnv()),
282 thread_jni.get(),
283 jklass.get());
284 if (klass->IsTemp()) {
285 AddTempClass(thread, jklass.get());
286 }
287 }
288 }
289
ClassPrepareopenjdkjvmti::ClassCallback290 void ClassPrepare(art::Handle<art::mirror::Class> temp_klass,
291 art::Handle<art::mirror::Class> klass)
292 REQUIRES_SHARED(art::Locks::mutator_lock_) {
293 if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kClassPrepare)) {
294 art::Thread* thread = art::Thread::Current();
295 if (temp_klass.Get() != klass.Get()) {
296 DCHECK(temp_klass->IsTemp());
297 DCHECK(temp_klass->IsRetired());
298 HandleTempClass(thread, temp_klass, klass);
299 }
300 ScopedLocalRef<jclass> jklass(thread->GetJniEnv(),
301 thread->GetJniEnv()->AddLocalReference<jclass>(klass.Get()));
302 art::ObjPtr<art::mirror::Object> peer(thread->GetPeer());
303 ScopedLocalRef<jthread> thread_jni(
304 thread->GetJniEnv(),
305 peer.IsNull() ? nullptr : thread->GetJniEnv()->AddLocalReference<jthread>(peer));
306 event_handler->DispatchEvent<ArtJvmtiEvent::kClassPrepare>(
307 thread,
308 static_cast<JNIEnv*>(thread->GetJniEnv()),
309 thread_jni.get(),
310 jklass.get());
311 }
312 }
313
314 // To support parallel class-loading, we need to perform some locking dances here. Namely,
315 // the fixup stage must not be holding the temp_classes lock when it fixes up the system
316 // (as that requires suspending all mutators).
317
AddTempClassopenjdkjvmti::ClassCallback318 void AddTempClass(art::Thread* self, jclass klass) {
319 std::unique_lock<std::mutex> mu(temp_classes_lock);
320 jclass global_klass = reinterpret_cast<jclass>(self->GetJniEnv()->NewGlobalRef(klass));
321 temp_classes.push_back(global_klass);
322 }
323
HandleTempClassopenjdkjvmti::ClassCallback324 void HandleTempClass(art::Thread* self,
325 art::Handle<art::mirror::Class> temp_klass,
326 art::Handle<art::mirror::Class> klass)
327 REQUIRES_SHARED(art::Locks::mutator_lock_) {
328 bool requires_fixup = false;
329 {
330 std::unique_lock<std::mutex> mu(temp_classes_lock);
331 if (temp_classes.empty()) {
332 return;
333 }
334
335 for (auto it = temp_classes.begin(); it != temp_classes.end(); ++it) {
336 if (temp_klass.Get() == art::ObjPtr<art::mirror::Class>::DownCast(self->DecodeJObject(*it))) {
337 self->GetJniEnv()->DeleteGlobalRef(*it);
338 temp_classes.erase(it);
339 requires_fixup = true;
340 break;
341 }
342 }
343 }
344 if (requires_fixup) {
345 FixupTempClass(self, temp_klass, klass);
346 }
347 }
348
FixupTempClassopenjdkjvmti::ClassCallback349 void FixupTempClass(art::Thread* self,
350 art::Handle<art::mirror::Class> temp_klass,
351 art::Handle<art::mirror::Class> klass)
352 REQUIRES_SHARED(art::Locks::mutator_lock_) {
353 // Suspend everything.
354 art::gc::Heap* heap = art::Runtime::Current()->GetHeap();
355 if (heap->IsGcConcurrentAndMoving()) {
356 // Need to take a heap dump while GC isn't running. See the
357 // comment in Heap::VisitObjects().
358 heap->IncrementDisableMovingGC(self);
359 }
360 {
361 art::ScopedThreadSuspension sts(self, art::kWaitingForVisitObjects);
362 art::ScopedSuspendAll ssa("FixupTempClass");
363
364 art::mirror::Class* input = temp_klass.Get();
365 art::mirror::Class* output = klass.Get();
366
367 FixupGlobalReferenceTables(input, output);
368 FixupLocalReferenceTables(self, input, output);
369 FixupHeap(input, output);
370 }
371 if (heap->IsGcConcurrentAndMoving()) {
372 heap->DecrementDisableMovingGC(self);
373 }
374 }
375
376 class RootUpdater : public art::RootVisitor {
377 public:
RootUpdater(const art::mirror::Class * input,art::mirror::Class * output)378 RootUpdater(const art::mirror::Class* input, art::mirror::Class* output)
379 : input_(input), output_(output) {}
380
VisitRoots(art::mirror::Object *** roots,size_t count,const art::RootInfo & info ATTRIBUTE_UNUSED)381 void VisitRoots(art::mirror::Object*** roots,
382 size_t count,
383 const art::RootInfo& info ATTRIBUTE_UNUSED)
384 OVERRIDE {
385 for (size_t i = 0; i != count; ++i) {
386 if (*roots[i] == input_) {
387 *roots[i] = output_;
388 }
389 }
390 }
391
VisitRoots(art::mirror::CompressedReference<art::mirror::Object> ** roots,size_t count,const art::RootInfo & info ATTRIBUTE_UNUSED)392 void VisitRoots(art::mirror::CompressedReference<art::mirror::Object>** roots,
393 size_t count,
394 const art::RootInfo& info ATTRIBUTE_UNUSED)
395 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
396 for (size_t i = 0; i != count; ++i) {
397 if (roots[i]->AsMirrorPtr() == input_) {
398 roots[i]->Assign(output_);
399 }
400 }
401 }
402
403 private:
404 const art::mirror::Class* input_;
405 art::mirror::Class* output_;
406 };
407
FixupGlobalReferenceTablesopenjdkjvmti::ClassCallback408 void FixupGlobalReferenceTables(art::mirror::Class* input, art::mirror::Class* output)
409 REQUIRES(art::Locks::mutator_lock_) {
410 art::JavaVMExt* java_vm = art::Runtime::Current()->GetJavaVM();
411
412 // Fix up the global table with a root visitor.
413 RootUpdater global_update(input, output);
414 java_vm->VisitRoots(&global_update);
415
416 class WeakGlobalUpdate : public art::IsMarkedVisitor {
417 public:
418 WeakGlobalUpdate(art::mirror::Class* root_input, art::mirror::Class* root_output)
419 : input_(root_input), output_(root_output) {}
420
421 art::mirror::Object* IsMarked(art::mirror::Object* obj) OVERRIDE {
422 if (obj == input_) {
423 return output_;
424 }
425 return obj;
426 }
427
428 private:
429 const art::mirror::Class* input_;
430 art::mirror::Class* output_;
431 };
432 WeakGlobalUpdate weak_global_update(input, output);
433 java_vm->SweepJniWeakGlobals(&weak_global_update);
434 }
435
FixupLocalReferenceTablesopenjdkjvmti::ClassCallback436 void FixupLocalReferenceTables(art::Thread* self,
437 art::mirror::Class* input,
438 art::mirror::Class* output)
439 REQUIRES(art::Locks::mutator_lock_) {
440 class LocalUpdate {
441 public:
442 LocalUpdate(const art::mirror::Class* root_input, art::mirror::Class* root_output)
443 : input_(root_input), output_(root_output) {}
444
445 static void Callback(art::Thread* t, void* arg) REQUIRES(art::Locks::mutator_lock_) {
446 LocalUpdate* local = reinterpret_cast<LocalUpdate*>(arg);
447
448 // Fix up the local table with a root visitor.
449 RootUpdater local_update(local->input_, local->output_);
450 t->GetJniEnv()->VisitJniLocalRoots(
451 &local_update, art::RootInfo(art::kRootJNILocal, t->GetThreadId()));
452 }
453
454 private:
455 const art::mirror::Class* input_;
456 art::mirror::Class* output_;
457 };
458 LocalUpdate local_upd(input, output);
459 art::MutexLock mu(self, *art::Locks::thread_list_lock_);
460 art::Runtime::Current()->GetThreadList()->ForEach(LocalUpdate::Callback, &local_upd);
461 }
462
FixupHeapopenjdkjvmti::ClassCallback463 void FixupHeap(art::mirror::Class* input, art::mirror::Class* output)
464 REQUIRES(art::Locks::mutator_lock_) {
465 class HeapFixupVisitor {
466 public:
467 HeapFixupVisitor(const art::mirror::Class* root_input, art::mirror::Class* root_output)
468 : input_(root_input), output_(root_output) {}
469
470 void operator()(art::mirror::Object* src,
471 art::MemberOffset field_offset,
472 bool is_static ATTRIBUTE_UNUSED) const
473 REQUIRES_SHARED(art::Locks::mutator_lock_) {
474 art::mirror::HeapReference<art::mirror::Object>* trg =
475 src->GetFieldObjectReferenceAddr(field_offset);
476 if (trg->AsMirrorPtr() == input_) {
477 DCHECK_NE(field_offset.Uint32Value(), 0u); // This shouldn't be the class field of
478 // an object.
479 trg->Assign(output_);
480 }
481 }
482
483 void operator()(art::ObjPtr<art::mirror::Class> klass ATTRIBUTE_UNUSED,
484 art::ObjPtr<art::mirror::Reference> reference) const
485 REQUIRES_SHARED(art::Locks::mutator_lock_) {
486 art::mirror::Object* val = reference->GetReferent();
487 if (val == input_) {
488 reference->SetReferent<false>(output_);
489 }
490 }
491
492 void VisitRoot(art::mirror::CompressedReference<art::mirror::Object>* root ATTRIBUTE_UNUSED)
493 const {
494 LOG(FATAL) << "Unreachable";
495 }
496
497 void VisitRootIfNonNull(
498 art::mirror::CompressedReference<art::mirror::Object>* root ATTRIBUTE_UNUSED) const {
499 LOG(FATAL) << "Unreachable";
500 }
501
502 private:
503 const art::mirror::Class* input_;
504 art::mirror::Class* output_;
505 };
506 HeapFixupVisitor hfv(input, output);
507 auto object_visitor = [&](art::mirror::Object* obj) {
508 obj->VisitReferences<false>(hfv, hfv); // Visit references, not native roots.
509 };
510 art::Runtime::Current()->GetHeap()->VisitObjectsPaused(object_visitor);
511 }
512
513 // A set of all the temp classes we have handed out. We have to fix up references to these.
514 // For simplicity, we store the temp classes as JNI global references in a vector. Normally a
515 // Prepare event will closely follow, so the vector should be small.
516 std::mutex temp_classes_lock;
517 std::vector<jclass> temp_classes;
518
519 EventHandler* event_handler = nullptr;
520 };
521
522 ClassCallback gClassCallback;
523
Register(EventHandler * handler)524 void ClassUtil::Register(EventHandler* handler) {
525 gClassCallback.event_handler = handler;
526 art::ScopedThreadStateChange stsc(art::Thread::Current(),
527 art::ThreadState::kWaitingForDebuggerToAttach);
528 art::ScopedSuspendAll ssa("Add load callback");
529 art::Runtime::Current()->GetRuntimeCallbacks()->AddClassLoadCallback(&gClassCallback);
530 }
531
Unregister()532 void ClassUtil::Unregister() {
533 art::ScopedThreadStateChange stsc(art::Thread::Current(),
534 art::ThreadState::kWaitingForDebuggerToAttach);
535 art::ScopedSuspendAll ssa("Remove thread callback");
536 art::Runtime* runtime = art::Runtime::Current();
537 runtime->GetRuntimeCallbacks()->RemoveClassLoadCallback(&gClassCallback);
538 }
539
GetClassFields(jvmtiEnv * env,jclass jklass,jint * field_count_ptr,jfieldID ** fields_ptr)540 jvmtiError ClassUtil::GetClassFields(jvmtiEnv* env,
541 jclass jklass,
542 jint* field_count_ptr,
543 jfieldID** fields_ptr) {
544 art::ScopedObjectAccess soa(art::Thread::Current());
545 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
546 if (klass == nullptr) {
547 return ERR(INVALID_CLASS);
548 }
549
550 // Check if this class is a temporary class object used for loading. Since we are seeing it the
551 // class must not have been prepared yet since otherwise the fixup would have gotten the jobject
552 // to point to the final class object.
553 if (klass->IsTemp() || klass->IsRetired()) {
554 return ERR(CLASS_NOT_PREPARED);
555 }
556
557 if (field_count_ptr == nullptr || fields_ptr == nullptr) {
558 return ERR(NULL_POINTER);
559 }
560
561 art::IterationRange<art::StrideIterator<art::ArtField>> ifields = klass->GetIFields();
562 art::IterationRange<art::StrideIterator<art::ArtField>> sfields = klass->GetSFields();
563 size_t array_size = klass->NumInstanceFields() + klass->NumStaticFields();
564
565 unsigned char* out_ptr;
566 jvmtiError allocError = env->Allocate(array_size * sizeof(jfieldID), &out_ptr);
567 if (allocError != ERR(NONE)) {
568 return allocError;
569 }
570 jfieldID* field_array = reinterpret_cast<jfieldID*>(out_ptr);
571
572 size_t array_idx = 0;
573 for (art::ArtField& field : sfields) {
574 field_array[array_idx] = art::jni::EncodeArtField(&field);
575 ++array_idx;
576 }
577 for (art::ArtField& field : ifields) {
578 field_array[array_idx] = art::jni::EncodeArtField(&field);
579 ++array_idx;
580 }
581
582 *field_count_ptr = static_cast<jint>(array_size);
583 *fields_ptr = field_array;
584
585 return ERR(NONE);
586 }
587
GetClassMethods(jvmtiEnv * env,jclass jklass,jint * method_count_ptr,jmethodID ** methods_ptr)588 jvmtiError ClassUtil::GetClassMethods(jvmtiEnv* env,
589 jclass jklass,
590 jint* method_count_ptr,
591 jmethodID** methods_ptr) {
592 art::ScopedObjectAccess soa(art::Thread::Current());
593 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
594 if (klass == nullptr) {
595 return ERR(INVALID_CLASS);
596 }
597
598 // Check if this class is a temporary class object used for loading. Since we are seeing it the
599 // class must not have been prepared yet since otherwise the fixup would have gotten the jobject
600 // to point to the final class object.
601 if (klass->IsTemp() || klass->IsRetired()) {
602 return ERR(CLASS_NOT_PREPARED);
603 }
604
605 if (method_count_ptr == nullptr || methods_ptr == nullptr) {
606 return ERR(NULL_POINTER);
607 }
608
609 size_t array_size = klass->NumDeclaredVirtualMethods() + klass->NumDirectMethods();
610 unsigned char* out_ptr;
611 jvmtiError allocError = env->Allocate(array_size * sizeof(jmethodID), &out_ptr);
612 if (allocError != ERR(NONE)) {
613 return allocError;
614 }
615 jmethodID* method_array = reinterpret_cast<jmethodID*>(out_ptr);
616
617 if (art::kIsDebugBuild) {
618 size_t count = 0;
619 for (auto& m ATTRIBUTE_UNUSED : klass->GetDeclaredMethods(art::kRuntimePointerSize)) {
620 count++;
621 }
622 CHECK_EQ(count, klass->NumDirectMethods() + klass->NumDeclaredVirtualMethods());
623 }
624
625 size_t array_idx = 0;
626 for (auto& m : klass->GetDeclaredMethods(art::kRuntimePointerSize)) {
627 method_array[array_idx] = art::jni::EncodeArtMethod(&m);
628 ++array_idx;
629 }
630
631 *method_count_ptr = static_cast<jint>(array_size);
632 *methods_ptr = method_array;
633
634 return ERR(NONE);
635 }
636
GetImplementedInterfaces(jvmtiEnv * env,jclass jklass,jint * interface_count_ptr,jclass ** interfaces_ptr)637 jvmtiError ClassUtil::GetImplementedInterfaces(jvmtiEnv* env,
638 jclass jklass,
639 jint* interface_count_ptr,
640 jclass** interfaces_ptr) {
641 art::ScopedObjectAccess soa(art::Thread::Current());
642 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
643 if (klass == nullptr) {
644 return ERR(INVALID_CLASS);
645 }
646
647 if (interface_count_ptr == nullptr || interfaces_ptr == nullptr) {
648 return ERR(NULL_POINTER);
649 }
650
651 // Need to handle array specifically. Arrays implement Serializable and Cloneable, but the
652 // spec says these should not be reported.
653 if (klass->IsArrayClass()) {
654 *interface_count_ptr = 0;
655 *interfaces_ptr = nullptr; // TODO: Should we allocate a dummy here?
656 return ERR(NONE);
657 }
658
659 size_t array_size = klass->NumDirectInterfaces();
660 unsigned char* out_ptr;
661 jvmtiError allocError = env->Allocate(array_size * sizeof(jclass), &out_ptr);
662 if (allocError != ERR(NONE)) {
663 return allocError;
664 }
665 jclass* interface_array = reinterpret_cast<jclass*>(out_ptr);
666
667 art::StackHandleScope<1> hs(soa.Self());
668 art::Handle<art::mirror::Class> h_klass(hs.NewHandle(klass));
669
670 for (uint32_t idx = 0; idx != array_size; ++idx) {
671 art::ObjPtr<art::mirror::Class> inf_klass =
672 art::mirror::Class::ResolveDirectInterface(soa.Self(), h_klass, idx);
673 if (inf_klass == nullptr) {
674 soa.Self()->ClearException();
675 env->Deallocate(out_ptr);
676 // TODO: What is the right error code here?
677 return ERR(INTERNAL);
678 }
679 interface_array[idx] = soa.AddLocalReference<jclass>(inf_klass);
680 }
681
682 *interface_count_ptr = static_cast<jint>(array_size);
683 *interfaces_ptr = interface_array;
684
685 return ERR(NONE);
686 }
687
GetClassSignature(jvmtiEnv * env,jclass jklass,char ** signature_ptr,char ** generic_ptr)688 jvmtiError ClassUtil::GetClassSignature(jvmtiEnv* env,
689 jclass jklass,
690 char** signature_ptr,
691 char** generic_ptr) {
692 art::ScopedObjectAccess soa(art::Thread::Current());
693 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
694 if (klass == nullptr) {
695 return ERR(INVALID_CLASS);
696 }
697
698 JvmtiUniquePtr<char[]> sig_copy;
699 if (signature_ptr != nullptr) {
700 std::string storage;
701 const char* descriptor = klass->GetDescriptor(&storage);
702
703 jvmtiError ret;
704 sig_copy = CopyString(env, descriptor, &ret);
705 if (sig_copy == nullptr) {
706 return ret;
707 }
708 *signature_ptr = sig_copy.get();
709 }
710
711 if (generic_ptr != nullptr) {
712 *generic_ptr = nullptr;
713 if (!klass->IsProxyClass() && klass->GetDexCache() != nullptr) {
714 art::StackHandleScope<1> hs(soa.Self());
715 art::Handle<art::mirror::Class> h_klass = hs.NewHandle(klass);
716 art::mirror::ObjectArray<art::mirror::String>* str_array =
717 art::annotations::GetSignatureAnnotationForClass(h_klass);
718 if (str_array != nullptr) {
719 std::ostringstream oss;
720 for (int32_t i = 0; i != str_array->GetLength(); ++i) {
721 oss << str_array->Get(i)->ToModifiedUtf8();
722 }
723 std::string output_string = oss.str();
724 jvmtiError ret;
725 JvmtiUniquePtr<char[]> copy = CopyString(env, output_string.c_str(), &ret);
726 if (copy == nullptr) {
727 return ret;
728 }
729 *generic_ptr = copy.release();
730 } else if (soa.Self()->IsExceptionPending()) {
731 // TODO: Should we report an error here?
732 soa.Self()->ClearException();
733 }
734 }
735 }
736
737 // Everything is fine, release the buffers.
738 sig_copy.release();
739
740 return ERR(NONE);
741 }
742
GetClassStatus(jvmtiEnv * env ATTRIBUTE_UNUSED,jclass jklass,jint * status_ptr)743 jvmtiError ClassUtil::GetClassStatus(jvmtiEnv* env ATTRIBUTE_UNUSED,
744 jclass jklass,
745 jint* status_ptr) {
746 art::ScopedObjectAccess soa(art::Thread::Current());
747 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
748 if (klass == nullptr) {
749 return ERR(INVALID_CLASS);
750 }
751
752 if (status_ptr == nullptr) {
753 return ERR(NULL_POINTER);
754 }
755
756 if (klass->IsArrayClass()) {
757 *status_ptr = JVMTI_CLASS_STATUS_ARRAY;
758 } else if (klass->IsPrimitive()) {
759 *status_ptr = JVMTI_CLASS_STATUS_PRIMITIVE;
760 } else {
761 *status_ptr = JVMTI_CLASS_STATUS_VERIFIED; // All loaded classes are structurally verified.
762 // This is finicky. If there's an error, we'll say it wasn't prepared.
763 if (klass->IsResolved()) {
764 *status_ptr |= JVMTI_CLASS_STATUS_PREPARED;
765 }
766 if (klass->IsInitialized()) {
767 *status_ptr |= JVMTI_CLASS_STATUS_INITIALIZED;
768 }
769 // Technically the class may be erroneous for other reasons, but we do not have enough info.
770 if (klass->IsErroneous()) {
771 *status_ptr |= JVMTI_CLASS_STATUS_ERROR;
772 }
773 }
774
775 return ERR(NONE);
776 }
777
778 template <typename T>
ClassIsT(jclass jklass,T test,jboolean * is_t_ptr)779 static jvmtiError ClassIsT(jclass jklass, T test, jboolean* is_t_ptr) {
780 art::ScopedObjectAccess soa(art::Thread::Current());
781 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
782 if (klass == nullptr) {
783 return ERR(INVALID_CLASS);
784 }
785
786 if (is_t_ptr == nullptr) {
787 return ERR(NULL_POINTER);
788 }
789
790 *is_t_ptr = test(klass) ? JNI_TRUE : JNI_FALSE;
791 return ERR(NONE);
792 }
793
IsInterface(jvmtiEnv * env ATTRIBUTE_UNUSED,jclass jklass,jboolean * is_interface_ptr)794 jvmtiError ClassUtil::IsInterface(jvmtiEnv* env ATTRIBUTE_UNUSED,
795 jclass jklass,
796 jboolean* is_interface_ptr) {
797 auto test = [](art::ObjPtr<art::mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_) {
798 return klass->IsInterface();
799 };
800 return ClassIsT(jklass, test, is_interface_ptr);
801 }
802
IsArrayClass(jvmtiEnv * env ATTRIBUTE_UNUSED,jclass jklass,jboolean * is_array_class_ptr)803 jvmtiError ClassUtil::IsArrayClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
804 jclass jklass,
805 jboolean* is_array_class_ptr) {
806 auto test = [](art::ObjPtr<art::mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_) {
807 return klass->IsArrayClass();
808 };
809 return ClassIsT(jklass, test, is_array_class_ptr);
810 }
811
812 // Keep this in sync with Class.getModifiers().
ClassGetModifiers(art::Thread * self,art::ObjPtr<art::mirror::Class> klass)813 static uint32_t ClassGetModifiers(art::Thread* self, art::ObjPtr<art::mirror::Class> klass)
814 REQUIRES_SHARED(art::Locks::mutator_lock_) {
815 if (klass->IsArrayClass()) {
816 uint32_t component_modifiers = ClassGetModifiers(self, klass->GetComponentType());
817 if ((component_modifiers & art::kAccInterface) != 0) {
818 component_modifiers &= ~(art::kAccInterface | art::kAccStatic);
819 }
820 return art::kAccAbstract | art::kAccFinal | component_modifiers;
821 }
822
823 uint32_t modifiers = klass->GetAccessFlags() & art::kAccJavaFlagsMask;
824
825 art::StackHandleScope<1> hs(self);
826 art::Handle<art::mirror::Class> h_klass(hs.NewHandle(klass));
827 return art::mirror::Class::GetInnerClassFlags(h_klass, modifiers);
828 }
829
GetClassModifiers(jvmtiEnv * env ATTRIBUTE_UNUSED,jclass jklass,jint * modifiers_ptr)830 jvmtiError ClassUtil::GetClassModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
831 jclass jklass,
832 jint* modifiers_ptr) {
833 art::ScopedObjectAccess soa(art::Thread::Current());
834 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
835 if (klass == nullptr) {
836 return ERR(INVALID_CLASS);
837 }
838
839 if (modifiers_ptr == nullptr) {
840 return ERR(NULL_POINTER);
841 }
842
843 *modifiers_ptr = ClassGetModifiers(soa.Self(), klass);
844
845 return ERR(NONE);
846 }
847
GetClassLoader(jvmtiEnv * env ATTRIBUTE_UNUSED,jclass jklass,jobject * classloader_ptr)848 jvmtiError ClassUtil::GetClassLoader(jvmtiEnv* env ATTRIBUTE_UNUSED,
849 jclass jklass,
850 jobject* classloader_ptr) {
851 art::ScopedObjectAccess soa(art::Thread::Current());
852 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
853 if (klass == nullptr) {
854 return ERR(INVALID_CLASS);
855 }
856
857 if (classloader_ptr == nullptr) {
858 return ERR(NULL_POINTER);
859 }
860
861 *classloader_ptr = soa.AddLocalReference<jobject>(klass->GetClassLoader());
862
863 return ERR(NONE);
864 }
865
866 // Copies unique class descriptors into the classes list from dex_files.
CopyClassDescriptors(jvmtiEnv * env,const std::vector<const art::DexFile * > & dex_files,jint * count_ptr,char *** classes)867 static jvmtiError CopyClassDescriptors(jvmtiEnv* env,
868 const std::vector<const art::DexFile*>& dex_files,
869 /*out*/jint* count_ptr,
870 /*out*/char*** classes) {
871 jvmtiError res = OK;
872 std::set<art::StringPiece> unique_descriptors;
873 std::vector<const char*> descriptors;
874 auto add_descriptor = [&](const char* desc) {
875 // Don't add duplicates.
876 if (res == OK && unique_descriptors.find(desc) == unique_descriptors.end()) {
877 // The desc will remain valid since we hold a ref to the class_loader.
878 unique_descriptors.insert(desc);
879 descriptors.push_back(CopyString(env, desc, &res).release());
880 }
881 };
882 for (const art::DexFile* dex_file : dex_files) {
883 uint32_t num_defs = dex_file->NumClassDefs();
884 for (uint32_t i = 0; i < num_defs; i++) {
885 add_descriptor(dex_file->GetClassDescriptor(dex_file->GetClassDef(i)));
886 }
887 }
888 char** out_data = nullptr;
889 if (res == OK) {
890 res = env->Allocate(sizeof(char*) * descriptors.size(),
891 reinterpret_cast<unsigned char**>(&out_data));
892 }
893 if (res != OK) {
894 env->Deallocate(reinterpret_cast<unsigned char*>(out_data));
895 // Failed to allocate. Cleanup everything.
896 for (const char* data : descriptors) {
897 env->Deallocate(reinterpret_cast<unsigned char*>(const_cast<char*>(data)));
898 }
899 descriptors.clear();
900 return res;
901 }
902 // Everything is good.
903 memcpy(out_data, descriptors.data(), sizeof(char*) * descriptors.size());
904 *count_ptr = static_cast<jint>(descriptors.size());
905 *classes = out_data;
906 return OK;
907 }
908
GetClassLoaderClassDescriptors(jvmtiEnv * env,jobject loader,jint * count_ptr,char *** classes)909 jvmtiError ClassUtil::GetClassLoaderClassDescriptors(jvmtiEnv* env,
910 jobject loader,
911 /*out*/jint* count_ptr,
912 /*out*/char*** classes) {
913 art::Thread* self = art::Thread::Current();
914 if (env == nullptr) {
915 return ERR(INVALID_ENVIRONMENT);
916 } else if (self == nullptr) {
917 return ERR(UNATTACHED_THREAD);
918 } else if (count_ptr == nullptr || classes == nullptr) {
919 return ERR(NULL_POINTER);
920 }
921 art::JNIEnvExt* jnienv = self->GetJniEnv();
922 if (loader == nullptr ||
923 jnienv->IsInstanceOf(loader, art::WellKnownClasses::java_lang_BootClassLoader)) {
924 // We can just get the dex files directly for the boot class path.
925 return CopyClassDescriptors(env,
926 art::Runtime::Current()->GetClassLinker()->GetBootClassPath(),
927 count_ptr,
928 classes);
929 }
930 if (!jnienv->IsInstanceOf(loader, art::WellKnownClasses::java_lang_ClassLoader)) {
931 return ERR(ILLEGAL_ARGUMENT);
932 } else if (!jnienv->IsInstanceOf(loader,
933 art::WellKnownClasses::dalvik_system_BaseDexClassLoader)) {
934 LOG(ERROR) << "GetClassLoaderClassDescriptors is only implemented for BootClassPath and "
935 << "dalvik.system.BaseDexClassLoader class loaders";
936 // TODO Possibly return OK With no classes would be better since these ones cannot have any
937 // real classes associated with them.
938 return ERR(NOT_IMPLEMENTED);
939 }
940
941 art::ScopedObjectAccess soa(self);
942 art::StackHandleScope<1> hs(self);
943 art::Handle<art::mirror::ClassLoader> class_loader(
944 hs.NewHandle(soa.Decode<art::mirror::ClassLoader>(loader)));
945 std::vector<const art::DexFile*> dex_files;
946 art::VisitClassLoaderDexFiles(
947 soa,
948 class_loader,
949 [&](const art::DexFile* dex_file) {
950 dex_files.push_back(dex_file);
951 return true; // Continue with other dex files.
952 });
953 // We hold the loader so the dex files won't go away until after this call at worst.
954 return CopyClassDescriptors(env, dex_files, count_ptr, classes);
955 }
956
GetClassLoaderClasses(jvmtiEnv * env,jobject initiating_loader,jint * class_count_ptr,jclass ** classes_ptr)957 jvmtiError ClassUtil::GetClassLoaderClasses(jvmtiEnv* env,
958 jobject initiating_loader,
959 jint* class_count_ptr,
960 jclass** classes_ptr) {
961 UNUSED(env, initiating_loader, class_count_ptr, classes_ptr);
962
963 if (class_count_ptr == nullptr || classes_ptr == nullptr) {
964 return ERR(NULL_POINTER);
965 }
966 art::Thread* self = art::Thread::Current();
967 if (!self->GetJniEnv()->IsInstanceOf(initiating_loader,
968 art::WellKnownClasses::java_lang_ClassLoader)) {
969 return ERR(ILLEGAL_ARGUMENT);
970 }
971 if (self->GetJniEnv()->IsInstanceOf(initiating_loader,
972 art::WellKnownClasses::java_lang_BootClassLoader)) {
973 // Need to use null for the BootClassLoader.
974 initiating_loader = nullptr;
975 }
976
977 art::ScopedObjectAccess soa(self);
978 art::ObjPtr<art::mirror::ClassLoader> class_loader =
979 soa.Decode<art::mirror::ClassLoader>(initiating_loader);
980
981 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
982
983 art::ReaderMutexLock mu(self, *art::Locks::classlinker_classes_lock_);
984
985 art::ClassTable* class_table = class_linker->ClassTableForClassLoader(class_loader);
986 if (class_table == nullptr) {
987 // Nothing loaded.
988 *class_count_ptr = 0;
989 *classes_ptr = nullptr;
990 return ERR(NONE);
991 }
992
993 struct ClassTableCount {
994 bool operator()(art::ObjPtr<art::mirror::Class> klass) {
995 DCHECK(klass != nullptr);
996 ++count;
997 return true;
998 }
999
1000 size_t count = 0;
1001 };
1002 ClassTableCount ctc;
1003 class_table->Visit(ctc);
1004
1005 if (ctc.count == 0) {
1006 // Nothing loaded.
1007 *class_count_ptr = 0;
1008 *classes_ptr = nullptr;
1009 return ERR(NONE);
1010 }
1011
1012 unsigned char* data;
1013 jvmtiError data_result = env->Allocate(ctc.count * sizeof(jclass), &data);
1014 if (data_result != ERR(NONE)) {
1015 return data_result;
1016 }
1017 jclass* class_array = reinterpret_cast<jclass*>(data);
1018
1019 struct ClassTableFill {
1020 bool operator()(art::ObjPtr<art::mirror::Class> klass)
1021 REQUIRES_SHARED(art::Locks::mutator_lock_) {
1022 DCHECK(klass != nullptr);
1023 DCHECK_LT(count, ctc_ref.count);
1024 local_class_array[count++] = soa_ptr->AddLocalReference<jclass>(klass);
1025 return true;
1026 }
1027
1028 jclass* local_class_array;
1029 const ClassTableCount& ctc_ref;
1030 art::ScopedObjectAccess* soa_ptr;
1031 size_t count;
1032 };
1033 ClassTableFill ctf = { class_array, ctc, &soa, 0 };
1034 class_table->Visit(ctf);
1035 DCHECK_EQ(ctc.count, ctf.count);
1036
1037 *class_count_ptr = ctc.count;
1038 *classes_ptr = class_array;
1039
1040 return ERR(NONE);
1041 }
1042
GetClassVersionNumbers(jvmtiEnv * env ATTRIBUTE_UNUSED,jclass jklass,jint * minor_version_ptr,jint * major_version_ptr)1043 jvmtiError ClassUtil::GetClassVersionNumbers(jvmtiEnv* env ATTRIBUTE_UNUSED,
1044 jclass jklass,
1045 jint* minor_version_ptr,
1046 jint* major_version_ptr) {
1047 art::ScopedObjectAccess soa(art::Thread::Current());
1048 if (jklass == nullptr) {
1049 return ERR(INVALID_CLASS);
1050 }
1051 art::ObjPtr<art::mirror::Object> jklass_obj = soa.Decode<art::mirror::Object>(jklass);
1052 if (!jklass_obj->IsClass()) {
1053 return ERR(INVALID_CLASS);
1054 }
1055 art::ObjPtr<art::mirror::Class> klass = jklass_obj->AsClass();
1056 if (klass->IsPrimitive() || klass->IsArrayClass()) {
1057 return ERR(INVALID_CLASS);
1058 }
1059
1060 if (minor_version_ptr == nullptr || major_version_ptr == nullptr) {
1061 return ERR(NULL_POINTER);
1062 }
1063
1064 // Note: proxies will show the dex file version of java.lang.reflect.Proxy, as that is
1065 // what their dex cache copies from.
1066 uint32_t version = klass->GetDexFile().GetHeader().GetVersion();
1067
1068 *major_version_ptr = static_cast<jint>(version);
1069 *minor_version_ptr = 0;
1070
1071 return ERR(NONE);
1072 }
1073
GetSourceFileName(jvmtiEnv * env,jclass jklass,char ** source_name_ptr)1074 jvmtiError ClassUtil::GetSourceFileName(jvmtiEnv* env, jclass jklass, char** source_name_ptr) {
1075 art::ScopedObjectAccess soa(art::Thread::Current());
1076 if (jklass == nullptr) {
1077 return ERR(INVALID_CLASS);
1078 }
1079 art::ObjPtr<art::mirror::Object> jklass_obj = soa.Decode<art::mirror::Object>(jklass);
1080 if (!jklass_obj->IsClass()) {
1081 return ERR(INVALID_CLASS);
1082 }
1083 art::ObjPtr<art::mirror::Class> klass = jklass_obj->AsClass();
1084 if (klass->IsPrimitive() || klass->IsArrayClass()) {
1085 return ERR(ABSENT_INFORMATION);
1086 }
1087 JvmtiUniquePtr<char[]> source_copy;
1088 const char* file_name = klass->GetSourceFile();
1089 if (file_name == nullptr) {
1090 return ERR(ABSENT_INFORMATION);
1091 }
1092 jvmtiError ret;
1093 source_copy = CopyString(env, file_name, &ret);
1094 if (source_copy == nullptr) {
1095 return ret;
1096 }
1097 *source_name_ptr = source_copy.release();
1098 return OK;
1099 }
1100
GetSourceDebugExtension(jvmtiEnv * env,jclass jklass,char ** source_debug_extension_ptr)1101 jvmtiError ClassUtil::GetSourceDebugExtension(jvmtiEnv* env,
1102 jclass jklass,
1103 char** source_debug_extension_ptr) {
1104 art::ScopedObjectAccess soa(art::Thread::Current());
1105 if (jklass == nullptr) {
1106 return ERR(INVALID_CLASS);
1107 }
1108 art::ObjPtr<art::mirror::Object> jklass_obj = soa.Decode<art::mirror::Object>(jklass);
1109 if (!jklass_obj->IsClass()) {
1110 return ERR(INVALID_CLASS);
1111 }
1112 art::StackHandleScope<1> hs(art::Thread::Current());
1113 art::Handle<art::mirror::Class> klass(hs.NewHandle(jklass_obj->AsClass()));
1114 if (klass->IsPrimitive() || klass->IsArrayClass()) {
1115 return ERR(ABSENT_INFORMATION);
1116 }
1117 JvmtiUniquePtr<char[]> ext_copy;
1118 const char* data = art::annotations::GetSourceDebugExtension(klass);
1119 if (data == nullptr) {
1120 return ERR(ABSENT_INFORMATION);
1121 }
1122 jvmtiError ret;
1123 ext_copy = CopyString(env, data, &ret);
1124 if (ext_copy == nullptr) {
1125 return ret;
1126 }
1127 *source_debug_extension_ptr = ext_copy.release();
1128 return OK;
1129 }
1130
1131 } // namespace openjdkjvmti
1132