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