blob: 06d5af0e3632733fa704a9282396d6b0baebccff [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
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070017#include <cstdio>
Alex Light8f2c6d42017-04-10 16:27:35 -070018#include <fstream>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070019#include <iomanip>
20#include <iostream>
Alex Lightbad2f512017-06-14 11:33:55 -070021#include <memory>
Alex Light8f2c6d42017-04-10 16:27:35 -070022#include <sstream>
Alex Lightb7edcda2017-04-27 13:20:31 -070023#include <strstream>
Alex Light8f2c6d42017-04-10 16:27:35 -070024
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070025#include <jni.h>
26
Alex Light8f2c6d42017-04-10 16:27:35 -070027#include "exec_utils.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070028#include "jvmti.h"
Alex Light8f2c6d42017-04-10 16:27:35 -070029#include "utils.h"
30
31namespace art {
32
33// Should we do a 'full_rewrite' with this test?
34static constexpr bool kDoFullRewrite = true;
35
36struct StressData {
37 std::string dexter_cmd;
38 std::string out_temp_dex;
39 std::string in_temp_dex;
40 bool vm_class_loader_initialized;
Alex Lightb7edcda2017-04-27 13:20:31 -070041 bool trace_stress;
42 bool redefine_stress;
Alex Light43e935d2017-06-19 15:40:40 -070043 bool field_stress;
Alex Lightc38c3692017-06-27 15:45:14 -070044 bool step_stress;
Alex Light8f2c6d42017-04-10 16:27:35 -070045};
46
47static void WriteToFile(const std::string& fname, jint data_len, const unsigned char* data) {
48 std::ofstream file(fname, std::ios::binary | std::ios::out | std::ios::trunc);
49 file.write(reinterpret_cast<const char*>(data), data_len);
50 file.flush();
51}
52
53static bool ReadIntoBuffer(const std::string& fname, /*out*/std::vector<unsigned char>* data) {
54 std::ifstream file(fname, std::ios::binary | std::ios::in);
55 file.seekg(0, std::ios::end);
56 size_t len = file.tellg();
57 data->resize(len);
58 file.seekg(0);
59 file.read(reinterpret_cast<char*>(data->data()), len);
60 return len != 0;
61}
62
63// TODO rewrite later.
64static bool DoExtractClassFromData(StressData* data,
65 const std::string& class_name,
66 jint in_len,
67 const unsigned char* in_data,
68 /*out*/std::vector<unsigned char>* dex) {
69 // Write the dex file into a temporary file.
70 WriteToFile(data->in_temp_dex, in_len, in_data);
71 // Clear out file so even if something suppresses the exit value we will still detect dexter
72 // failure.
73 WriteToFile(data->out_temp_dex, 0, nullptr);
74 // Have dexter do the extraction.
75 std::vector<std::string> args;
76 args.push_back(data->dexter_cmd);
77 if (kDoFullRewrite) {
78 args.push_back("-x");
79 args.push_back("full_rewrite");
80 }
81 args.push_back("-e");
82 args.push_back(class_name);
83 args.push_back("-o");
84 args.push_back(data->out_temp_dex);
85 args.push_back(data->in_temp_dex);
86 std::string error;
87 if (ExecAndReturnCode(args, &error) != 0) {
88 LOG(ERROR) << "unable to execute dexter: " << error;
89 return false;
90 }
91 return ReadIntoBuffer(data->out_temp_dex, dex);
92}
93
Alex Lightbad2f512017-06-14 11:33:55 -070094class ScopedThreadInfo {
95 public:
96 ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread)
97 : jvmtienv_(jvmtienv), env_(env), free_name_(false) {
98 memset(&info_, 0, sizeof(info_));
99 if (thread == nullptr) {
100 info_.name = const_cast<char*>("<NULLPTR>");
101 } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) {
102 info_.name = const_cast<char*>("<UNKNOWN THREAD>");
103 } else {
104 free_name_ = true;
105 }
106 }
107
108 ~ScopedThreadInfo() {
109 if (free_name_) {
110 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name));
111 }
112 env_->DeleteLocalRef(info_.thread_group);
113 env_->DeleteLocalRef(info_.context_class_loader);
114 }
115
116 const char* GetName() const {
117 return info_.name;
118 }
119
120 private:
121 jvmtiEnv* jvmtienv_;
122 JNIEnv* env_;
123 bool free_name_;
124 jvmtiThreadInfo info_;
125};
126
127class ScopedClassInfo {
128 public:
129 ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c)
130 : jvmtienv_(jvmtienv),
131 class_(c),
132 name_(nullptr),
Alex Light6fa7b812017-06-16 09:04:29 -0700133 generic_(nullptr),
134 file_(nullptr),
135 debug_ext_(nullptr) {}
Alex Lightbad2f512017-06-14 11:33:55 -0700136
137 ~ScopedClassInfo() {
Alex Light43e935d2017-06-19 15:40:40 -0700138 if (class_ != nullptr) {
139 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
140 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
Alex Light6fa7b812017-06-16 09:04:29 -0700141 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(file_));
142 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(debug_ext_));
Alex Light43e935d2017-06-19 15:40:40 -0700143 }
Alex Lightbad2f512017-06-14 11:33:55 -0700144 }
145
146 bool Init() {
Alex Light43e935d2017-06-19 15:40:40 -0700147 if (class_ == nullptr) {
148 name_ = const_cast<char*>("<NONE>");
149 generic_ = const_cast<char*>("<NONE>");
150 return true;
151 } else {
Alex Light6fa7b812017-06-16 09:04:29 -0700152 jvmtiError ret1 = jvmtienv_->GetSourceFileName(class_, &file_);
153 jvmtiError ret2 = jvmtienv_->GetSourceDebugExtension(class_, &debug_ext_);
154 return jvmtienv_->GetClassSignature(class_, &name_, &generic_) == JVMTI_ERROR_NONE &&
155 ret1 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
156 ret1 != JVMTI_ERROR_INVALID_CLASS &&
157 ret2 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
158 ret2 != JVMTI_ERROR_INVALID_CLASS;
Alex Light43e935d2017-06-19 15:40:40 -0700159 }
Alex Lightbad2f512017-06-14 11:33:55 -0700160 }
161
162 jclass GetClass() const {
163 return class_;
164 }
165 const char* GetName() const {
166 return name_;
167 }
168 const char* GetGeneric() const {
169 return generic_;
170 }
Alex Light6fa7b812017-06-16 09:04:29 -0700171 const char* GetSourceDebugExtension() const {
172 if (debug_ext_ == nullptr) {
173 return "<UNKNOWN_SOURCE_DEBUG_EXTENSION>";
174 } else {
175 return debug_ext_;
176 }
177 }
178 const char* GetSourceFileName() const {
179 if (file_ == nullptr) {
180 return "<UNKNOWN_FILE>";
181 } else {
182 return file_;
183 }
184 }
Alex Lightbad2f512017-06-14 11:33:55 -0700185
186 private:
187 jvmtiEnv* jvmtienv_;
188 jclass class_;
189 char* name_;
190 char* generic_;
Alex Light6fa7b812017-06-16 09:04:29 -0700191 char* file_;
192 char* debug_ext_;
Alex Lightbad2f512017-06-14 11:33:55 -0700193};
194
195class ScopedMethodInfo {
196 public:
197 ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m)
198 : jvmtienv_(jvmtienv),
199 env_(env),
200 method_(m),
201 declaring_class_(nullptr),
202 class_info_(nullptr),
203 name_(nullptr),
204 signature_(nullptr),
Alex Light6fa7b812017-06-16 09:04:29 -0700205 generic_(nullptr),
206 first_line_(-1) {}
Alex Lightbad2f512017-06-14 11:33:55 -0700207
208 ~ScopedMethodInfo() {
209 env_->DeleteLocalRef(declaring_class_);
210 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
211 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
212 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
213 }
214
215 bool Init() {
216 if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
217 return false;
218 }
219 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
Alex Light6fa7b812017-06-16 09:04:29 -0700220 jint nlines;
221 jvmtiLineNumberEntry* lines;
222 jvmtiError err = jvmtienv_->GetLineNumberTable(method_, &nlines, &lines);
223 if (err == JVMTI_ERROR_NONE) {
224 if (nlines > 0) {
225 first_line_ = lines[0].line_number;
226 }
227 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(lines));
228 } else if (err != JVMTI_ERROR_ABSENT_INFORMATION &&
229 err != JVMTI_ERROR_NATIVE_METHOD) {
230 return false;
231 }
Alex Lightbad2f512017-06-14 11:33:55 -0700232 return class_info_->Init() &&
233 (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
234 }
235
236 const ScopedClassInfo& GetDeclaringClassInfo() const {
237 return *class_info_;
238 }
239
240 jclass GetDeclaringClass() const {
241 return declaring_class_;
242 }
243
244 const char* GetName() const {
245 return name_;
246 }
247
248 const char* GetSignature() const {
249 return signature_;
250 }
251
252 const char* GetGeneric() const {
253 return generic_;
254 }
255
Alex Light6fa7b812017-06-16 09:04:29 -0700256 jint GetFirstLine() const {
257 return first_line_;
258 }
259
Alex Lightbad2f512017-06-14 11:33:55 -0700260 private:
261 jvmtiEnv* jvmtienv_;
262 JNIEnv* env_;
263 jmethodID method_;
264 jclass declaring_class_;
265 std::unique_ptr<ScopedClassInfo> class_info_;
266 char* name_;
267 char* signature_;
268 char* generic_;
Alex Light6fa7b812017-06-16 09:04:29 -0700269 jint first_line_;
Alex Lightbad2f512017-06-14 11:33:55 -0700270
271 friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
272};
273
Alex Light43e935d2017-06-19 15:40:40 -0700274class ScopedFieldInfo {
275 public:
276 ScopedFieldInfo(jvmtiEnv* jvmtienv, jclass field_klass, jfieldID field)
277 : jvmtienv_(jvmtienv),
278 declaring_class_(field_klass),
279 field_(field),
280 class_info_(nullptr),
281 name_(nullptr),
282 type_(nullptr),
283 generic_(nullptr) {}
284
285 ~ScopedFieldInfo() {
286 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
287 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(type_));
288 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
289 }
290
291 bool Init() {
292 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
293 return class_info_->Init() &&
294 (jvmtienv_->GetFieldName(
295 declaring_class_, field_, &name_, &type_, &generic_) == JVMTI_ERROR_NONE);
296 }
297
298 const ScopedClassInfo& GetDeclaringClassInfo() const {
299 return *class_info_;
300 }
301
302 jclass GetDeclaringClass() const {
303 return declaring_class_;
304 }
305
306 const char* GetName() const {
307 return name_;
308 }
309
310 const char* GetType() const {
311 return type_;
312 }
313
314 const char* GetGeneric() const {
315 return generic_;
316 }
317
318 private:
319 jvmtiEnv* jvmtienv_;
320 jclass declaring_class_;
321 jfieldID field_;
322 std::unique_ptr<ScopedClassInfo> class_info_;
323 char* name_;
324 char* type_;
325 char* generic_;
326
327 friend std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m);
328};
329
330std::ostream& operator<<(std::ostream &os, const ScopedFieldInfo* m) {
331 return os << *m;
332}
333
334std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m) {
335 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName()
336 << ":" << m.GetType();
337}
338
Alex Lightbad2f512017-06-14 11:33:55 -0700339std::ostream& operator<<(std::ostream &os, const ScopedMethodInfo* m) {
340 return os << *m;
341}
342
343std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
Alex Light6fa7b812017-06-16 09:04:29 -0700344 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature()
345 << " (source: " << m.GetDeclaringClassInfo().GetSourceFileName() << ":"
346 << m.GetFirstLine() << ")";
Alex Lightbad2f512017-06-14 11:33:55 -0700347}
348
Alex Light0af8cde2017-04-20 13:35:05 -0700349static void doJvmtiMethodBind(jvmtiEnv* jvmtienv,
350 JNIEnv* env,
351 jthread thread,
352 jmethodID m,
353 void* address,
354 /*out*/void** out_address) {
355 *out_address = address;
Alex Lightbad2f512017-06-14 11:33:55 -0700356 ScopedThreadInfo thread_info(jvmtienv, env, thread);
357 ScopedMethodInfo method_info(jvmtienv, env, m);
358 if (!method_info.Init()) {
359 LOG(ERROR) << "Unable to get method info!";
Alex Light0af8cde2017-04-20 13:35:05 -0700360 return;
361 }
Alex Lightbad2f512017-06-14 11:33:55 -0700362 LOG(INFO) << "Loading native method \"" << method_info << "\". Thread is "
363 << thread_info.GetName();
Alex Light0af8cde2017-04-20 13:35:05 -0700364}
365
Alex Lightb7edcda2017-04-27 13:20:31 -0700366static std::string GetName(jvmtiEnv* jvmtienv, JNIEnv* jnienv, jobject obj) {
367 jclass klass = jnienv->GetObjectClass(obj);
368 char *cname, *cgen;
369 if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
370 LOG(ERROR) << "Unable to get class name!";
371 jnienv->DeleteLocalRef(klass);
372 return "<UNKNOWN>";
373 }
374 std::string name(cname);
375 if (name == "Ljava/lang/String;") {
376 jstring str = reinterpret_cast<jstring>(obj);
377 const char* val = jnienv->GetStringUTFChars(str, nullptr);
378 if (val == nullptr) {
379 name += " (unable to get value)";
380 } else {
381 std::ostringstream oss;
382 oss << name << " (value: \"" << val << "\")";
383 name = oss.str();
384 jnienv->ReleaseStringUTFChars(str, val);
385 }
386 }
387 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
388 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
389 jnienv->DeleteLocalRef(klass);
390 return name;
391}
392
393static std::string GetValOf(jvmtiEnv* env, JNIEnv* jnienv, std::string type, jvalue val) {
394 std::ostringstream oss;
395 switch (type[0]) {
396 case '[':
397 case 'L':
398 return val.l != nullptr ? GetName(env, jnienv, val.l) : "null";
399 case 'Z':
400 return val.z == JNI_TRUE ? "true" : "false";
401 case 'B':
402 oss << val.b;
403 return oss.str();
404 case 'C':
405 oss << val.c;
406 return oss.str();
407 case 'S':
408 oss << val.s;
409 return oss.str();
410 case 'I':
411 oss << val.i;
412 return oss.str();
413 case 'J':
414 oss << val.j;
415 return oss.str();
416 case 'F':
417 oss << val.f;
418 return oss.str();
419 case 'D':
420 oss << val.d;
421 return oss.str();
422 case 'V':
423 return "<void>";
424 default:
425 return "<ERROR Found type " + type + ">";
426 }
427}
428
Alex Light43e935d2017-06-19 15:40:40 -0700429void JNICALL FieldAccessHook(jvmtiEnv* jvmtienv,
430 JNIEnv* env,
431 jthread thread,
432 jmethodID m,
433 jlocation location,
434 jclass field_klass,
435 jobject object,
436 jfieldID field) {
437 ScopedThreadInfo info(jvmtienv, env, thread);
438 ScopedMethodInfo method_info(jvmtienv, env, m);
439 ScopedFieldInfo field_info(jvmtienv, field_klass, field);
440 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr;
441 ScopedClassInfo obj_class_info(jvmtienv, oklass);
442 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) {
443 LOG(ERROR) << "Unable to get callback info!";
444 return;
445 }
446 LOG(INFO) << "ACCESS field \"" << field_info << "\" on object of "
447 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info
448 << "\" at location 0x" << std::hex << location << ". Thread is \""
449 << info.GetName() << "\".";
450 env->DeleteLocalRef(oklass);
451}
452
453static std::string PrintJValue(jvmtiEnv* jvmtienv, JNIEnv* env, char type, jvalue new_value) {
454 std::ostringstream oss;
455 switch (type) {
456 case 'L': {
457 jobject nv = new_value.l;
458 if (nv == nullptr) {
459 oss << "\"null\"";
460 } else {
461 jclass nv_klass = env->GetObjectClass(nv);
462 ScopedClassInfo nv_class_info(jvmtienv, nv_klass);
463 if (!nv_class_info.Init()) {
464 oss << "with unknown type";
465 } else {
466 oss << "of type \"" << nv_class_info.GetName() << "\"";
467 }
468 env->DeleteLocalRef(nv_klass);
469 }
470 break;
471 }
472 case 'Z': {
473 if (new_value.z) {
474 oss << "true";
475 } else {
476 oss << "false";
477 }
478 break;
479 }
480#define SEND_VALUE(chr, sym, type) \
481 case chr: { \
482 oss << static_cast<type>(new_value.sym); \
483 break; \
484 }
485 SEND_VALUE('B', b, int8_t);
486 SEND_VALUE('C', c, uint16_t);
487 SEND_VALUE('S', s, int16_t);
488 SEND_VALUE('I', i, int32_t);
489 SEND_VALUE('J', j, int64_t);
490 SEND_VALUE('F', f, float);
491 SEND_VALUE('D', d, double);
492#undef SEND_VALUE
493 }
494 return oss.str();
495}
496
497void JNICALL FieldModificationHook(jvmtiEnv* jvmtienv,
498 JNIEnv* env,
499 jthread thread,
500 jmethodID m,
501 jlocation location,
502 jclass field_klass,
503 jobject object,
504 jfieldID field,
505 char type,
506 jvalue new_value) {
507 ScopedThreadInfo info(jvmtienv, env, thread);
508 ScopedMethodInfo method_info(jvmtienv, env, m);
509 ScopedFieldInfo field_info(jvmtienv, field_klass, field);
510 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr;
511 ScopedClassInfo obj_class_info(jvmtienv, oklass);
512 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) {
513 LOG(ERROR) << "Unable to get callback info!";
514 return;
515 }
516 LOG(INFO) << "MODIFY field \"" << field_info << "\" on object of "
517 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info
518 << "\" at location 0x" << std::hex << location << std::dec << ". New value is "
519 << PrintJValue(jvmtienv, env, type, new_value) << ". Thread is \""
520 << info.GetName() << "\".";
521 env->DeleteLocalRef(oklass);
522}
Alex Lightb7edcda2017-04-27 13:20:31 -0700523void JNICALL MethodExitHook(jvmtiEnv* jvmtienv,
524 JNIEnv* env,
525 jthread thread,
526 jmethodID m,
527 jboolean was_popped_by_exception,
528 jvalue val) {
Alex Lightbad2f512017-06-14 11:33:55 -0700529 ScopedThreadInfo info(jvmtienv, env, thread);
530 ScopedMethodInfo method_info(jvmtienv, env, m);
531 if (!method_info.Init()) {
532 LOG(ERROR) << "Unable to get method info!";
Alex Lightb7edcda2017-04-27 13:20:31 -0700533 return;
534 }
Alex Lightbad2f512017-06-14 11:33:55 -0700535 std::string type(method_info.GetSignature());
Alex Lightb7edcda2017-04-27 13:20:31 -0700536 type = type.substr(type.find(")") + 1);
537 std::string out_val(was_popped_by_exception ? "" : GetValOf(jvmtienv, env, type, val));
Alex Lightbad2f512017-06-14 11:33:55 -0700538 LOG(INFO) << "Leaving method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"."
539 << std::endl
Alex Lightb7edcda2017-04-27 13:20:31 -0700540 << " Cause: " << (was_popped_by_exception ? "exception" : "return ")
541 << out_val << ".";
Alex Lightb7edcda2017-04-27 13:20:31 -0700542}
543
544void JNICALL MethodEntryHook(jvmtiEnv* jvmtienv,
545 JNIEnv* env,
546 jthread thread,
547 jmethodID m) {
Alex Lightbad2f512017-06-14 11:33:55 -0700548 ScopedThreadInfo info(jvmtienv, env, thread);
549 ScopedMethodInfo method_info(jvmtienv, env, m);
550 if (!method_info.Init()) {
551 LOG(ERROR) << "Unable to get method info!";
Alex Lightb7edcda2017-04-27 13:20:31 -0700552 return;
553 }
Alex Lightbad2f512017-06-14 11:33:55 -0700554 LOG(INFO) << "Entering method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"";
Alex Lightb7edcda2017-04-27 13:20:31 -0700555}
556
Alex Light72398652017-06-16 09:08:12 -0700557void JNICALL ClassPrepareHook(jvmtiEnv* jvmtienv,
558 JNIEnv* env,
559 jthread thread,
560 jclass klass) {
Alex Light43e935d2017-06-19 15:40:40 -0700561 StressData* data = nullptr;
562 CHECK_EQ(jvmtienv->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
563 JVMTI_ERROR_NONE);
564 if (data->field_stress) {
565 jint nfields;
566 jfieldID* fields;
567 if (jvmtienv->GetClassFields(klass, &nfields, &fields) != JVMTI_ERROR_NONE) {
568 LOG(ERROR) << "Unable to get a classes fields!";
569 return;
570 }
571 for (jint i = 0; i < nfields; i++) {
572 jfieldID f = fields[i];
573 // Ignore errors
574 jvmtienv->SetFieldAccessWatch(klass, f);
575 jvmtienv->SetFieldModificationWatch(klass, f);
576 }
577 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fields));
Alex Light72398652017-06-16 09:08:12 -0700578 }
Alex Light43e935d2017-06-19 15:40:40 -0700579 if (data->trace_stress) {
580 ScopedThreadInfo info(jvmtienv, env, thread);
581 ScopedClassInfo class_info(jvmtienv, klass);
582 if (!class_info.Init()) {
583 LOG(ERROR) << "Unable to get class info!";
584 return;
585 }
586 LOG(INFO) << "Prepared class \"" << class_info.GetName() << "\". Thread is \""
587 << info.GetName() << "\"";
588 }
Alex Light72398652017-06-16 09:08:12 -0700589}
590
Alex Lightc38c3692017-06-27 15:45:14 -0700591void JNICALL SingleStepHook(jvmtiEnv* jvmtienv,
592 JNIEnv* env,
593 jthread thread,
594 jmethodID method,
595 jlocation location) {
596 ScopedThreadInfo info(jvmtienv, env, thread);
597 ScopedMethodInfo method_info(jvmtienv, env, method);
598 if (!method_info.Init()) {
599 LOG(ERROR) << "Unable to get method info!";
600 return;
601 }
602 LOG(INFO) << "Single step at location: 0x" << std::setw(8) << std::setfill('0') << std::hex
603 << location << " in method " << method_info << " thread: " << info.GetName();
604}
605
Alex Light8f2c6d42017-04-10 16:27:35 -0700606// The hook we are using.
607void JNICALL ClassFileLoadHookSecretNoOp(jvmtiEnv* jvmti,
608 JNIEnv* jni_env ATTRIBUTE_UNUSED,
609 jclass class_being_redefined ATTRIBUTE_UNUSED,
610 jobject loader ATTRIBUTE_UNUSED,
611 const char* name,
612 jobject protection_domain ATTRIBUTE_UNUSED,
613 jint class_data_len,
614 const unsigned char* class_data,
615 jint* new_class_data_len,
616 unsigned char** new_class_data) {
617 std::vector<unsigned char> out;
618 std::string name_str(name);
619 // Make the jvmti semi-descriptor into the java style descriptor (though with $ for inner
620 // classes).
621 std::replace(name_str.begin(), name_str.end(), '/', '.');
622 StressData* data = nullptr;
623 CHECK_EQ(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
624 JVMTI_ERROR_NONE);
625 if (!data->vm_class_loader_initialized) {
626 LOG(WARNING) << "Ignoring load of class " << name << " because VMClassLoader is not yet "
627 << "initialized. Transforming this class could cause spurious test failures.";
628 return;
629 } else if (DoExtractClassFromData(data, name_str, class_data_len, class_data, /*out*/ &out)) {
630 LOG(INFO) << "Extracted class: " << name;
631 unsigned char* new_data;
632 CHECK_EQ(JVMTI_ERROR_NONE, jvmti->Allocate(out.size(), &new_data));
633 memcpy(new_data, out.data(), out.size());
634 *new_class_data_len = static_cast<jint>(out.size());
635 *new_class_data = new_data;
636 } else {
637 std::cerr << "Unable to extract class " << name_str << std::endl;
638 *new_class_data_len = 0;
639 *new_class_data = nullptr;
640 }
641}
642
Alex Lightb7edcda2017-04-27 13:20:31 -0700643static std::string AdvanceOption(const std::string& ops) {
644 return ops.substr(ops.find(',') + 1);
Alex Light8f2c6d42017-04-10 16:27:35 -0700645}
646
Alex Lightb7edcda2017-04-27 13:20:31 -0700647static bool HasNextOption(const std::string& ops) {
648 return ops.find(',') != std::string::npos;
649}
650
651static std::string GetOption(const std::string& in) {
652 return in.substr(0, in.find(','));
653}
654
655// Options are
Alex Light43e935d2017-06-19 15:40:40 -0700656// jvmti-stress,[redefine,${DEXTER_BINARY},${TEMP_FILE_1},${TEMP_FILE_2},][trace,][field]
Alex Lightb7edcda2017-04-27 13:20:31 -0700657static void ReadOptions(StressData* data, char* options) {
658 std::string ops(options);
659 CHECK_EQ(GetOption(ops), "jvmti-stress") << "Options should start with jvmti-stress";
660 do {
661 ops = AdvanceOption(ops);
662 std::string cur = GetOption(ops);
663 if (cur == "trace") {
664 data->trace_stress = true;
Alex Lightc38c3692017-06-27 15:45:14 -0700665 } else if (cur == "step") {
666 data->step_stress = true;
Alex Light43e935d2017-06-19 15:40:40 -0700667 } else if (cur == "field") {
668 data->field_stress = true;
Alex Lightb7edcda2017-04-27 13:20:31 -0700669 } else if (cur == "redefine") {
670 data->redefine_stress = true;
671 ops = AdvanceOption(ops);
672 data->dexter_cmd = GetOption(ops);
673 ops = AdvanceOption(ops);
674 data->in_temp_dex = GetOption(ops);
675 ops = AdvanceOption(ops);
676 data->out_temp_dex = GetOption(ops);
677 } else {
678 LOG(FATAL) << "Unknown option: " << GetOption(ops);
679 }
680 } while (HasNextOption(ops));
681}
682
683// Do final setup during the VMInit callback. By this time most things are all setup.
684static void JNICALL PerformFinalSetupVMInit(jvmtiEnv *jvmti_env,
685 JNIEnv* jni_env,
686 jthread thread ATTRIBUTE_UNUSED) {
Alex Light8f2c6d42017-04-10 16:27:35 -0700687 // Load the VMClassLoader class. We will get a ClassNotFound exception because we don't have
688 // visibility but the class will be loaded behind the scenes.
689 LOG(INFO) << "manual load & initialization of class java/lang/VMClassLoader!";
690 jclass klass = jni_env->FindClass("java/lang/VMClassLoader");
Alex Lightb7edcda2017-04-27 13:20:31 -0700691 StressData* data = nullptr;
692 CHECK_EQ(jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
693 JVMTI_ERROR_NONE);
694 // We need to make sure that VMClassLoader is initialized before we start redefining anything
695 // since it can give (non-fatal) error messages if it's initialized after we've redefined BCP
696 // classes. These error messages are expected and no problem but they will mess up our testing
697 // infrastructure.
Alex Light8f2c6d42017-04-10 16:27:35 -0700698 if (klass == nullptr) {
Alex Light42151c02017-04-20 15:54:25 -0700699 // Probably on RI. Clear the exception so we can continue but don't mark vmclassloader as
700 // initialized.
701 LOG(WARNING) << "Unable to find VMClassLoader class!";
702 jni_env->ExceptionClear();
Alex Light8f2c6d42017-04-10 16:27:35 -0700703 } else {
704 // GetMethodID is spec'd to cause the class to be initialized.
705 jni_env->GetMethodID(klass, "hashCode", "()I");
706 jni_env->DeleteLocalRef(klass);
Alex Light8f2c6d42017-04-10 16:27:35 -0700707 data->vm_class_loader_initialized = true;
708 }
Alex Light43e935d2017-06-19 15:40:40 -0700709}
710
711static bool WatchAllFields(JavaVM* vm, jvmtiEnv* jvmti) {
712 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
713 JVMTI_EVENT_CLASS_PREPARE,
714 nullptr) != JVMTI_ERROR_NONE) {
715 LOG(ERROR) << "Couldn't set prepare event!";
716 return false;
Alex Lightb7edcda2017-04-27 13:20:31 -0700717 }
Alex Light43e935d2017-06-19 15:40:40 -0700718 // TODO We really shouldn't need to do this step here.
719 jint nklass;
720 jclass* klasses;
721 if (jvmti->GetLoadedClasses(&nklass, &klasses) != JVMTI_ERROR_NONE) {
722 LOG(WARNING) << "Couldn't get loaded classes! Ignoring.";
723 return true;
724 }
725 JNIEnv* jni = nullptr;
726 if (vm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6)) {
727 LOG(ERROR) << "Unable to get jni env. Ignoring and potentially leaking jobjects.";
728 return false;
729 }
730 for (jint i = 0; i < nklass; i++) {
731 jclass k = klasses[i];
732 ScopedClassInfo sci(jvmti, k);
733 if (sci.Init()) {
734 LOG(INFO) << "NOTE: class " << sci.GetName() << " already loaded.";
735 }
736 jint nfields;
737 jfieldID* fields;
738 jvmtiError err = jvmti->GetClassFields(k, &nfields, &fields);
739 if (err == JVMTI_ERROR_NONE) {
740 for (jint j = 0; j < nfields; j++) {
741 jfieldID f = fields[j];
742 if (jvmti->SetFieldModificationWatch(k, f) != JVMTI_ERROR_NONE ||
743 jvmti->SetFieldAccessWatch(k, f) != JVMTI_ERROR_NONE) {
744 LOG(ERROR) << "Unable to set watches on a field.";
745 return false;
746 }
747 }
748 } else if (err != JVMTI_ERROR_CLASS_NOT_PREPARED) {
749 LOG(ERROR) << "Unexpected error getting class fields!";
750 return false;
751 }
752 jvmti->Deallocate(reinterpret_cast<unsigned char*>(fields));
753 jni->DeleteLocalRef(k);
754 }
755 jvmti->Deallocate(reinterpret_cast<unsigned char*>(klasses));
756 return true;
Alex Light8f2c6d42017-04-10 16:27:35 -0700757}
758
759extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm,
760 char* options,
761 void* reserved ATTRIBUTE_UNUSED) {
762 jvmtiEnv* jvmti = nullptr;
763 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0)) {
764 LOG(ERROR) << "Unable to get jvmti env.";
765 return 1;
766 }
767 StressData* data = nullptr;
768 if (JVMTI_ERROR_NONE != jvmti->Allocate(sizeof(StressData),
769 reinterpret_cast<unsigned char**>(&data))) {
770 LOG(ERROR) << "Unable to allocate data for stress test.";
771 return 1;
772 }
773 memset(data, 0, sizeof(StressData));
774 // Read the options into the static variables that hold them.
775 ReadOptions(data, options);
776 // Save the data
777 if (JVMTI_ERROR_NONE != jvmti->SetEnvironmentLocalStorage(data)) {
778 LOG(ERROR) << "Unable to save stress test data.";
779 return 1;
780 }
781
782 // Just get all capabilities.
Alex Light3d324fd2017-07-20 15:38:52 -0700783 jvmtiCapabilities caps = {
784 .can_tag_objects = 0,
785 .can_generate_field_modification_events = 1,
786 .can_generate_field_access_events = 1,
787 .can_get_bytecodes = 0,
788 .can_get_synthetic_attribute = 0,
789 .can_get_owned_monitor_info = 0,
790 .can_get_current_contended_monitor = 0,
791 .can_get_monitor_info = 0,
792 .can_pop_frame = 0,
793 .can_redefine_classes = 1,
794 .can_signal_thread = 0,
795 .can_get_source_file_name = 1,
796 .can_get_line_numbers = 1,
797 .can_get_source_debug_extension = 0,
798 .can_access_local_variables = 0,
799 .can_maintain_original_method_order = 0,
800 .can_generate_single_step_events = 1,
801 .can_generate_exception_events = 0,
802 .can_generate_frame_pop_events = 0,
803 .can_generate_breakpoint_events = 0,
804 .can_suspend = 0,
805 .can_redefine_any_class = 0,
806 .can_get_current_thread_cpu_time = 0,
807 .can_get_thread_cpu_time = 0,
808 .can_generate_method_entry_events = 1,
809 .can_generate_method_exit_events = 1,
810 .can_generate_all_class_hook_events = 0,
811 .can_generate_compiled_method_load_events = 0,
812 .can_generate_monitor_events = 0,
813 .can_generate_vm_object_alloc_events = 0,
814 .can_generate_native_method_bind_events = 1,
815 .can_generate_garbage_collection_events = 0,
816 .can_generate_object_free_events = 0,
817 .can_force_early_return = 0,
818 .can_get_owned_monitor_stack_depth_info = 0,
819 .can_get_constant_pool = 0,
820 .can_set_native_method_prefix = 0,
821 .can_retransform_classes = 1,
822 .can_retransform_any_class = 0,
823 .can_generate_resource_exhaustion_heap_events = 0,
824 .can_generate_resource_exhaustion_threads_events = 0,
825 };
Alex Light8f2c6d42017-04-10 16:27:35 -0700826 jvmti->AddCapabilities(&caps);
827
828 // Set callbacks.
829 jvmtiEventCallbacks cb;
830 memset(&cb, 0, sizeof(cb));
831 cb.ClassFileLoadHook = ClassFileLoadHookSecretNoOp;
Alex Light0af8cde2017-04-20 13:35:05 -0700832 cb.NativeMethodBind = doJvmtiMethodBind;
Alex Lightb7edcda2017-04-27 13:20:31 -0700833 cb.VMInit = PerformFinalSetupVMInit;
834 cb.MethodEntry = MethodEntryHook;
835 cb.MethodExit = MethodExitHook;
Alex Light43e935d2017-06-19 15:40:40 -0700836 cb.FieldAccess = FieldAccessHook;
837 cb.FieldModification = FieldModificationHook;
Alex Light72398652017-06-16 09:08:12 -0700838 cb.ClassPrepare = ClassPrepareHook;
Alex Lightc38c3692017-06-27 15:45:14 -0700839 cb.SingleStep = SingleStepHook;
Alex Light8f2c6d42017-04-10 16:27:35 -0700840 if (jvmti->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
841 LOG(ERROR) << "Unable to set class file load hook cb!";
842 return 1;
843 }
844 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
Alex Light8f2c6d42017-04-10 16:27:35 -0700845 JVMTI_EVENT_VM_INIT,
846 nullptr) != JVMTI_ERROR_NONE) {
847 LOG(ERROR) << "Unable to enable JVMTI_EVENT_VM_INIT event!";
848 return 1;
849 }
Alex Light43e935d2017-06-19 15:40:40 -0700850 if (data->redefine_stress) {
851 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
852 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
853 nullptr) != JVMTI_ERROR_NONE) {
854 LOG(ERROR) << "Unable to enable CLASS_FILE_LOAD_HOOK event!";
855 return 1;
856 }
857 }
Alex Light72398652017-06-16 09:08:12 -0700858 if (data->trace_stress) {
859 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
860 JVMTI_EVENT_CLASS_PREPARE,
861 nullptr) != JVMTI_ERROR_NONE) {
862 LOG(ERROR) << "Unable to enable CLASS_PREPARE event!";
863 return 1;
864 }
Alex Lightb7edcda2017-04-27 13:20:31 -0700865 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
Alex Light43e935d2017-06-19 15:40:40 -0700866 JVMTI_EVENT_NATIVE_METHOD_BIND,
Alex Lightb7edcda2017-04-27 13:20:31 -0700867 nullptr) != JVMTI_ERROR_NONE) {
Alex Light43e935d2017-06-19 15:40:40 -0700868 LOG(ERROR) << "Unable to enable JVMTI_EVENT_NATIVE_METHOD_BIND event!";
869 return 1;
870 }
871 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
872 JVMTI_EVENT_METHOD_ENTRY,
873 nullptr) != JVMTI_ERROR_NONE) {
874 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_ENTRY event!";
875 return 1;
876 }
877 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
878 JVMTI_EVENT_METHOD_EXIT,
879 nullptr) != JVMTI_ERROR_NONE) {
880 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_EXIT event!";
881 return 1;
882 }
883 }
884 if (data->field_stress) {
885 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
886 JVMTI_EVENT_FIELD_MODIFICATION,
887 nullptr) != JVMTI_ERROR_NONE) {
888 LOG(ERROR) << "Unable to enable FIELD_MODIFICATION event!";
889 return 1;
890 }
891 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
892 JVMTI_EVENT_FIELD_ACCESS,
893 nullptr) != JVMTI_ERROR_NONE) {
894 LOG(ERROR) << "Unable to enable FIELD_ACCESS event!";
895 return 1;
896 }
897 if (!WatchAllFields(vm, jvmti)) {
Alex Lightb7edcda2017-04-27 13:20:31 -0700898 return 1;
899 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700900 }
Alex Lightc38c3692017-06-27 15:45:14 -0700901 if (data->step_stress) {
902 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
903 JVMTI_EVENT_SINGLE_STEP,
904 nullptr) != JVMTI_ERROR_NONE) {
905 return 1;
906 }
907 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700908 return 0;
909}
910
911} // namespace art