blob: c5ed46034d43678b74665b15ea9114e7cd68264a [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"
Andreas Gampecefaa142017-01-23 15:04:59 -080031#include "936-search-onload/search_onload.h"
Alex Light49948e92016-08-11 15:35:28 -070032
33namespace art {
34
Andreas Gampecc13b222016-10-10 19:09:09 -070035jvmtiEnv* jvmti_env;
36
Andreas Gampe53ae7802017-01-19 21:13:46 -080037namespace {
38
Alex Light49948e92016-08-11 15:35:28 -070039using OnLoad = jint (*)(JavaVM* vm, char* options, void* reserved);
40using OnAttach = jint (*)(JavaVM* vm, char* options, void* reserved);
41
42struct AgentLib {
43 const char* name;
44 OnLoad load;
45 OnAttach attach;
46};
47
Andreas Gampe53ae7802017-01-19 21:13:46 -080048static void JNICALL VMInitCallback(jvmtiEnv *jvmti_env,
49 JNIEnv* jni_env,
50 jthread thread ATTRIBUTE_UNUSED) {
51 // Bind Main native methods.
52 BindFunctions(jvmti_env, jni_env, "Main");
53}
54
55// Install a phase callback that will bind JNI functions on VMInit.
56bool InstallBindCallback(JavaVM* vm) {
57 // Use a new jvmtiEnv. Otherwise we might collide with table changes.
58 jvmtiEnv* install_env;
59 if (vm->GetEnv(reinterpret_cast<void**>(&install_env), JVMTI_VERSION_1_0) != 0) {
60 return false;
61 }
62 SetAllCapabilities(install_env);
63
64 {
65 jvmtiEventCallbacks callbacks;
66 memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
67 callbacks.VMInit = VMInitCallback;
68
69 jvmtiError install_error = install_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
70 if (install_error != JVMTI_ERROR_NONE) {
71 return false;
72 }
73 }
74
75 {
76 jvmtiError enable_error = install_env->SetEventNotificationMode(JVMTI_ENABLE,
77 JVMTI_EVENT_VM_INIT,
78 nullptr);
79 if (enable_error != JVMTI_ERROR_NONE) {
80 return false;
81 }
82 }
83
84 return true;
85}
86
Andreas Gampea8883a02017-01-11 19:53:50 -080087// A trivial OnLoad implementation that only initializes the global jvmti_env.
88static jint MinimalOnLoad(JavaVM* vm,
89 char* options ATTRIBUTE_UNUSED,
90 void* reserved ATTRIBUTE_UNUSED) {
Andreas Gampe53ae7802017-01-19 21:13:46 -080091 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
Andreas Gampea8883a02017-01-11 19:53:50 -080092 printf("Unable to get jvmti env!\n");
93 return 1;
94 }
95 SetAllCapabilities(jvmti_env);
96 return 0;
97}
98
99// A list of all non-standard the agents we have for testing. All other agents will use
100// MinimalOnLoad.
Andreas Gampe53ae7802017-01-19 21:13:46 -0800101static AgentLib agents[] = {
Alex Light49948e92016-08-11 15:35:28 -0700102 { "901-hello-ti-agent", Test901HelloTi::OnLoad, nullptr },
Alex Light1e07ca62016-12-02 11:40:56 -0800103 { "902-hello-transformation", common_redefine::OnLoad, nullptr },
Leonard Mosescueb842212016-10-06 17:26:36 -0700104 { "909-attach-agent", nullptr, Test909AttachAgent::OnAttach },
Alex Lightdba61482016-12-21 08:20:29 -0800105 { "914-hello-obsolescence", common_redefine::OnLoad, nullptr },
106 { "915-obsolete-2", common_redefine::OnLoad, nullptr },
107 { "916-obsolete-jit", common_redefine::OnLoad, nullptr },
Alex Light200b9d72016-12-15 11:34:13 -0800108 { "917-fields-transformation", common_redefine::OnLoad, nullptr },
Alex Light32a2fba2017-01-06 16:58:19 +0000109 { "919-obsolete-fields", common_redefine::OnLoad, nullptr },
Alex Light6ac57502017-01-19 15:05:06 -0800110 { "921-hello-failure", common_retransform::OnLoad, nullptr },
Alex Light0e692732017-01-10 15:00:05 -0800111 { "926-multi-obsolescence", common_redefine::OnLoad, nullptr },
Alex Light6ac57502017-01-19 15:05:06 -0800112 { "930-hello-retransform", common_retransform::OnLoad, nullptr },
Alex Lighta7e38d82017-01-19 14:57:28 -0800113 { "932-transform-saves", common_retransform::OnLoad, nullptr },
Alex Light440b5d92017-01-24 15:32:25 -0800114 { "934-load-transform", common_retransform::OnLoad, nullptr },
115 { "935-non-retransformable", common_transform::OnLoad, nullptr },
Andreas Gampecefaa142017-01-23 15:04:59 -0800116 { "936-search-onload", Test936SearchOnload::OnLoad, nullptr },
Alex Light28027122017-01-26 17:21:51 -0800117 { "937-hello-retransform-package", common_retransform::OnLoad, nullptr },
Alex Light7916f202017-01-27 09:00:15 -0800118 { "938-load-transform-bcp", common_retransform::OnLoad, nullptr },
119 { "939-hello-transformation-bcp", common_redefine::OnLoad, nullptr },
Alex Light49948e92016-08-11 15:35:28 -0700120};
121
122static AgentLib* FindAgent(char* name) {
123 for (AgentLib& l : agents) {
124 if (strncmp(l.name, name, strlen(l.name)) == 0) {
125 return &l;
126 }
127 }
128 return nullptr;
129}
130
131static bool FindAgentNameAndOptions(char* options,
132 /*out*/char** name,
133 /*out*/char** other_options) {
134 // Name is the first element.
135 *name = options;
136 char* rest = options;
137 // name is the first thing in the options
138 while (*rest != '\0' && *rest != ',') {
139 rest++;
140 }
141 if (*rest == ',') {
142 *rest = '\0';
143 rest++;
144 }
145 *other_options = rest;
146 return true;
147}
148
Alex Light1e07ca62016-12-02 11:40:56 -0800149static void SetIsJVM(char* options) {
150 RuntimeIsJVM = strncmp(options, "jvm", 3) == 0;
151}
152
Andreas Gampe53ae7802017-01-19 21:13:46 -0800153static bool BindFunctionsAttached(JavaVM* vm, const char* class_name) {
154 // Get a JNIEnv. As the thread is attached, we must not destroy it.
155 JNIEnv* env;
156 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != 0) {
157 printf("Unable to get JNI env!\n");
158 return false;
159 }
160
161 jvmtiEnv* jenv;
162 if (vm->GetEnv(reinterpret_cast<void**>(&jenv), JVMTI_VERSION_1_0) != 0) {
163 printf("Unable to get jvmti env!\n");
164 return false;
165 }
166 SetAllCapabilities(jenv);
167
168 BindFunctions(jenv, env, class_name);
169
170 return true;
171}
172
173} // namespace
174
Alex Light49948e92016-08-11 15:35:28 -0700175extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
176 char* remaining_options = nullptr;
177 char* name_option = nullptr;
178 if (!FindAgentNameAndOptions(options, &name_option, &remaining_options)) {
179 printf("Unable to find agent name in options: %s\n", options);
180 return -1;
181 }
Andreas Gampea8883a02017-01-11 19:53:50 -0800182
Alex Light1e07ca62016-12-02 11:40:56 -0800183 SetIsJVM(remaining_options);
Andreas Gampea8883a02017-01-11 19:53:50 -0800184
Andreas Gampe53ae7802017-01-19 21:13:46 -0800185 if (!InstallBindCallback(vm)) {
186 return 1;
187 }
188
Andreas Gampea8883a02017-01-11 19:53:50 -0800189 AgentLib* lib = FindAgent(name_option);
190 OnLoad fn = nullptr;
191 if (lib == nullptr) {
192 fn = &MinimalOnLoad;
193 } else {
194 if (lib->load == nullptr) {
195 printf("agent: %s does not include an OnLoad method.\n", name_option);
196 return -3;
197 }
198 fn = lib->load;
199 }
200 return fn(vm, remaining_options, reserved);
Alex Light49948e92016-08-11 15:35:28 -0700201}
202
Alex Light49948e92016-08-11 15:35:28 -0700203extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
204 char* remaining_options = nullptr;
205 char* name_option = nullptr;
206 if (!FindAgentNameAndOptions(options, &name_option, &remaining_options)) {
207 printf("Unable to find agent name in options: %s\n", options);
208 return -1;
209 }
Andreas Gampe53ae7802017-01-19 21:13:46 -0800210
211 BindFunctionsAttached(vm, "Main");
212
Alex Light49948e92016-08-11 15:35:28 -0700213 AgentLib* lib = FindAgent(name_option);
214 if (lib == nullptr) {
215 printf("Unable to find agent named: %s, add it to the list in test/ti-agent/common_load.cc\n",
216 name_option);
217 return -2;
218 }
219 if (lib->attach == nullptr) {
220 printf("agent: %s does not include an OnAttach method.\n", name_option);
221 return -3;
222 }
Alex Light1e07ca62016-12-02 11:40:56 -0800223 SetIsJVM(remaining_options);
Alex Light49948e92016-08-11 15:35:28 -0700224 return lib->attach(vm, remaining_options, reserved);
225}
226
227} // namespace art