blob: 6f98f100721cb8c36bce1f12f07a7ccaf447e2ad [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 Light460d1b42017-01-10 15:37:17 +000065static void throwRedefinitionError(jvmtiEnv* jvmti, JNIEnv* env, jclass target, jvmtiError res) {
66 std::stringstream err;
67 char* signature = nullptr;
68 char* generic = nullptr;
69 jvmti->GetClassSignature(target, &signature, &generic);
70 char* error = nullptr;
71 jvmti->GetErrorName(res, &error);
72 err << "Failed to redefine class <" << signature << "> due to " << error;
73 std::string message = err.str();
74 jvmti->Deallocate(reinterpret_cast<unsigned char*>(signature));
75 jvmti->Deallocate(reinterpret_cast<unsigned char*>(generic));
76 jvmti->Deallocate(reinterpret_cast<unsigned char*>(error));
77 env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
78}
79
Alex Light1e07ca62016-12-02 11:40:56 -080080using RedefineDirectFunction = jvmtiError (*)(jvmtiEnv*, jclass, jint, const unsigned char*);
Alex Light460d1b42017-01-10 15:37:17 +000081static void DoClassTransformation(jvmtiEnv* jvmti_env,
82 JNIEnv* env,
Alex Light1e07ca62016-12-02 11:40:56 -080083 jclass target,
84 jbyteArray class_file_bytes,
85 jbyteArray dex_file_bytes) {
86 jbyteArray desired_array = IsJVM() ? class_file_bytes : dex_file_bytes;
87 jint len = static_cast<jint>(env->GetArrayLength(desired_array));
88 const unsigned char* redef_bytes = reinterpret_cast<const unsigned char*>(
89 env->GetByteArrayElements(desired_array, nullptr));
90 jvmtiError res;
91 if (IsJVM()) {
92 jvmtiClassDefinition def;
93 def.klass = target;
94 def.class_byte_count = static_cast<jint>(len);
95 def.class_bytes = redef_bytes;
96 res = jvmti_env->RedefineClasses(1, &def);
97 } else {
98 RedefineDirectFunction f =
99 reinterpret_cast<RedefineDirectFunction>(jvmti_env->functions->reserved3);
100 res = f(jvmti_env, target, len, redef_bytes);
101 }
102 if (res != JVMTI_ERROR_NONE) {
Alex Light460d1b42017-01-10 15:37:17 +0000103 throwRedefinitionError(jvmti_env, env, target, res);
Alex Light1e07ca62016-12-02 11:40:56 -0800104 }
105}
106
107// Magic JNI export that classes can use for redefining classes.
108// To use classes should declare this as a native function with signature (Ljava/lang/Class;[B[B)V
109extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRedefinition(JNIEnv* env,
110 jclass,
111 jclass target,
112 jbyteArray class_file_bytes,
113 jbyteArray dex_file_bytes) {
114 DoClassTransformation(jvmti_env, env, target, class_file_bytes, dex_file_bytes);
115}
116
117// Don't do anything
118jint OnLoad(JavaVM* vm,
119 char* options ATTRIBUTE_UNUSED,
120 void* reserved ATTRIBUTE_UNUSED) {
121 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
122 printf("Unable to get jvmti env!\n");
123 return 1;
124 }
125 SetAllCapabilities(jvmti_env);
126 return 0;
127}
128
129} // namespace common_redefine
130
131} // namespace art