blob: 2c6d3eda008f1deaf5f3a927b41af2fee2c98613 [file] [log] [blame]
Alex Light1e07ca62016-12-02 11:40:56 -08001/*
2 * Copyright (C) 2016 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 "ti-agent/common_helper.h"
18
19#include <stdio.h>
Alex Light460d1b42017-01-10 15:37:17 +000020#include <sstream>
Alex Light1e07ca62016-12-02 11:40:56 -080021
Alex Lightdba61482016-12-21 08:20:29 -080022#include "art_method.h"
Alex Light1e07ca62016-12-02 11:40:56 -080023#include "jni.h"
24#include "openjdkjvmti/jvmti.h"
Alex Lightdba61482016-12-21 08:20:29 -080025#include "scoped_thread_state_change-inl.h"
26#include "stack.h"
Alex Light1e07ca62016-12-02 11:40:56 -080027#include "ti-agent/common_load.h"
28#include "utils.h"
29
30namespace art {
31bool RuntimeIsJVM;
32
33bool IsJVM() {
34 return RuntimeIsJVM;
35}
36
37void SetAllCapabilities(jvmtiEnv* env) {
38 jvmtiCapabilities caps;
39 env->GetPotentialCapabilities(&caps);
40 env->AddCapabilities(&caps);
41}
42
Andreas Gampe1bdaf732017-01-09 19:21:06 -080043bool JvmtiErrorToException(JNIEnv* env, jvmtiError error) {
44 if (error == JVMTI_ERROR_NONE) {
45 return false;
46 }
47
48 ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
49 if (rt_exception.get() == nullptr) {
50 // CNFE should be pending.
51 return true;
52 }
53
54 char* err;
55 jvmti_env->GetErrorName(error, &err);
56
57 env->ThrowNew(rt_exception.get(), err);
58
59 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
60 return true;
61}
62
Alex Light1e07ca62016-12-02 11:40:56 -080063namespace common_redefine {
64
Alex Light0e692732017-01-10 15:00:05 -080065static void throwRedefinitionError(jvmtiEnv* jvmti,
66 JNIEnv* env,
67 jint num_targets,
68 jclass* target,
69 jvmtiError res) {
Alex Light460d1b42017-01-10 15:37:17 +000070 std::stringstream err;
Alex Light460d1b42017-01-10 15:37:17 +000071 char* error = nullptr;
72 jvmti->GetErrorName(res, &error);
Alex Light0e692732017-01-10 15:00:05 -080073 err << "Failed to redefine class";
74 if (num_targets > 1) {
75 err << "es";
76 }
77 err << " <";
78 for (jint i = 0; i < num_targets; i++) {
79 char* signature = nullptr;
80 char* generic = nullptr;
81 jvmti->GetClassSignature(target[i], &signature, &generic);
82 if (i != 0) {
83 err << ", ";
84 }
85 err << signature;
86 jvmti->Deallocate(reinterpret_cast<unsigned char*>(signature));
87 jvmti->Deallocate(reinterpret_cast<unsigned char*>(generic));
88 }
89 err << "> due to " << error;
Alex Light460d1b42017-01-10 15:37:17 +000090 std::string message = err.str();
Alex Light460d1b42017-01-10 15:37:17 +000091 jvmti->Deallocate(reinterpret_cast<unsigned char*>(error));
92 env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
93}
94
Alex Light0e692732017-01-10 15:00:05 -080095static void DoMultiClassRedefine(jvmtiEnv* jvmti_env,
96 JNIEnv* env,
97 jint num_redefines,
98 jclass* targets,
99 jbyteArray* class_file_bytes,
100 jbyteArray* dex_file_bytes) {
101 std::vector<jvmtiClassDefinition> defs;
102 for (jint i = 0; i < num_redefines; i++) {
103 jbyteArray desired_array = IsJVM() ? class_file_bytes[i] : dex_file_bytes[i];
104 jint len = static_cast<jint>(env->GetArrayLength(desired_array));
105 const unsigned char* redef_bytes = reinterpret_cast<const unsigned char*>(
106 env->GetByteArrayElements(desired_array, nullptr));
107 defs.push_back({targets[i], static_cast<jint>(len), redef_bytes});
Alex Light1e07ca62016-12-02 11:40:56 -0800108 }
Alex Light0e692732017-01-10 15:00:05 -0800109 jvmtiError res = jvmti_env->RedefineClasses(num_redefines, defs.data());
Alex Light1e07ca62016-12-02 11:40:56 -0800110 if (res != JVMTI_ERROR_NONE) {
Alex Light0e692732017-01-10 15:00:05 -0800111 throwRedefinitionError(jvmti_env, env, num_redefines, targets, res);
Alex Light1e07ca62016-12-02 11:40:56 -0800112 }
113}
114
Alex Light0e692732017-01-10 15:00:05 -0800115static void DoClassRedefine(jvmtiEnv* jvmti_env,
116 JNIEnv* env,
117 jclass target,
118 jbyteArray class_file_bytes,
119 jbyteArray dex_file_bytes) {
120 return DoMultiClassRedefine(jvmti_env, env, 1, &target, &class_file_bytes, &dex_file_bytes);
121}
122
Alex Light1e07ca62016-12-02 11:40:56 -0800123// Magic JNI export that classes can use for redefining classes.
124// To use classes should declare this as a native function with signature (Ljava/lang/Class;[B[B)V
125extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRedefinition(JNIEnv* env,
126 jclass,
127 jclass target,
128 jbyteArray class_file_bytes,
129 jbyteArray dex_file_bytes) {
Alex Light0e692732017-01-10 15:00:05 -0800130 DoClassRedefine(jvmti_env, env, target, class_file_bytes, dex_file_bytes);
131}
132
133// Magic JNI export that classes can use for redefining classes.
134// To use classes should declare this as a native function with signature
135// ([Ljava/lang/Class;[[B[[B)V
136extern "C" JNIEXPORT void JNICALL Java_Main_doCommonMultiClassRedefinition(
137 JNIEnv* env,
138 jclass,
139 jobjectArray targets,
140 jobjectArray class_file_bytes,
141 jobjectArray dex_file_bytes) {
142 std::vector<jclass> classes;
143 std::vector<jbyteArray> class_files;
144 std::vector<jbyteArray> dex_files;
145 jint len = env->GetArrayLength(targets);
146 if (len != env->GetArrayLength(class_file_bytes) || len != env->GetArrayLength(dex_file_bytes)) {
147 env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"),
148 "the three array arguments passed to this function have different lengths!");
149 return;
150 }
151 for (jint i = 0; i < len; i++) {
152 classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
153 dex_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(dex_file_bytes, i)));
154 class_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(class_file_bytes, i)));
155 }
156 return DoMultiClassRedefine(jvmti_env,
157 env,
158 len,
159 classes.data(),
160 class_files.data(),
161 dex_files.data());
Alex Light1e07ca62016-12-02 11:40:56 -0800162}
163
164// Don't do anything
165jint OnLoad(JavaVM* vm,
166 char* options ATTRIBUTE_UNUSED,
167 void* reserved ATTRIBUTE_UNUSED) {
168 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
169 printf("Unable to get jvmti env!\n");
170 return 1;
171 }
172 SetAllCapabilities(jvmti_env);
173 return 0;
174}
175
176} // namespace common_redefine
177
178} // namespace art