blob: f5074519b88f9bca47ef6984b41f00e0cf3a8fe4 [file] [log] [blame]
Alex Light49948e92016-08-11 15:35:28 -07001/*
2 * Copyright 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
Andreas Gampe53ae7802017-01-19 21:13:46 -080017#include "common_load.h"
18
Alex Light49948e92016-08-11 15:35:28 -070019#include <jni.h>
20#include <stdio.h>
21// TODO I don't know?
22#include "openjdkjvmti/jvmti.h"
23
24#include "art_method-inl.h"
25#include "base/logging.h"
26#include "base/macros.h"
Alex Light1e07ca62016-12-02 11:40:56 -080027#include "common_helper.h"
Alex Light49948e92016-08-11 15:35:28 -070028
29#include "901-hello-ti-agent/basics.h"
Leonard Mosescueb842212016-10-06 17:26:36 -070030#include "909-attach-agent/attach.h"
Alex Light49948e92016-08-11 15:35:28 -070031
32namespace art {
33
Andreas Gampecc13b222016-10-10 19:09:09 -070034jvmtiEnv* jvmti_env;
35
Andreas Gampe53ae7802017-01-19 21:13:46 -080036namespace {
37
Alex Light49948e92016-08-11 15:35:28 -070038using OnLoad = jint (*)(JavaVM* vm, char* options, void* reserved);
39using OnAttach = jint (*)(JavaVM* vm, char* options, void* reserved);
40
41struct AgentLib {
42 const char* name;
43 OnLoad load;
44 OnAttach attach;
45};
46
Andreas Gampe53ae7802017-01-19 21:13:46 -080047static void JNICALL VMInitCallback(jvmtiEnv *jvmti_env,
48 JNIEnv* jni_env,
49 jthread thread ATTRIBUTE_UNUSED) {
50 // Bind Main native methods.
51 BindFunctions(jvmti_env, jni_env, "Main");
52}
53
54// Install a phase callback that will bind JNI functions on VMInit.
55bool InstallBindCallback(JavaVM* vm) {
56 // Use a new jvmtiEnv. Otherwise we might collide with table changes.
57 jvmtiEnv* install_env;
58 if (vm->GetEnv(reinterpret_cast<void**>(&install_env), JVMTI_VERSION_1_0) != 0) {
59 return false;
60 }
61 SetAllCapabilities(install_env);
62
63 {
64 jvmtiEventCallbacks callbacks;
65 memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
66 callbacks.VMInit = VMInitCallback;
67
68 jvmtiError install_error = install_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
69 if (install_error != JVMTI_ERROR_NONE) {
70 return false;
71 }
72 }
73
74 {
75 jvmtiError enable_error = install_env->SetEventNotificationMode(JVMTI_ENABLE,
76 JVMTI_EVENT_VM_INIT,
77 nullptr);
78 if (enable_error != JVMTI_ERROR_NONE) {
79 return false;
80 }
81 }
82
83 return true;
84}
85
Andreas Gampea8883a02017-01-11 19:53:50 -080086// A trivial OnLoad implementation that only initializes the global jvmti_env.
87static jint MinimalOnLoad(JavaVM* vm,
88 char* options ATTRIBUTE_UNUSED,
89 void* reserved ATTRIBUTE_UNUSED) {
Andreas Gampe53ae7802017-01-19 21:13:46 -080090 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
Andreas Gampea8883a02017-01-11 19:53:50 -080091 printf("Unable to get jvmti env!\n");
92 return 1;
93 }
94 SetAllCapabilities(jvmti_env);
95 return 0;
96}
97
98// A list of all non-standard the agents we have for testing. All other agents will use
99// MinimalOnLoad.
Andreas Gampe53ae7802017-01-19 21:13:46 -0800100static AgentLib agents[] = {
Alex Light49948e92016-08-11 15:35:28 -0700101 { "901-hello-ti-agent", Test901HelloTi::OnLoad, nullptr },
Alex Light1e07ca62016-12-02 11:40:56 -0800102 { "902-hello-transformation", common_redefine::OnLoad, nullptr },
Leonard Mosescueb842212016-10-06 17:26:36 -0700103 { "909-attach-agent", nullptr, Test909AttachAgent::OnAttach },
Alex Lightdba61482016-12-21 08:20:29 -0800104 { "914-hello-obsolescence", common_redefine::OnLoad, nullptr },
105 { "915-obsolete-2", common_redefine::OnLoad, nullptr },
106 { "916-obsolete-jit", common_redefine::OnLoad, nullptr },
Alex Light200b9d72016-12-15 11:34:13 -0800107 { "917-fields-transformation", common_redefine::OnLoad, nullptr },
Alex Light32a2fba2017-01-06 16:58:19 +0000108 { "919-obsolete-fields", common_redefine::OnLoad, nullptr },
Alex Light6ac57502017-01-19 15:05:06 -0800109 { "921-hello-failure", common_retransform::OnLoad, nullptr },
Alex Light0e692732017-01-10 15:00:05 -0800110 { "926-multi-obsolescence", common_redefine::OnLoad, nullptr },
Alex Light6ac57502017-01-19 15:05:06 -0800111 { "930-hello-retransform", common_retransform::OnLoad, nullptr },
Alex Lighta7e38d82017-01-19 14:57:28 -0800112 { "932-transform-saves", common_retransform::OnLoad, nullptr },
Alex Light440b5d92017-01-24 15:32:25 -0800113 { "934-load-transform", common_retransform::OnLoad, nullptr },
114 { "935-non-retransformable", common_transform::OnLoad, nullptr },
Alex Light49948e92016-08-11 15:35:28 -0700115};
116
117static AgentLib* FindAgent(char* name) {
118 for (AgentLib& l : agents) {
119 if (strncmp(l.name, name, strlen(l.name)) == 0) {
120 return &l;
121 }
122 }
123 return nullptr;
124}
125
126static bool FindAgentNameAndOptions(char* options,
127 /*out*/char** name,
128 /*out*/char** other_options) {
129 // Name is the first element.
130 *name = options;
131 char* rest = options;
132 // name is the first thing in the options
133 while (*rest != '\0' && *rest != ',') {
134 rest++;
135 }
136 if (*rest == ',') {
137 *rest = '\0';
138 rest++;
139 }
140 *other_options = rest;
141 return true;
142}
143
Alex Light1e07ca62016-12-02 11:40:56 -0800144static void SetIsJVM(char* options) {
145 RuntimeIsJVM = strncmp(options, "jvm", 3) == 0;
146}
147
Andreas Gampe53ae7802017-01-19 21:13:46 -0800148static bool BindFunctionsAttached(JavaVM* vm, const char* class_name) {
149 // Get a JNIEnv. As the thread is attached, we must not destroy it.
150 JNIEnv* env;
151 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != 0) {
152 printf("Unable to get JNI env!\n");
153 return false;
154 }
155
156 jvmtiEnv* jenv;
157 if (vm->GetEnv(reinterpret_cast<void**>(&jenv), JVMTI_VERSION_1_0) != 0) {
158 printf("Unable to get jvmti env!\n");
159 return false;
160 }
161 SetAllCapabilities(jenv);
162
163 BindFunctions(jenv, env, class_name);
164
165 return true;
166}
167
168} // namespace
169
Alex Light49948e92016-08-11 15:35:28 -0700170extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
171 char* remaining_options = nullptr;
172 char* name_option = nullptr;
173 if (!FindAgentNameAndOptions(options, &name_option, &remaining_options)) {
174 printf("Unable to find agent name in options: %s\n", options);
175 return -1;
176 }
Andreas Gampea8883a02017-01-11 19:53:50 -0800177
Alex Light1e07ca62016-12-02 11:40:56 -0800178 SetIsJVM(remaining_options);
Andreas Gampea8883a02017-01-11 19:53:50 -0800179
Andreas Gampe53ae7802017-01-19 21:13:46 -0800180 if (!InstallBindCallback(vm)) {
181 return 1;
182 }
183
Andreas Gampea8883a02017-01-11 19:53:50 -0800184 AgentLib* lib = FindAgent(name_option);
185 OnLoad fn = nullptr;
186 if (lib == nullptr) {
187 fn = &MinimalOnLoad;
188 } else {
189 if (lib->load == nullptr) {
190 printf("agent: %s does not include an OnLoad method.\n", name_option);
191 return -3;
192 }
193 fn = lib->load;
194 }
195 return fn(vm, remaining_options, reserved);
Alex Light49948e92016-08-11 15:35:28 -0700196}
197
Alex Light49948e92016-08-11 15:35:28 -0700198extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
199 char* remaining_options = nullptr;
200 char* name_option = nullptr;
201 if (!FindAgentNameAndOptions(options, &name_option, &remaining_options)) {
202 printf("Unable to find agent name in options: %s\n", options);
203 return -1;
204 }
Andreas Gampe53ae7802017-01-19 21:13:46 -0800205
206 BindFunctionsAttached(vm, "Main");
207
Alex Light49948e92016-08-11 15:35:28 -0700208 AgentLib* lib = FindAgent(name_option);
209 if (lib == nullptr) {
210 printf("Unable to find agent named: %s, add it to the list in test/ti-agent/common_load.cc\n",
211 name_option);
212 return -2;
213 }
214 if (lib->attach == nullptr) {
215 printf("agent: %s does not include an OnAttach method.\n", name_option);
216 return -3;
217 }
Alex Light1e07ca62016-12-02 11:40:56 -0800218 SetIsJVM(remaining_options);
Alex Light49948e92016-08-11 15:35:28 -0700219 return lib->attach(vm, remaining_options, reserved);
220}
221
222} // namespace art