diff options
Diffstat (limited to 'runtime/openjdkjvmti/transform.cc')
-rw-r--r-- | runtime/openjdkjvmti/transform.cc | 136 |
1 files changed, 26 insertions, 110 deletions
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc index 2809cb6926..f5451254c0 100644 --- a/runtime/openjdkjvmti/transform.cc +++ b/runtime/openjdkjvmti/transform.cc @@ -38,7 +38,6 @@ #include "class_linker.h" #include "dex_file.h" #include "dex_file_types.h" -#include "events-inl.h" #include "gc_root-inl.h" #include "globals.h" #include "jni_env_ext-inl.h" @@ -53,76 +52,12 @@ #include "scoped_thread_state_change-inl.h" #include "stack.h" #include "thread_list.h" -#include "ti_redefine.h" #include "transform.h" #include "utf.h" #include "utils/dex_cache_arrays_layout-inl.h" namespace openjdkjvmti { -jvmtiError Transformer::RetransformClassesDirect( - ArtJvmTiEnv* env, - art::Thread* self, - /*in-out*/std::vector<ArtClassDefinition>* definitions) { - for (ArtClassDefinition& def : *definitions) { - jint new_len = -1; - unsigned char* new_data = nullptr; - // Static casts are so that we get the right template initialization for the special event - // handling code required by the ClassFileLoadHooks. - gEventHandler.DispatchEvent(self, - ArtJvmtiEvent::kClassFileLoadHookRetransformable, - GetJniEnv(env), - static_cast<jclass>(def.klass), - static_cast<jobject>(def.loader), - static_cast<const char*>(def.name.c_str()), - static_cast<jobject>(def.protection_domain), - static_cast<jint>(def.dex_len), - static_cast<const unsigned char*>(def.dex_data.get()), - static_cast<jint*>(&new_len), - static_cast<unsigned char**>(&new_data)); - def.SetNewDexData(env, new_len, new_data); - } - return OK; -} - -jvmtiError Transformer::RetransformClasses(ArtJvmTiEnv* env, - art::Runtime* runtime, - art::Thread* self, - jint class_count, - const jclass* classes, - /*out*/std::string* error_msg) { - if (env == nullptr) { - *error_msg = "env was null!"; - return ERR(INVALID_ENVIRONMENT); - } else if (class_count < 0) { - *error_msg = "class_count was less then 0"; - return ERR(ILLEGAL_ARGUMENT); - } else if (class_count == 0) { - // We don't actually need to do anything. Just return OK. - return OK; - } else if (classes == nullptr) { - *error_msg = "null classes!"; - return ERR(NULL_POINTER); - } - // A holder that will Deallocate all the class bytes buffers on destruction. - std::vector<ArtClassDefinition> definitions; - jvmtiError res = OK; - for (jint i = 0; i < class_count; i++) { - ArtClassDefinition def; - res = FillInTransformationData(env, classes[i], &def); - if (res != OK) { - return res; - } - definitions.push_back(std::move(def)); - } - res = RetransformClassesDirect(env, self, &definitions); - if (res != OK) { - return res; - } - return Redefiner::RedefineClassesDirect(env, runtime, self, definitions, error_msg); -} - -// TODO Move this somewhere else, ti_class? jvmtiError GetClassLocation(ArtJvmTiEnv* env, jclass klass, /*out*/std::string* location) { JNIEnv* jni_env = nullptr; jint ret = env->art_vm->GetEnv(reinterpret_cast<void**>(&jni_env), JNI_VERSION_1_1); @@ -138,61 +73,42 @@ jvmtiError GetClassLocation(ArtJvmTiEnv* env, jclass klass, /*out*/std::string* return OK; } -// TODO Implement this for real once transformed dex data is actually saved. -jvmtiError Transformer::GetDexDataForRetransformation(ArtJvmTiEnv* env, - art::Handle<art::mirror::Class> klass, - /*out*/jint* dex_data_len, - /*out*/unsigned char** dex_data) { - // TODO De-quicken the dex file before passing it to the agents. - LOG(WARNING) << "Dex file is not de-quickened yet! Quickened dex instructions might be present"; - LOG(WARNING) << "Caching of initial dex data is not yet performed! Dex data might have been " - << "transformed by agent already"; - const art::DexFile& dex = klass->GetDexFile(); - *dex_data_len = static_cast<jint>(dex.Size()); - unsigned char* new_dex_data = nullptr; - jvmtiError alloc_error = env->Allocate(*dex_data_len, &new_dex_data); - if (alloc_error != OK) { - return alloc_error; - } - // Copy the data into a temporary buffer. - memcpy(reinterpret_cast<void*>(new_dex_data), - reinterpret_cast<const void*>(dex.Begin()), - *dex_data_len); - *dex_data = new_dex_data; - return OK; -} - // TODO Move this function somewhere more appropriate. // Gets the data surrounding the given class. -// TODO Make this less magical. -jvmtiError Transformer::FillInTransformationData(ArtJvmTiEnv* env, - jclass klass, - ArtClassDefinition* def) { - JNIEnv* jni_env = GetJniEnv(env); - if (jni_env == nullptr) { +jvmtiError GetTransformationData(ArtJvmTiEnv* env, + jclass klass, + /*out*/std::string* location, + /*out*/JNIEnv** jni_env_ptr, + /*out*/jobject* loader, + /*out*/std::string* name, + /*out*/jobject* protection_domain, + /*out*/jint* data_len, + /*out*/unsigned char** dex_data) { + jint ret = env->art_vm->GetEnv(reinterpret_cast<void**>(jni_env_ptr), JNI_VERSION_1_1); + if (ret != JNI_OK) { // TODO Different error might be better? return ERR(INTERNAL); } + JNIEnv* jni_env = *jni_env_ptr; art::ScopedObjectAccess soa(jni_env); art::StackHandleScope<3> hs(art::Thread::Current()); art::Handle<art::mirror::Class> hs_klass(hs.NewHandle(soa.Decode<art::mirror::Class>(klass))); - if (hs_klass.IsNull()) { - return ERR(INVALID_CLASS); - } - def->klass = klass; - def->loader = soa.AddLocalReference<jobject>(hs_klass->GetClassLoader()); - def->name = art::mirror::Class::ComputeName(hs_klass)->ToModifiedUtf8(); + *loader = soa.AddLocalReference<jobject>(hs_klass->GetClassLoader()); + *name = art::mirror::Class::ComputeName(hs_klass)->ToModifiedUtf8(); // TODO is this always null? - def->protection_domain = nullptr; - if (def->dex_data.get() == nullptr) { - unsigned char* new_data; - jvmtiError res = GetDexDataForRetransformation(env, hs_klass, &def->dex_len, &new_data); - if (res == OK) { - def->dex_data = MakeJvmtiUniquePtr(env, new_data); - } else { - return res; - } + *protection_domain = nullptr; + const art::DexFile& dex = hs_klass->GetDexFile(); + *location = dex.GetLocation(); + *data_len = static_cast<jint>(dex.Size()); + // TODO We should maybe change env->Allocate to allow us to mprotect this memory and stop writes. + jvmtiError alloc_error = env->Allocate(*data_len, dex_data); + if (alloc_error != OK) { + return alloc_error; } + // Copy the data into a temporary buffer. + memcpy(reinterpret_cast<void*>(*dex_data), + reinterpret_cast<const void*>(dex.Begin()), + *data_len); return OK; } |