blob: c30c2b1118b99acf01ee2cb582ac97b0dd25635f [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 Light28027122017-01-26 17:21:51 -0800115 { "937-hello-retransform-package", common_retransform::OnLoad, nullptr },
Alex Light49948e92016-08-11 15:35:28 -0700116};
117
118static AgentLib* FindAgent(char* name) {
119 for (AgentLib& l : agents) {
120 if (strncmp(l.name, name, strlen(l.name)) == 0) {
121 return &l;
122 }
123 }
124 return nullptr;
125}
126
127static bool FindAgentNameAndOptions(char* options,
128 /*out*/char** name,
129 /*out*/char** other_options) {
130 // Name is the first element.
131 *name = options;
132 char* rest = options;
133 // name is the first thing in the options
134 while (*rest != '\0' && *rest != ',') {
135 rest++;
136 }
137 if (*rest == ',') {
138 *rest = '\0';
139 rest++;
140 }
141 *other_options = rest;
142 return true;
143}
144
Alex Light1e07ca62016-12-02 11:40:56 -0800145static void SetIsJVM(char* options) {
146 RuntimeIsJVM = strncmp(options, "jvm", 3) == 0;
147}
148
Andreas Gampe53ae7802017-01-19 21:13:46 -0800149static bool BindFunctionsAttached(JavaVM* vm, const char* class_name) {
150 // Get a JNIEnv. As the thread is attached, we must not destroy it.
151 JNIEnv* env;
152 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != 0) {
153 printf("Unable to get JNI env!\n");
154 return false;
155 }
156
157 jvmtiEnv* jenv;
158 if (vm->GetEnv(reinterpret_cast<void**>(&jenv), JVMTI_VERSION_1_0) != 0) {
159 printf("Unable to get jvmti env!\n");
160 return false;
161 }
162 SetAllCapabilities(jenv);
163
164 BindFunctions(jenv, env, class_name);
165
166 return true;
167}
168
169} // namespace
170
Alex Light49948e92016-08-11 15:35:28 -0700171extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
172 char* remaining_options = nullptr;
173 char* name_option = nullptr;
174 if (!FindAgentNameAndOptions(options, &name_option, &remaining_options)) {
175 printf("Unable to find agent name in options: %s\n", options);
176 return -1;
177 }
Andreas Gampea8883a02017-01-11 19:53:50 -0800178
Alex Light1e07ca62016-12-02 11:40:56 -0800179 SetIsJVM(remaining_options);
Andreas Gampea8883a02017-01-11 19:53:50 -0800180
Andreas Gampe53ae7802017-01-19 21:13:46 -0800181 if (!InstallBindCallback(vm)) {
182 return 1;
183 }
184
Andreas Gampea8883a02017-01-11 19:53:50 -0800185 AgentLib* lib = FindAgent(name_option);
186 OnLoad fn = nullptr;
187 if (lib == nullptr) {
188 fn = &MinimalOnLoad;
189 } else {
190 if (lib->load == nullptr) {
191 printf("agent: %s does not include an OnLoad method.\n", name_option);
192 return -3;
193 }
194 fn = lib->load;
195 }
196 return fn(vm, remaining_options, reserved);
Alex Light49948e92016-08-11 15:35:28 -0700197}
198
Alex Light49948e92016-08-11 15:35:28 -0700199extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
200 char* remaining_options = nullptr;
201 char* name_option = nullptr;
202 if (!FindAgentNameAndOptions(options, &name_option, &remaining_options)) {
203 printf("Unable to find agent name in options: %s\n", options);
204 return -1;
205 }
Andreas Gampe53ae7802017-01-19 21:13:46 -0800206
207 BindFunctionsAttached(vm, "Main");
208
Alex Light49948e92016-08-11 15:35:28 -0700209 AgentLib* lib = FindAgent(name_option);
210 if (lib == nullptr) {
211 printf("Unable to find agent named: %s, add it to the list in test/ti-agent/common_load.cc\n",
212 name_option);
213 return -2;
214 }
215 if (lib->attach == nullptr) {
216 printf("agent: %s does not include an OnAttach method.\n", name_option);
217 return -3;
218 }
Alex Light1e07ca62016-12-02 11:40:56 -0800219 SetIsJVM(remaining_options);
Alex Light49948e92016-08-11 15:35:28 -0700220 return lib->attach(vm, remaining_options, reserved);
221}
222
223} // namespace art