1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <limits>
18 #include <memory>
19
20 #include "jni.h"
21 #include "jvmti.h"
22
23 // Test infrastructure
24 #include "jvmti_helper.h"
25 #include "test_env.h"
26
27 // Slicer's headers have code that triggers these warnings. b/65298177
28 #pragma clang diagnostic push
29 #pragma clang diagnostic ignored "-Wsign-compare"
30 #pragma clang diagnostic ignored "-Wunused-parameter"
31 #include "slicer/instrumentation.h"
32 #include "slicer/reader.h"
33 #include "slicer/writer.h"
34 #pragma clang diagnostic pop
35
36 namespace art {
37 namespace Test1959RedefineObjectInstrument {
38
39 // Just pull it out of the dex file but don't bother changing anything.
RedefineObjectHook(jvmtiEnv * jvmti_env,JNIEnv * env,jclass class_being_redefined ATTRIBUTE_UNUSED,jobject loader ATTRIBUTE_UNUSED,const char * name,jobject protection_domain ATTRIBUTE_UNUSED,jint class_data_len,const unsigned char * class_data,jint * new_class_data_len,unsigned char ** new_class_data)40 static void JNICALL RedefineObjectHook(jvmtiEnv *jvmti_env,
41 JNIEnv* env,
42 jclass class_being_redefined ATTRIBUTE_UNUSED,
43 jobject loader ATTRIBUTE_UNUSED,
44 const char* name,
45 jobject protection_domain ATTRIBUTE_UNUSED,
46 jint class_data_len,
47 const unsigned char* class_data,
48 jint* new_class_data_len,
49 unsigned char** new_class_data) {
50 if (strcmp(name, "java/lang/Object") != 0) {
51 return;
52 }
53
54 dex::Reader reader(class_data, class_data_len);
55 dex::u4 class_index = reader.FindClassIndex("Ljava/lang/Object;");
56 if (class_index == dex::kNoIndex) {
57 env->ThrowNew(env->FindClass("java/lang/RuntimeException"),
58 "Failed to find object in dex file!");
59 return;
60 }
61
62 reader.CreateClassIr(class_index);
63 auto dex_ir = reader.GetIr();
64 dex::Writer writer(dex_ir);
65
66 class JvmtiAllocator : public dex::Writer::Allocator {
67 public:
68 explicit JvmtiAllocator(jvmtiEnv* jvmti) : jvmti_(jvmti) {}
69
70 void* Allocate(size_t size) override {
71 unsigned char* res = nullptr;
72 jvmti_->Allocate(size, &res);
73 return res;
74 }
75
76 void Free(void* ptr) override {
77 jvmti_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
78 }
79
80 private:
81 jvmtiEnv* jvmti_;
82 };
83 JvmtiAllocator allocator(jvmti_env);
84 size_t new_size;
85 *new_class_data = writer.CreateImage(&allocator, &new_size);
86 if (new_size > std::numeric_limits<jint>::max()) {
87 *new_class_data = nullptr;
88 env->ThrowNew(env->FindClass("java/lang/RuntimeException"),
89 "transform result is too large!");
90 return;
91 }
92 *new_class_data_len = static_cast<jint>(new_size);
93 }
94
Java_Main_forceRedefine(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jclass obj_class,jthread thr)95 extern "C" JNIEXPORT void JNICALL Java_Main_forceRedefine(JNIEnv* env,
96 jclass klass ATTRIBUTE_UNUSED,
97 jclass obj_class,
98 jthread thr) {
99 if (IsJVM()) {
100 // RI so don't do anything.
101 return;
102 }
103 jvmtiCapabilities caps {.can_retransform_classes = 1};
104 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
105 return;
106 }
107 jvmtiEventCallbacks cb {.ClassFileLoadHook = RedefineObjectHook };
108 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)))) {
109 return;
110 }
111 if (JvmtiErrorToException(env,
112 jvmti_env,
113 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
114 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
115 thr))) {
116 return;
117 }
118 if (JvmtiErrorToException(env,
119 jvmti_env,
120 jvmti_env->RetransformClasses(1, &obj_class))) {
121 return;
122 }
123 if (JvmtiErrorToException(env,
124 jvmti_env,
125 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
126 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
127 thr))) {
128 return;
129 }
130 }
131
132 } // namespace Test1959RedefineObjectInstrument
133 } // namespace art
134
135