blob: 8d4cc8913932ddbbed9dfa32c2560cfebfb4d7bd [file] [log] [blame]
Alex Light8f2c6d42017-04-10 16:27:35 -07001/*
2 * Copyright 2017 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 <jni.h>
18#include <stdio.h>
19#include <iostream>
20#include <fstream>
Alex Lightbad2f512017-06-14 11:33:55 -070021#include <memory>
Alex Light8f2c6d42017-04-10 16:27:35 -070022#include <stdio.h>
23#include <sstream>
Alex Lightb7edcda2017-04-27 13:20:31 -070024#include <strstream>
Alex Light8f2c6d42017-04-10 16:27:35 -070025
26#include "jvmti.h"
27#include "exec_utils.h"
28#include "utils.h"
29
30namespace art {
31
32// Should we do a 'full_rewrite' with this test?
33static constexpr bool kDoFullRewrite = true;
34
35struct StressData {
36 std::string dexter_cmd;
37 std::string out_temp_dex;
38 std::string in_temp_dex;
39 bool vm_class_loader_initialized;
Alex Lightb7edcda2017-04-27 13:20:31 -070040 bool trace_stress;
41 bool redefine_stress;
Alex Light43e935d2017-06-19 15:40:40 -070042 bool field_stress;
Alex Light8f2c6d42017-04-10 16:27:35 -070043};
44
45static void WriteToFile(const std::string& fname, jint data_len, const unsigned char* data) {
46 std::ofstream file(fname, std::ios::binary | std::ios::out | std::ios::trunc);
47 file.write(reinterpret_cast<const char*>(data), data_len);
48 file.flush();
49}
50
51static bool ReadIntoBuffer(const std::string& fname, /*out*/std::vector<unsigned char>* data) {
52 std::ifstream file(fname, std::ios::binary | std::ios::in);
53 file.seekg(0, std::ios::end);
54 size_t len = file.tellg();
55 data->resize(len);
56 file.seekg(0);
57 file.read(reinterpret_cast<char*>(data->data()), len);
58 return len != 0;
59}
60
61// TODO rewrite later.
62static bool DoExtractClassFromData(StressData* data,
63 const std::string& class_name,
64 jint in_len,
65 const unsigned char* in_data,
66 /*out*/std::vector<unsigned char>* dex) {
67 // Write the dex file into a temporary file.
68 WriteToFile(data->in_temp_dex, in_len, in_data);
69 // Clear out file so even if something suppresses the exit value we will still detect dexter
70 // failure.
71 WriteToFile(data->out_temp_dex, 0, nullptr);
72 // Have dexter do the extraction.
73 std::vector<std::string> args;
74 args.push_back(data->dexter_cmd);
75 if (kDoFullRewrite) {
76 args.push_back("-x");
77 args.push_back("full_rewrite");
78 }
79 args.push_back("-e");
80 args.push_back(class_name);
81 args.push_back("-o");
82 args.push_back(data->out_temp_dex);
83 args.push_back(data->in_temp_dex);
84 std::string error;
85 if (ExecAndReturnCode(args, &error) != 0) {
86 LOG(ERROR) << "unable to execute dexter: " << error;
87 return false;
88 }
89 return ReadIntoBuffer(data->out_temp_dex, dex);
90}
91
Alex Lightbad2f512017-06-14 11:33:55 -070092class ScopedThreadInfo {
93 public:
94 ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread)
95 : jvmtienv_(jvmtienv), env_(env), free_name_(false) {
96 memset(&info_, 0, sizeof(info_));
97 if (thread == nullptr) {
98 info_.name = const_cast<char*>("<NULLPTR>");
99 } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) {
100 info_.name = const_cast<char*>("<UNKNOWN THREAD>");
101 } else {
102 free_name_ = true;
103 }
104 }
105
106 ~ScopedThreadInfo() {
107 if (free_name_) {
108 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name));
109 }
110 env_->DeleteLocalRef(info_.thread_group);
111 env_->DeleteLocalRef(info_.context_class_loader);
112 }
113
114 const char* GetName() const {
115 return info_.name;
116 }
117
118 private:
119 jvmtiEnv* jvmtienv_;
120 JNIEnv* env_;
121 bool free_name_;
122 jvmtiThreadInfo info_;
123};
124
125class ScopedClassInfo {
126 public:
127 ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c)
128 : jvmtienv_(jvmtienv),
129 class_(c),
130 name_(nullptr),
131 generic_(nullptr) {}
132
133 ~ScopedClassInfo() {
Alex Light43e935d2017-06-19 15:40:40 -0700134 if (class_ != nullptr) {
135 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
136 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
137 }
Alex Lightbad2f512017-06-14 11:33:55 -0700138 }
139
140 bool Init() {
Alex Light43e935d2017-06-19 15:40:40 -0700141 if (class_ == nullptr) {
142 name_ = const_cast<char*>("<NONE>");
143 generic_ = const_cast<char*>("<NONE>");
144 return true;
145 } else {
146 return jvmtienv_->GetClassSignature(class_, &name_, &generic_) == JVMTI_ERROR_NONE;
147 }
Alex Lightbad2f512017-06-14 11:33:55 -0700148 }
149
150 jclass GetClass() const {
151 return class_;
152 }
153 const char* GetName() const {
154 return name_;
155 }
156 const char* GetGeneric() const {
157 return generic_;
158 }
159
160 private:
161 jvmtiEnv* jvmtienv_;
162 jclass class_;
163 char* name_;
164 char* generic_;
165};
166
167class ScopedMethodInfo {
168 public:
169 ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m)
170 : jvmtienv_(jvmtienv),
171 env_(env),
172 method_(m),
173 declaring_class_(nullptr),
174 class_info_(nullptr),
175 name_(nullptr),
176 signature_(nullptr),
177 generic_(nullptr) {}
178
179 ~ScopedMethodInfo() {
180 env_->DeleteLocalRef(declaring_class_);
181 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
182 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
183 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
184 }
185
186 bool Init() {
187 if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
188 return false;
189 }
190 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
191 return class_info_->Init() &&
192 (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
193 }
194
195 const ScopedClassInfo& GetDeclaringClassInfo() const {
196 return *class_info_;
197 }
198
199 jclass GetDeclaringClass() const {
200 return declaring_class_;
201 }
202
203 const char* GetName() const {
204 return name_;
205 }
206
207 const char* GetSignature() const {
208 return signature_;
209 }
210
211 const char* GetGeneric() const {
212 return generic_;
213 }
214
215 private:
216 jvmtiEnv* jvmtienv_;
217 JNIEnv* env_;
218 jmethodID method_;
219 jclass declaring_class_;
220 std::unique_ptr<ScopedClassInfo> class_info_;
221 char* name_;
222 char* signature_;
223 char* generic_;
224
225 friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
226};
227
Alex Light43e935d2017-06-19 15:40:40 -0700228class ScopedFieldInfo {
229 public:
230 ScopedFieldInfo(jvmtiEnv* jvmtienv, jclass field_klass, jfieldID field)
231 : jvmtienv_(jvmtienv),
232 declaring_class_(field_klass),
233 field_(field),
234 class_info_(nullptr),
235 name_(nullptr),
236 type_(nullptr),
237 generic_(nullptr) {}
238
239 ~ScopedFieldInfo() {
240 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
241 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(type_));
242 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
243 }
244
245 bool Init() {
246 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
247 return class_info_->Init() &&
248 (jvmtienv_->GetFieldName(
249 declaring_class_, field_, &name_, &type_, &generic_) == JVMTI_ERROR_NONE);
250 }
251
252 const ScopedClassInfo& GetDeclaringClassInfo() const {
253 return *class_info_;
254 }
255
256 jclass GetDeclaringClass() const {
257 return declaring_class_;
258 }
259
260 const char* GetName() const {
261 return name_;
262 }
263
264 const char* GetType() const {
265 return type_;
266 }
267
268 const char* GetGeneric() const {
269 return generic_;
270 }
271
272 private:
273 jvmtiEnv* jvmtienv_;
274 jclass declaring_class_;
275 jfieldID field_;
276 std::unique_ptr<ScopedClassInfo> class_info_;
277 char* name_;
278 char* type_;
279 char* generic_;
280
281 friend std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m);
282};
283
284std::ostream& operator<<(std::ostream &os, const ScopedFieldInfo* m) {
285 return os << *m;
286}
287
288std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m) {
289 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName()
290 << ":" << m.GetType();
291}
292
Alex Lightbad2f512017-06-14 11:33:55 -0700293std::ostream& operator<<(std::ostream &os, const ScopedMethodInfo* m) {
294 return os << *m;
295}
296
297std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
298 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature();
299}
300
Alex Light0af8cde2017-04-20 13:35:05 -0700301static void doJvmtiMethodBind(jvmtiEnv* jvmtienv,
302 JNIEnv* env,
303 jthread thread,
304 jmethodID m,
305 void* address,
306 /*out*/void** out_address) {
307 *out_address = address;
Alex Lightbad2f512017-06-14 11:33:55 -0700308 ScopedThreadInfo thread_info(jvmtienv, env, thread);
309 ScopedMethodInfo method_info(jvmtienv, env, m);
310 if (!method_info.Init()) {
311 LOG(ERROR) << "Unable to get method info!";
Alex Light0af8cde2017-04-20 13:35:05 -0700312 return;
313 }
Alex Lightbad2f512017-06-14 11:33:55 -0700314 LOG(INFO) << "Loading native method \"" << method_info << "\". Thread is "
315 << thread_info.GetName();
Alex Light0af8cde2017-04-20 13:35:05 -0700316}
317
Alex Lightb7edcda2017-04-27 13:20:31 -0700318static std::string GetName(jvmtiEnv* jvmtienv, JNIEnv* jnienv, jobject obj) {
319 jclass klass = jnienv->GetObjectClass(obj);
320 char *cname, *cgen;
321 if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
322 LOG(ERROR) << "Unable to get class name!";
323 jnienv->DeleteLocalRef(klass);
324 return "<UNKNOWN>";
325 }
326 std::string name(cname);
327 if (name == "Ljava/lang/String;") {
328 jstring str = reinterpret_cast<jstring>(obj);
329 const char* val = jnienv->GetStringUTFChars(str, nullptr);
330 if (val == nullptr) {
331 name += " (unable to get value)";
332 } else {
333 std::ostringstream oss;
334 oss << name << " (value: \"" << val << "\")";
335 name = oss.str();
336 jnienv->ReleaseStringUTFChars(str, val);
337 }
338 }
339 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
340 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
341 jnienv->DeleteLocalRef(klass);
342 return name;
343}
344
345static std::string GetValOf(jvmtiEnv* env, JNIEnv* jnienv, std::string type, jvalue val) {
346 std::ostringstream oss;
347 switch (type[0]) {
348 case '[':
349 case 'L':
350 return val.l != nullptr ? GetName(env, jnienv, val.l) : "null";
351 case 'Z':
352 return val.z == JNI_TRUE ? "true" : "false";
353 case 'B':
354 oss << val.b;
355 return oss.str();
356 case 'C':
357 oss << val.c;
358 return oss.str();
359 case 'S':
360 oss << val.s;
361 return oss.str();
362 case 'I':
363 oss << val.i;
364 return oss.str();
365 case 'J':
366 oss << val.j;
367 return oss.str();
368 case 'F':
369 oss << val.f;
370 return oss.str();
371 case 'D':
372 oss << val.d;
373 return oss.str();
374 case 'V':
375 return "<void>";
376 default:
377 return "<ERROR Found type " + type + ">";
378 }
379}
380
Alex Light43e935d2017-06-19 15:40:40 -0700381void JNICALL FieldAccessHook(jvmtiEnv* jvmtienv,
382 JNIEnv* env,
383 jthread thread,
384 jmethodID m,
385 jlocation location,
386 jclass field_klass,
387 jobject object,
388 jfieldID field) {
389 ScopedThreadInfo info(jvmtienv, env, thread);
390 ScopedMethodInfo method_info(jvmtienv, env, m);
391 ScopedFieldInfo field_info(jvmtienv, field_klass, field);
392 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr;
393 ScopedClassInfo obj_class_info(jvmtienv, oklass);
394 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) {
395 LOG(ERROR) << "Unable to get callback info!";
396 return;
397 }
398 LOG(INFO) << "ACCESS field \"" << field_info << "\" on object of "
399 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info
400 << "\" at location 0x" << std::hex << location << ". Thread is \""
401 << info.GetName() << "\".";
402 env->DeleteLocalRef(oklass);
403}
404
405static std::string PrintJValue(jvmtiEnv* jvmtienv, JNIEnv* env, char type, jvalue new_value) {
406 std::ostringstream oss;
407 switch (type) {
408 case 'L': {
409 jobject nv = new_value.l;
410 if (nv == nullptr) {
411 oss << "\"null\"";
412 } else {
413 jclass nv_klass = env->GetObjectClass(nv);
414 ScopedClassInfo nv_class_info(jvmtienv, nv_klass);
415 if (!nv_class_info.Init()) {
416 oss << "with unknown type";
417 } else {
418 oss << "of type \"" << nv_class_info.GetName() << "\"";
419 }
420 env->DeleteLocalRef(nv_klass);
421 }
422 break;
423 }
424 case 'Z': {
425 if (new_value.z) {
426 oss << "true";
427 } else {
428 oss << "false";
429 }
430 break;
431 }
432#define SEND_VALUE(chr, sym, type) \
433 case chr: { \
434 oss << static_cast<type>(new_value.sym); \
435 break; \
436 }
437 SEND_VALUE('B', b, int8_t);
438 SEND_VALUE('C', c, uint16_t);
439 SEND_VALUE('S', s, int16_t);
440 SEND_VALUE('I', i, int32_t);
441 SEND_VALUE('J', j, int64_t);
442 SEND_VALUE('F', f, float);
443 SEND_VALUE('D', d, double);
444#undef SEND_VALUE
445 }
446 return oss.str();
447}
448
449void JNICALL FieldModificationHook(jvmtiEnv* jvmtienv,
450 JNIEnv* env,
451 jthread thread,
452 jmethodID m,
453 jlocation location,
454 jclass field_klass,
455 jobject object,
456 jfieldID field,
457 char type,
458 jvalue new_value) {
459 ScopedThreadInfo info(jvmtienv, env, thread);
460 ScopedMethodInfo method_info(jvmtienv, env, m);
461 ScopedFieldInfo field_info(jvmtienv, field_klass, field);
462 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr;
463 ScopedClassInfo obj_class_info(jvmtienv, oklass);
464 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) {
465 LOG(ERROR) << "Unable to get callback info!";
466 return;
467 }
468 LOG(INFO) << "MODIFY field \"" << field_info << "\" on object of "
469 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info
470 << "\" at location 0x" << std::hex << location << std::dec << ". New value is "
471 << PrintJValue(jvmtienv, env, type, new_value) << ". Thread is \""
472 << info.GetName() << "\".";
473 env->DeleteLocalRef(oklass);
474}
Alex Lightb7edcda2017-04-27 13:20:31 -0700475void JNICALL MethodExitHook(jvmtiEnv* jvmtienv,
476 JNIEnv* env,
477 jthread thread,
478 jmethodID m,
479 jboolean was_popped_by_exception,
480 jvalue val) {
Alex Lightbad2f512017-06-14 11:33:55 -0700481 ScopedThreadInfo info(jvmtienv, env, thread);
482 ScopedMethodInfo method_info(jvmtienv, env, m);
483 if (!method_info.Init()) {
484 LOG(ERROR) << "Unable to get method info!";
Alex Lightb7edcda2017-04-27 13:20:31 -0700485 return;
486 }
Alex Lightbad2f512017-06-14 11:33:55 -0700487 std::string type(method_info.GetSignature());
Alex Lightb7edcda2017-04-27 13:20:31 -0700488 type = type.substr(type.find(")") + 1);
489 std::string out_val(was_popped_by_exception ? "" : GetValOf(jvmtienv, env, type, val));
Alex Lightbad2f512017-06-14 11:33:55 -0700490 LOG(INFO) << "Leaving method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"."
491 << std::endl
Alex Lightb7edcda2017-04-27 13:20:31 -0700492 << " Cause: " << (was_popped_by_exception ? "exception" : "return ")
493 << out_val << ".";
Alex Lightb7edcda2017-04-27 13:20:31 -0700494}
495
496void JNICALL MethodEntryHook(jvmtiEnv* jvmtienv,
497 JNIEnv* env,
498 jthread thread,
499 jmethodID m) {
Alex Lightbad2f512017-06-14 11:33:55 -0700500 ScopedThreadInfo info(jvmtienv, env, thread);
501 ScopedMethodInfo method_info(jvmtienv, env, m);
502 if (!method_info.Init()) {
503 LOG(ERROR) << "Unable to get method info!";
Alex Lightb7edcda2017-04-27 13:20:31 -0700504 return;
505 }
Alex Lightbad2f512017-06-14 11:33:55 -0700506 LOG(INFO) << "Entering method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"";
Alex Lightb7edcda2017-04-27 13:20:31 -0700507}
508
Alex Light72398652017-06-16 09:08:12 -0700509void JNICALL ClassPrepareHook(jvmtiEnv* jvmtienv,
510 JNIEnv* env,
511 jthread thread,
512 jclass klass) {
Alex Light43e935d2017-06-19 15:40:40 -0700513 StressData* data = nullptr;
514 CHECK_EQ(jvmtienv->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
515 JVMTI_ERROR_NONE);
516 if (data->field_stress) {
517 jint nfields;
518 jfieldID* fields;
519 if (jvmtienv->GetClassFields(klass, &nfields, &fields) != JVMTI_ERROR_NONE) {
520 LOG(ERROR) << "Unable to get a classes fields!";
521 return;
522 }
523 for (jint i = 0; i < nfields; i++) {
524 jfieldID f = fields[i];
525 // Ignore errors
526 jvmtienv->SetFieldAccessWatch(klass, f);
527 jvmtienv->SetFieldModificationWatch(klass, f);
528 }
529 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fields));
Alex Light72398652017-06-16 09:08:12 -0700530 }
Alex Light43e935d2017-06-19 15:40:40 -0700531 if (data->trace_stress) {
532 ScopedThreadInfo info(jvmtienv, env, thread);
533 ScopedClassInfo class_info(jvmtienv, klass);
534 if (!class_info.Init()) {
535 LOG(ERROR) << "Unable to get class info!";
536 return;
537 }
538 LOG(INFO) << "Prepared class \"" << class_info.GetName() << "\". Thread is \""
539 << info.GetName() << "\"";
540 }
Alex Light72398652017-06-16 09:08:12 -0700541}
542
Alex Light8f2c6d42017-04-10 16:27:35 -0700543// The hook we are using.
544void JNICALL ClassFileLoadHookSecretNoOp(jvmtiEnv* jvmti,
545 JNIEnv* jni_env ATTRIBUTE_UNUSED,
546 jclass class_being_redefined ATTRIBUTE_UNUSED,
547 jobject loader ATTRIBUTE_UNUSED,
548 const char* name,
549 jobject protection_domain ATTRIBUTE_UNUSED,
550 jint class_data_len,
551 const unsigned char* class_data,
552 jint* new_class_data_len,
553 unsigned char** new_class_data) {
554 std::vector<unsigned char> out;
555 std::string name_str(name);
556 // Make the jvmti semi-descriptor into the java style descriptor (though with $ for inner
557 // classes).
558 std::replace(name_str.begin(), name_str.end(), '/', '.');
559 StressData* data = nullptr;
560 CHECK_EQ(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
561 JVMTI_ERROR_NONE);
562 if (!data->vm_class_loader_initialized) {
563 LOG(WARNING) << "Ignoring load of class " << name << " because VMClassLoader is not yet "
564 << "initialized. Transforming this class could cause spurious test failures.";
565 return;
566 } else if (DoExtractClassFromData(data, name_str, class_data_len, class_data, /*out*/ &out)) {
567 LOG(INFO) << "Extracted class: " << name;
568 unsigned char* new_data;
569 CHECK_EQ(JVMTI_ERROR_NONE, jvmti->Allocate(out.size(), &new_data));
570 memcpy(new_data, out.data(), out.size());
571 *new_class_data_len = static_cast<jint>(out.size());
572 *new_class_data = new_data;
573 } else {
574 std::cerr << "Unable to extract class " << name_str << std::endl;
575 *new_class_data_len = 0;
576 *new_class_data = nullptr;
577 }
578}
579
Alex Lightb7edcda2017-04-27 13:20:31 -0700580static std::string AdvanceOption(const std::string& ops) {
581 return ops.substr(ops.find(',') + 1);
Alex Light8f2c6d42017-04-10 16:27:35 -0700582}
583
Alex Lightb7edcda2017-04-27 13:20:31 -0700584static bool HasNextOption(const std::string& ops) {
585 return ops.find(',') != std::string::npos;
586}
587
588static std::string GetOption(const std::string& in) {
589 return in.substr(0, in.find(','));
590}
591
592// Options are
Alex Light43e935d2017-06-19 15:40:40 -0700593// jvmti-stress,[redefine,${DEXTER_BINARY},${TEMP_FILE_1},${TEMP_FILE_2},][trace,][field]
Alex Lightb7edcda2017-04-27 13:20:31 -0700594static void ReadOptions(StressData* data, char* options) {
595 std::string ops(options);
596 CHECK_EQ(GetOption(ops), "jvmti-stress") << "Options should start with jvmti-stress";
597 do {
598 ops = AdvanceOption(ops);
599 std::string cur = GetOption(ops);
600 if (cur == "trace") {
601 data->trace_stress = true;
Alex Light43e935d2017-06-19 15:40:40 -0700602 } else if (cur == "field") {
603 data->field_stress = true;
Alex Lightb7edcda2017-04-27 13:20:31 -0700604 } else if (cur == "redefine") {
605 data->redefine_stress = true;
606 ops = AdvanceOption(ops);
607 data->dexter_cmd = GetOption(ops);
608 ops = AdvanceOption(ops);
609 data->in_temp_dex = GetOption(ops);
610 ops = AdvanceOption(ops);
611 data->out_temp_dex = GetOption(ops);
612 } else {
613 LOG(FATAL) << "Unknown option: " << GetOption(ops);
614 }
615 } while (HasNextOption(ops));
616}
617
618// Do final setup during the VMInit callback. By this time most things are all setup.
619static void JNICALL PerformFinalSetupVMInit(jvmtiEnv *jvmti_env,
620 JNIEnv* jni_env,
621 jthread thread ATTRIBUTE_UNUSED) {
Alex Light8f2c6d42017-04-10 16:27:35 -0700622 // Load the VMClassLoader class. We will get a ClassNotFound exception because we don't have
623 // visibility but the class will be loaded behind the scenes.
624 LOG(INFO) << "manual load & initialization of class java/lang/VMClassLoader!";
625 jclass klass = jni_env->FindClass("java/lang/VMClassLoader");
Alex Lightb7edcda2017-04-27 13:20:31 -0700626 StressData* data = nullptr;
627 CHECK_EQ(jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
628 JVMTI_ERROR_NONE);
629 // We need to make sure that VMClassLoader is initialized before we start redefining anything
630 // since it can give (non-fatal) error messages if it's initialized after we've redefined BCP
631 // classes. These error messages are expected and no problem but they will mess up our testing
632 // infrastructure.
Alex Light8f2c6d42017-04-10 16:27:35 -0700633 if (klass == nullptr) {
Alex Light42151c02017-04-20 15:54:25 -0700634 // Probably on RI. Clear the exception so we can continue but don't mark vmclassloader as
635 // initialized.
636 LOG(WARNING) << "Unable to find VMClassLoader class!";
637 jni_env->ExceptionClear();
Alex Light8f2c6d42017-04-10 16:27:35 -0700638 } else {
639 // GetMethodID is spec'd to cause the class to be initialized.
640 jni_env->GetMethodID(klass, "hashCode", "()I");
641 jni_env->DeleteLocalRef(klass);
Alex Light8f2c6d42017-04-10 16:27:35 -0700642 data->vm_class_loader_initialized = true;
643 }
Alex Light43e935d2017-06-19 15:40:40 -0700644}
645
646static bool WatchAllFields(JavaVM* vm, jvmtiEnv* jvmti) {
647 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
648 JVMTI_EVENT_CLASS_PREPARE,
649 nullptr) != JVMTI_ERROR_NONE) {
650 LOG(ERROR) << "Couldn't set prepare event!";
651 return false;
Alex Lightb7edcda2017-04-27 13:20:31 -0700652 }
Alex Light43e935d2017-06-19 15:40:40 -0700653 // TODO We really shouldn't need to do this step here.
654 jint nklass;
655 jclass* klasses;
656 if (jvmti->GetLoadedClasses(&nklass, &klasses) != JVMTI_ERROR_NONE) {
657 LOG(WARNING) << "Couldn't get loaded classes! Ignoring.";
658 return true;
659 }
660 JNIEnv* jni = nullptr;
661 if (vm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6)) {
662 LOG(ERROR) << "Unable to get jni env. Ignoring and potentially leaking jobjects.";
663 return false;
664 }
665 for (jint i = 0; i < nklass; i++) {
666 jclass k = klasses[i];
667 ScopedClassInfo sci(jvmti, k);
668 if (sci.Init()) {
669 LOG(INFO) << "NOTE: class " << sci.GetName() << " already loaded.";
670 }
671 jint nfields;
672 jfieldID* fields;
673 jvmtiError err = jvmti->GetClassFields(k, &nfields, &fields);
674 if (err == JVMTI_ERROR_NONE) {
675 for (jint j = 0; j < nfields; j++) {
676 jfieldID f = fields[j];
677 if (jvmti->SetFieldModificationWatch(k, f) != JVMTI_ERROR_NONE ||
678 jvmti->SetFieldAccessWatch(k, f) != JVMTI_ERROR_NONE) {
679 LOG(ERROR) << "Unable to set watches on a field.";
680 return false;
681 }
682 }
683 } else if (err != JVMTI_ERROR_CLASS_NOT_PREPARED) {
684 LOG(ERROR) << "Unexpected error getting class fields!";
685 return false;
686 }
687 jvmti->Deallocate(reinterpret_cast<unsigned char*>(fields));
688 jni->DeleteLocalRef(k);
689 }
690 jvmti->Deallocate(reinterpret_cast<unsigned char*>(klasses));
691 return true;
Alex Light8f2c6d42017-04-10 16:27:35 -0700692}
693
694extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm,
695 char* options,
696 void* reserved ATTRIBUTE_UNUSED) {
697 jvmtiEnv* jvmti = nullptr;
698 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0)) {
699 LOG(ERROR) << "Unable to get jvmti env.";
700 return 1;
701 }
702 StressData* data = nullptr;
703 if (JVMTI_ERROR_NONE != jvmti->Allocate(sizeof(StressData),
704 reinterpret_cast<unsigned char**>(&data))) {
705 LOG(ERROR) << "Unable to allocate data for stress test.";
706 return 1;
707 }
708 memset(data, 0, sizeof(StressData));
709 // Read the options into the static variables that hold them.
710 ReadOptions(data, options);
711 // Save the data
712 if (JVMTI_ERROR_NONE != jvmti->SetEnvironmentLocalStorage(data)) {
713 LOG(ERROR) << "Unable to save stress test data.";
714 return 1;
715 }
716
717 // Just get all capabilities.
718 jvmtiCapabilities caps;
719 jvmti->GetPotentialCapabilities(&caps);
720 jvmti->AddCapabilities(&caps);
721
722 // Set callbacks.
723 jvmtiEventCallbacks cb;
724 memset(&cb, 0, sizeof(cb));
725 cb.ClassFileLoadHook = ClassFileLoadHookSecretNoOp;
Alex Light0af8cde2017-04-20 13:35:05 -0700726 cb.NativeMethodBind = doJvmtiMethodBind;
Alex Lightb7edcda2017-04-27 13:20:31 -0700727 cb.VMInit = PerformFinalSetupVMInit;
728 cb.MethodEntry = MethodEntryHook;
729 cb.MethodExit = MethodExitHook;
Alex Light43e935d2017-06-19 15:40:40 -0700730 cb.FieldAccess = FieldAccessHook;
731 cb.FieldModification = FieldModificationHook;
Alex Light72398652017-06-16 09:08:12 -0700732 cb.ClassPrepare = ClassPrepareHook;
Alex Light8f2c6d42017-04-10 16:27:35 -0700733 if (jvmti->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
734 LOG(ERROR) << "Unable to set class file load hook cb!";
735 return 1;
736 }
737 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
Alex Light8f2c6d42017-04-10 16:27:35 -0700738 JVMTI_EVENT_VM_INIT,
739 nullptr) != JVMTI_ERROR_NONE) {
740 LOG(ERROR) << "Unable to enable JVMTI_EVENT_VM_INIT event!";
741 return 1;
742 }
Alex Light43e935d2017-06-19 15:40:40 -0700743 if (data->redefine_stress) {
744 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
745 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
746 nullptr) != JVMTI_ERROR_NONE) {
747 LOG(ERROR) << "Unable to enable CLASS_FILE_LOAD_HOOK event!";
748 return 1;
749 }
750 }
Alex Light72398652017-06-16 09:08:12 -0700751 if (data->trace_stress) {
752 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
753 JVMTI_EVENT_CLASS_PREPARE,
754 nullptr) != JVMTI_ERROR_NONE) {
755 LOG(ERROR) << "Unable to enable CLASS_PREPARE event!";
756 return 1;
757 }
Alex Lightb7edcda2017-04-27 13:20:31 -0700758 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
Alex Light43e935d2017-06-19 15:40:40 -0700759 JVMTI_EVENT_NATIVE_METHOD_BIND,
Alex Lightb7edcda2017-04-27 13:20:31 -0700760 nullptr) != JVMTI_ERROR_NONE) {
Alex Light43e935d2017-06-19 15:40:40 -0700761 LOG(ERROR) << "Unable to enable JVMTI_EVENT_NATIVE_METHOD_BIND event!";
762 return 1;
763 }
764 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
765 JVMTI_EVENT_METHOD_ENTRY,
766 nullptr) != JVMTI_ERROR_NONE) {
767 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_ENTRY event!";
768 return 1;
769 }
770 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
771 JVMTI_EVENT_METHOD_EXIT,
772 nullptr) != JVMTI_ERROR_NONE) {
773 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_EXIT event!";
774 return 1;
775 }
776 }
777 if (data->field_stress) {
778 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
779 JVMTI_EVENT_FIELD_MODIFICATION,
780 nullptr) != JVMTI_ERROR_NONE) {
781 LOG(ERROR) << "Unable to enable FIELD_MODIFICATION event!";
782 return 1;
783 }
784 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
785 JVMTI_EVENT_FIELD_ACCESS,
786 nullptr) != JVMTI_ERROR_NONE) {
787 LOG(ERROR) << "Unable to enable FIELD_ACCESS event!";
788 return 1;
789 }
790 if (!WatchAllFields(vm, jvmti)) {
Alex Lightb7edcda2017-04-27 13:20:31 -0700791 return 1;
792 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700793 }
794 return 0;
795}
796
797} // namespace art