blob: e0d623e6e117e9b239d1d2d81888bb08a694524b [file] [log] [blame]
Alex Light9c20a142016-08-23 15:05:12 -07001/*
2 * Copyright (C) 2013 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 <iostream>
18#include <pthread.h>
19#include <stdio.h>
20#include <vector>
21
22#include "art_method-inl.h"
23#include "base/logging.h"
24#include "jni.h"
25#include "openjdkjvmti/jvmti.h"
26#include "utils.h"
27
28namespace art {
29namespace Test902HelloTransformation {
30
31static bool RuntimeIsJvm = false;
32
33jvmtiEnv* jvmti_env;
34bool IsJVM() {
35 return RuntimeIsJvm;
36}
37
38// base64 encoded class/dex file for
39//
40// class Transform {
41// public void sayHi() {
42// System.out.println("Goodbye");
43// }
44// }
45const char* class_file_base64 =
46 "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB"
47 "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA"
48 "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq"
49 "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph"
50 "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG"
51 "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB"
52 "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0=";
53
54const char* dex_file_base64 =
55 "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO"
56 "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB"
57 "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA"
58 "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA"
59 "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA"
60 "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA"
61 "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50"
62 "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh"
63 "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291"
64 "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA"
65 "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA"
66 "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA"
67 "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=";
68
69static void JNICALL transformationHook(jvmtiEnv *jvmtienv,
70 JNIEnv* jni_env ATTRIBUTE_UNUSED,
71 jclass class_being_redefined ATTRIBUTE_UNUSED,
72 jobject loader ATTRIBUTE_UNUSED,
73 const char* name,
74 jobject protection_domain ATTRIBUTE_UNUSED,
75 jint class_data_len ATTRIBUTE_UNUSED,
76 const unsigned char* class_data ATTRIBUTE_UNUSED,
77 jint* new_class_data_len,
78 unsigned char** new_class_data) {
79 if (strcmp("Transform", name)) {
80 return;
81 }
82 printf("modifying class '%s'\n", name);
83 bool is_jvm = IsJVM();
84 size_t decode_len = 0;
85 unsigned char* new_data;
86 std::unique_ptr<uint8_t[]> file_data(
87 DecodeBase64((is_jvm) ? class_file_base64 : dex_file_base64, &decode_len));
88 jvmtiError ret = JVMTI_ERROR_NONE;
89 if ((ret = jvmtienv->Allocate(static_cast<jlong>(decode_len), &new_data)) != JVMTI_ERROR_NONE) {
90 printf("Unable to allocate buffer!\n");
91 return;
92 }
93 memcpy(new_data, file_data.get(), decode_len);
94 *new_class_data_len = static_cast<jint>(decode_len);
95 *new_class_data = new_data;
96 return;
97}
98
99using RetransformWithHookFunction = jvmtiError (*)(jvmtiEnv*, jclass, jvmtiEventClassFileLoadHook);
100static void DoClassTransformation(jvmtiEnv* jvmtienv, JNIEnv* jnienv, jclass target) {
101 if (IsJVM()) {
102 UNUSED(jnienv);
103 jvmtienv->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr);
104 jvmtiError ret = jvmtienv->RetransformClasses(1, &target);
105 if (ret != JVMTI_ERROR_NONE) {
106 char* err;
107 jvmtienv->GetErrorName(ret, &err);
108 printf("Error transforming: %s\n", err);
109 }
110 } else {
111 RetransformWithHookFunction f =
112 reinterpret_cast<RetransformWithHookFunction>(jvmtienv->functions->reserved1);
113 if (f(jvmtienv, target, transformationHook) != JVMTI_ERROR_NONE) {
114 printf("Failed to tranform class!");
115 return;
116 }
117 }
118}
119
120extern "C" JNIEXPORT void JNICALL Java_Main_doClassTransformation(JNIEnv* env,
121 jclass,
122 jclass target) {
123 JavaVM* vm;
124 if (env->GetJavaVM(&vm)) {
125 printf("Unable to get javaVM!\n");
126 return;
127 }
128 DoClassTransformation(jvmti_env, env, target);
129}
130
131// Don't do anything
132jint OnLoad(JavaVM* vm,
133 char* options,
134 void* reserved ATTRIBUTE_UNUSED) {
135 jvmtiCapabilities caps;
136 RuntimeIsJvm = (strcmp("jvm", options) == 0);
137 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
138 printf("Unable to get jvmti env!\n");
139 return 1;
140 }
141 if (IsJVM()) {
142 jvmti_env->GetPotentialCapabilities(&caps);
143 jvmti_env->AddCapabilities(&caps);
144 jvmtiEventCallbacks cbs;
145 memset(&cbs, 0, sizeof(cbs));
146 cbs.ClassFileLoadHook = transformationHook;
147 jvmti_env->SetEventCallbacks(&cbs, sizeof(jvmtiEventCallbacks));
148 }
149 return 0;
150}
151
152} // namespace Test902HelloTransformation
153} // namespace art
154