blob: 621d45a1bcd65c075720993540a350af44840a2d [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 Light49948e92016-08-11 15:35:28 -0700118};
119
120static AgentLib* FindAgent(char* name) {
121 for (AgentLib& l : agents) {
122 if (strncmp(l.name, name, strlen(l.name)) == 0) {
123 return &l;
124 }
125 }
126 return nullptr;
127}
128
129static bool FindAgentNameAndOptions(char* options,
130 /*out*/char** name,
131 /*out*/char** other_options) {
132 // Name is the first element.
133 *name = options;
134 char* rest = options;
135 // name is the first thing in the options
136 while (*rest != '\0' && *rest != ',') {
137 rest++;
138 }
139 if (*rest == ',') {
140 *rest = '\0';
141 rest++;
142 }
143 *other_options = rest;
144 return true;
145}
146
Alex Light1e07ca62016-12-02 11:40:56 -0800147static void SetIsJVM(char* options) {
148 RuntimeIsJVM = strncmp(options, "jvm", 3) == 0;
149}
150
Andreas Gampe53ae7802017-01-19 21:13:46 -0800151static bool BindFunctionsAttached(JavaVM* vm, const char* class_name) {
152 // Get a JNIEnv. As the thread is attached, we must not destroy it.
153 JNIEnv* env;
154 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != 0) {
155 printf("Unable to get JNI env!\n");
156 return false;
157 }
158
159 jvmtiEnv* jenv;
160 if (vm->GetEnv(reinterpret_cast<void**>(&jenv), JVMTI_VERSION_1_0) != 0) {
161 printf("Unable to get jvmti env!\n");
162 return false;
163 }
164 SetAllCapabilities(jenv);
165
166 BindFunctions(jenv, env, class_name);
167
168 return true;
169}
170
171} // namespace
172
Alex Light49948e92016-08-11 15:35:28 -0700173extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
174 char* remaining_options = nullptr;
175 char* name_option = nullptr;
176 if (!FindAgentNameAndOptions(options, &name_option, &remaining_options)) {
177 printf("Unable to find agent name in options: %s\n", options);
178 return -1;
179 }
Andreas Gampea8883a02017-01-11 19:53:50 -0800180
Alex Light1e07ca62016-12-02 11:40:56 -0800181 SetIsJVM(remaining_options);
Andreas Gampea8883a02017-01-11 19:53:50 -0800182
Andreas Gampe53ae7802017-01-19 21:13:46 -0800183 if (!InstallBindCallback(vm)) {
184 return 1;
185 }
186
Andreas Gampea8883a02017-01-11 19:53:50 -0800187 AgentLib* lib = FindAgent(name_option);
188 OnLoad fn = nullptr;
189 if (lib == nullptr) {
190 fn = &MinimalOnLoad;
191 } else {
192 if (lib->load == nullptr) {
193 printf("agent: %s does not include an OnLoad method.\n", name_option);
194 return -3;
195 }
196 fn = lib->load;
197 }
198 return fn(vm, remaining_options, reserved);
Alex Light49948e92016-08-11 15:35:28 -0700199}
200
Alex Light49948e92016-08-11 15:35:28 -0700201extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
202 char* remaining_options = nullptr;
203 char* name_option = nullptr;
204 if (!FindAgentNameAndOptions(options, &name_option, &remaining_options)) {
205 printf("Unable to find agent name in options: %s\n", options);
206 return -1;
207 }
Andreas Gampe53ae7802017-01-19 21:13:46 -0800208
209 BindFunctionsAttached(vm, "Main");
210
Alex Light49948e92016-08-11 15:35:28 -0700211 AgentLib* lib = FindAgent(name_option);
212 if (lib == nullptr) {
213 printf("Unable to find agent named: %s, add it to the list in test/ti-agent/common_load.cc\n",
214 name_option);
215 return -2;
216 }
217 if (lib->attach == nullptr) {
218 printf("agent: %s does not include an OnAttach method.\n", name_option);
219 return -3;
220 }
Alex Light1e07ca62016-12-02 11:40:56 -0800221 SetIsJVM(remaining_options);
Alex Light49948e92016-08-11 15:35:28 -0700222 return lib->attach(vm, remaining_options, reserved);
223}
224
225} // namespace art