diff options
author | 2019-10-15 15:46:07 -0700 | |
---|---|---|
committer | 2019-10-30 16:53:25 -0700 | |
commit | d55b844e39c4d5eb1a56de6cb95c891659f8a27f (patch) | |
tree | ed2f7809528e8b44985edc12d75fb0965806045f /openjdkjvmti/ti_extension.cc | |
parent | 436c6f5fae95aae332361060778599d0ef24a167 (diff) |
Add more standard structural redefinition entrypoints
Add structural redefinition extension function and event that mirror
the 'RedefineClasses' function and 'ClassFileLoadHook' event. The new
extension function is called
'com.android.art.class.structurally_redefine_classes' and the new
extension event is called
'com.android.art.class.structural_dex_file_load_hook'.
These extensions are the preferred way to use structural redefinition.
Like the standard 'RedefineClasses' multiple classes may be redefined
at a time.
The structural_dex_file_load_hook is triggered prior to the
can_retransform_classes ClassFileLoadHook. It is triggered on all
classes, even ones that cannot be structurally changed by
class-loading, class redefinition or by calling the RetransformClasses
function.
Calling 'structurally_redefine_classes' with new definitions that do
not require structural changes will fall back to non-structural
redefinition.
Test: ./test.py --host
Bug: 134162467
Change-Id: If4810930470c5c6509cf6db779910006e114b39f
Diffstat (limited to 'openjdkjvmti/ti_extension.cc')
-rw-r--r-- | openjdkjvmti/ti_extension.cc | 69 |
1 files changed, 66 insertions, 3 deletions
diff --git a/openjdkjvmti/ti_extension.cc b/openjdkjvmti/ti_extension.cc index 5dc7445681..058a188630 100644 --- a/openjdkjvmti/ti_extension.cc +++ b/openjdkjvmti/ti_extension.cc @@ -30,6 +30,7 @@ #include <vector> +#include "jvmti.h" #include "ti_extension.h" #include "art_jvmti.h" @@ -45,6 +46,7 @@ #include "ti_monitor.h" #include "ti_redefine.h" #include "ti_search.h" +#include "transform.h" #include "thread-inl.h" @@ -416,7 +418,40 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env, return error; } - // StructurallyRedefineClass + // StructurallyRedefineClasses + error = add_extension( + reinterpret_cast<jvmtiExtensionFunction>(Redefiner::StructurallyRedefineClasses), + "com.android.art.class.structurally_redefine_classes", + "Entrypoint for structural class redefinition. Has the same signature as RedefineClasses." + " Currently this only supports adding new static fields to a class without any instance" + " fields or methods. After calling this com.android.art.structural_dex_file_load_hook" + " events will be triggered, followed by re-transformable ClassFileLoadHook events. After" + " this method completes subsequent RetransformClasses calls will use the input to this" + " function as the initial class definition.", + { + { "num_classes", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false }, + { "class_definitions", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CVOID, false }, + }, + { + ERR(CLASS_LOADER_UNSUPPORTED), + ERR(FAILS_VERIFICATION), + ERR(ILLEGAL_ARGUMENT), + ERR(INVALID_CLASS), + ERR(MUST_POSSESS_CAPABILITY), + ERR(MUST_POSSESS_CAPABILITY), + ERR(NULL_POINTER), + ERR(OUT_OF_MEMORY), + ERR(UNMODIFIABLE_CLASS), + ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED), + ERR(UNSUPPORTED_REDEFINITION_METHOD_ADDED), + ERR(UNSUPPORTED_REDEFINITION_METHOD_DELETED), + ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED), + }); + if (error != ERR(NONE)) { + return error; + } + + // StructurallyRedefineClassDirect error = add_extension( reinterpret_cast<jvmtiExtensionFunction>(Redefiner::StructurallyRedefineClassDirect), "com.android.art.UNSAFE.class.structurally_redefine_class_direct", @@ -494,7 +529,7 @@ jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env, const char* id, const char* short_description, const std::vector<CParamInfo>& params) { - DCHECK(IsExtensionEvent(extension_event_index)); + DCHECK(IsExtensionEvent(extension_event_index)) << static_cast<jint>(extension_event_index); jvmtiExtensionEventInfo event_info; jvmtiError error; @@ -592,7 +627,35 @@ jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env, if (error != OK) { return error; } - + art::Runtime* runtime = art::Runtime::Current(); + if (runtime->GetJniIdType() == art::JniIdType::kIndices && + (runtime->GetInstrumentation()->IsForcedInterpretOnly() || runtime->IsJavaDebuggable())) { + error = add_extension( + ArtJvmtiEvent::kStructuralDexFileLoadHook, + "com.android.art.class.structural_dex_file_load_hook", + "Called during class load, after a 'RetransformClasses' call, or after a 'RedefineClasses'" + " call in order to allow the agent to modify the class. This event is called after any" + " non-can_retransform_classes ClassFileLoadHookEvents and before any" + " can_retransform_classes ClassFileLoadHookEvents. The transformations applied are" + " restricted in the same way that transformations applied via the " + " 'com.android.art.class.structurally_redefine_classes' extension function. The arguments" + " to the event are identical to the ones in the ClassFileLoadHook and have the same" + " semantics.", + { + { "jni_env", JVMTI_KIND_IN, JVMTI_TYPE_JNIENV, false }, + { "class_being_redefined", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true }, + { "loader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, false }, + { "name", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, false }, + { "protection_domain", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, true }, + { "dex_data_len", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false }, + { "dex_data", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false }, + { "new_dex_data_len", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false }, + { "new_dex_data", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, true }, + }); + } else { + LOG(INFO) << "debuggable & jni-type indices are required to implement structural " + << "class redefinition extensions."; + } // Copy into output buffer. *extension_count_ptr = ext_vector.size(); |