summaryrefslogtreecommitdiff
path: root/openjdkjvmti/ti_class.cc
diff options
context:
space:
mode:
Diffstat (limited to 'openjdkjvmti/ti_class.cc')
-rw-r--r--openjdkjvmti/ti_class.cc104
1 files changed, 103 insertions, 1 deletions
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index 4d54d756d5..d510ae5dd4 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -69,7 +69,7 @@
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"
#include "thread_list.h"
-#include "ti_class_loader.h"
+#include "ti_class_loader-inl.h"
#include "ti_phase.h"
#include "ti_redefine.h"
#include "utils.h"
@@ -862,6 +862,108 @@ jvmtiError ClassUtil::GetClassLoader(jvmtiEnv* env ATTRIBUTE_UNUSED,
return ERR(NONE);
}
+// Copies unique class descriptors into the classes list from dex_files.
+static jvmtiError CopyClassDescriptors(jvmtiEnv* env,
+ const std::vector<const art::DexFile*>& dex_files,
+ /*out*/jint* count_ptr,
+ /*out*/char*** classes) {
+ jvmtiError res = OK;
+ std::set<art::StringPiece> unique_descriptors;
+ std::vector<const char*> descriptors;
+ auto add_descriptor = [&](const char* desc) {
+ // Don't add duplicates.
+ if (res == OK && unique_descriptors.find(desc) == unique_descriptors.end()) {
+ // The desc will remain valid since we hold a ref to the class_loader.
+ unique_descriptors.insert(desc);
+ descriptors.push_back(CopyString(env, desc, &res).release());
+ }
+ };
+ for (const art::DexFile* dex_file : dex_files) {
+ uint32_t num_defs = dex_file->NumClassDefs();
+ for (uint32_t i = 0; i < num_defs; i++) {
+ add_descriptor(dex_file->GetClassDescriptor(dex_file->GetClassDef(i)));
+ }
+ }
+ char** out_data = nullptr;
+ if (res == OK) {
+ res = env->Allocate(sizeof(char*) * descriptors.size(),
+ reinterpret_cast<unsigned char**>(&out_data));
+ }
+ if (res != OK) {
+ env->Deallocate(reinterpret_cast<unsigned char*>(out_data));
+ // Failed to allocate. Cleanup everything.
+ for (const char* data : descriptors) {
+ env->Deallocate(reinterpret_cast<unsigned char*>(const_cast<char*>(data)));
+ }
+ descriptors.clear();
+ return res;
+ }
+ // Everything is good.
+ memcpy(out_data, descriptors.data(), sizeof(char*) * descriptors.size());
+ *count_ptr = static_cast<jint>(descriptors.size());
+ *classes = out_data;
+ return OK;
+}
+
+jvmtiError ClassUtil::GetClassLoaderClassDescriptors(jvmtiEnv* env,
+ jobject loader,
+ /*out*/jint* count_ptr,
+ /*out*/char*** classes) {
+ art::Thread* self = art::Thread::Current();
+ if (env == nullptr) {
+ return ERR(INVALID_ENVIRONMENT);
+ } else if (self == nullptr) {
+ return ERR(UNATTACHED_THREAD);
+ } else if (count_ptr == nullptr || classes == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ if (loader == nullptr ||
+ jnienv->IsInstanceOf(loader, art::WellKnownClasses::java_lang_BootClassLoader)) {
+ // We can just get the dex files directly for the boot class path.
+ return CopyClassDescriptors(env,
+ art::Runtime::Current()->GetClassLinker()->GetBootClassPath(),
+ count_ptr,
+ classes);
+ }
+ if (!jnienv->IsInstanceOf(loader, art::WellKnownClasses::java_lang_ClassLoader)) {
+ return ERR(ILLEGAL_ARGUMENT);
+ } else if (!jnienv->IsInstanceOf(loader,
+ art::WellKnownClasses::dalvik_system_BaseDexClassLoader)) {
+ LOG(ERROR) << "GetClassLoaderClassDescriptors is only implemented for BootClassPath and "
+ << "dalvik.system.BaseDexClassLoader class loaders";
+ // TODO Possibly return OK With no classes would be better since these ones cannot have any
+ // real classes associated with them.
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ art::ScopedObjectAccess soa(self);
+ art::StackHandleScope<1> hs(self);
+ art::Handle<art::mirror::ClassLoader> class_loader(
+ hs.NewHandle(soa.Decode<art::mirror::ClassLoader>(loader)));
+ std::vector<const art::DexFile*> dex_files;
+ ClassLoaderHelper::VisitDexFileObjects(
+ self,
+ class_loader,
+ [&] (art::ObjPtr<art::mirror::Object> dex_file) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ art::StackHandleScope<2> hs(self);
+ art::Handle<art::mirror::Object> h_dex_file(hs.NewHandle(dex_file));
+ art::Handle<art::mirror::LongArray> cookie(
+ hs.NewHandle(ClassLoaderHelper::GetDexFileCookie(h_dex_file)));
+ size_t num_elements = cookie->GetLength();
+ // We need to skip over the oat_file that's the first element. The other elements are all
+ // dex files.
+ for (size_t i = 1; i < num_elements; i++) {
+ dex_files.push_back(
+ reinterpret_cast<const art::DexFile*>(static_cast<uintptr_t>(cookie->Get(i))));
+ }
+ // Iterate over all dex files.
+ return true;
+ });
+ // We hold the loader so the dex files won't go away until after this call at worst.
+ return CopyClassDescriptors(env, dex_files, count_ptr, classes);
+}
+
jvmtiError ClassUtil::GetClassLoaderClasses(jvmtiEnv* env,
jobject initiating_loader,
jint* class_count_ptr,