blob: 4e0f48d3f0290df817dcab8a48f8341e0ddedb7b [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
Alex Lightceae9542017-09-07 13:28:00 -070031#include "code_ir.h"
32#include "control_flow_graph.h"
33#include "dex_ir.h"
34#include "dex_ir_builder.h"
35#include "instrumentation.h"
36#include "reader.h"
37#include "writer.h"
38
Alex Light8f2c6d42017-04-10 16:27:35 -070039namespace art {
40
41// Should we do a 'full_rewrite' with this test?
42static constexpr bool kDoFullRewrite = true;
43
44struct StressData {
Alex Light8f2c6d42017-04-10 16:27:35 -070045 bool vm_class_loader_initialized;
Alex Lightb7edcda2017-04-27 13:20:31 -070046 bool trace_stress;
47 bool redefine_stress;
Alex Light43e935d2017-06-19 15:40:40 -070048 bool field_stress;
Alex Lightc38c3692017-06-27 15:45:14 -070049 bool step_stress;
Alex Light8f2c6d42017-04-10 16:27:35 -070050};
51
Alex Lightceae9542017-09-07 13:28:00 -070052static bool DoExtractClassFromData(jvmtiEnv* env,
53 const std::string& descriptor,
Alex Light8f2c6d42017-04-10 16:27:35 -070054 jint in_len,
55 const unsigned char* in_data,
Alex Lightceae9542017-09-07 13:28:00 -070056 /*out*/jint* out_len,
57 /*out*/unsigned char** out_data) {
58 dex::Reader reader(in_data, in_len);
59 dex::u4 class_idx = reader.FindClassIndex(descriptor.c_str());
60 if (class_idx != dex::kNoIndex) {
61 reader.CreateClassIr(class_idx);
62 } else {
63 LOG(ERROR) << "ERROR: Can't find class " << descriptor;
Alex Light8f2c6d42017-04-10 16:27:35 -070064 return false;
65 }
Alex Lightceae9542017-09-07 13:28:00 -070066 auto dex_ir = reader.GetIr();
67
68 if (kDoFullRewrite) {
69 for (auto& ir_method : dex_ir->encoded_methods) {
70 if (ir_method->code != nullptr) {
71 lir::CodeIr code_ir(ir_method.get(), dex_ir);
72 lir::ControlFlowGraph cfg_compact(&code_ir, false);
73 lir::ControlFlowGraph cfg_verbose(&code_ir, true);
74 code_ir.Assemble();
75 }
76 }
77 }
78 dex::Writer writer(dex_ir);
79
80 struct Allocator : public dex::Writer::Allocator {
81 explicit Allocator(jvmtiEnv* jvmti_env) : jvmti_env_(jvmti_env) {}
82 virtual void* Allocate(size_t size) {
83 unsigned char* out = nullptr;
84 if (JVMTI_ERROR_NONE != jvmti_env_->Allocate(size, &out)) {
85 return nullptr;
86 } else {
87 return out;
88 }
89 }
90 virtual void Free(void* ptr) {
91 jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
92 }
93 private:
94 jvmtiEnv* jvmti_env_;
95 };
96 Allocator alloc(env);
97 size_t res_len;
98 unsigned char* res = writer.CreateImage(&alloc, &res_len);
99 if (res != nullptr) {
100 *out_data = res;
101 *out_len = res_len;
102 return true;
103 } else {
104 return false;
105 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700106}
107
Alex Lightbad2f512017-06-14 11:33:55 -0700108class ScopedThreadInfo {
109 public:
110 ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread)
111 : jvmtienv_(jvmtienv), env_(env), free_name_(false) {
112 memset(&info_, 0, sizeof(info_));
113 if (thread == nullptr) {
114 info_.name = const_cast<char*>("<NULLPTR>");
115 } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) {
116 info_.name = const_cast<char*>("<UNKNOWN THREAD>");
117 } else {
118 free_name_ = true;
119 }
120 }
121
122 ~ScopedThreadInfo() {
123 if (free_name_) {
124 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name));
125 }
126 env_->DeleteLocalRef(info_.thread_group);
127 env_->DeleteLocalRef(info_.context_class_loader);
128 }
129
130 const char* GetName() const {
131 return info_.name;
132 }
133
134 private:
135 jvmtiEnv* jvmtienv_;
136 JNIEnv* env_;
137 bool free_name_;
138 jvmtiThreadInfo info_;
139};
140
141class ScopedClassInfo {
142 public:
143 ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c)
144 : jvmtienv_(jvmtienv),
145 class_(c),
146 name_(nullptr),
Alex Light6fa7b812017-06-16 09:04:29 -0700147 generic_(nullptr),
148 file_(nullptr),
149 debug_ext_(nullptr) {}
Alex Lightbad2f512017-06-14 11:33:55 -0700150
151 ~ScopedClassInfo() {
Alex Light43e935d2017-06-19 15:40:40 -0700152 if (class_ != nullptr) {
153 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
154 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
Alex Light6fa7b812017-06-16 09:04:29 -0700155 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(file_));
156 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(debug_ext_));
Alex Light43e935d2017-06-19 15:40:40 -0700157 }
Alex Lightbad2f512017-06-14 11:33:55 -0700158 }
159
160 bool Init() {
Alex Light43e935d2017-06-19 15:40:40 -0700161 if (class_ == nullptr) {
162 name_ = const_cast<char*>("<NONE>");
163 generic_ = const_cast<char*>("<NONE>");
164 return true;
165 } else {
Alex Light6fa7b812017-06-16 09:04:29 -0700166 jvmtiError ret1 = jvmtienv_->GetSourceFileName(class_, &file_);
167 jvmtiError ret2 = jvmtienv_->GetSourceDebugExtension(class_, &debug_ext_);
168 return jvmtienv_->GetClassSignature(class_, &name_, &generic_) == JVMTI_ERROR_NONE &&
169 ret1 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
170 ret1 != JVMTI_ERROR_INVALID_CLASS &&
171 ret2 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
172 ret2 != JVMTI_ERROR_INVALID_CLASS;
Alex Light43e935d2017-06-19 15:40:40 -0700173 }
Alex Lightbad2f512017-06-14 11:33:55 -0700174 }
175
176 jclass GetClass() const {
177 return class_;
178 }
179 const char* GetName() const {
180 return name_;
181 }
182 const char* GetGeneric() const {
183 return generic_;
184 }
Alex Light6fa7b812017-06-16 09:04:29 -0700185 const char* GetSourceDebugExtension() const {
186 if (debug_ext_ == nullptr) {
187 return "<UNKNOWN_SOURCE_DEBUG_EXTENSION>";
188 } else {
189 return debug_ext_;
190 }
191 }
192 const char* GetSourceFileName() const {
193 if (file_ == nullptr) {
194 return "<UNKNOWN_FILE>";
195 } else {
196 return file_;
197 }
198 }
Alex Lightbad2f512017-06-14 11:33:55 -0700199
200 private:
201 jvmtiEnv* jvmtienv_;
202 jclass class_;
203 char* name_;
204 char* generic_;
Alex Light6fa7b812017-06-16 09:04:29 -0700205 char* file_;
206 char* debug_ext_;
Alex Lightbad2f512017-06-14 11:33:55 -0700207};
208
209class ScopedMethodInfo {
210 public:
211 ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m)
212 : jvmtienv_(jvmtienv),
213 env_(env),
214 method_(m),
215 declaring_class_(nullptr),
216 class_info_(nullptr),
217 name_(nullptr),
218 signature_(nullptr),
Alex Light6fa7b812017-06-16 09:04:29 -0700219 generic_(nullptr),
220 first_line_(-1) {}
Alex Lightbad2f512017-06-14 11:33:55 -0700221
222 ~ScopedMethodInfo() {
223 env_->DeleteLocalRef(declaring_class_);
224 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
225 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
226 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
227 }
228
229 bool Init() {
230 if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
231 return false;
232 }
233 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
Alex Light6fa7b812017-06-16 09:04:29 -0700234 jint nlines;
235 jvmtiLineNumberEntry* lines;
236 jvmtiError err = jvmtienv_->GetLineNumberTable(method_, &nlines, &lines);
237 if (err == JVMTI_ERROR_NONE) {
238 if (nlines > 0) {
239 first_line_ = lines[0].line_number;
240 }
241 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(lines));
242 } else if (err != JVMTI_ERROR_ABSENT_INFORMATION &&
243 err != JVMTI_ERROR_NATIVE_METHOD) {
244 return false;
245 }
Alex Lightbad2f512017-06-14 11:33:55 -0700246 return class_info_->Init() &&
247 (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
248 }
249
250 const ScopedClassInfo& GetDeclaringClassInfo() const {
251 return *class_info_;
252 }
253
254 jclass GetDeclaringClass() const {
255 return declaring_class_;
256 }
257
258 const char* GetName() const {
259 return name_;
260 }
261
262 const char* GetSignature() const {
263 return signature_;
264 }
265
266 const char* GetGeneric() const {
267 return generic_;
268 }
269
Alex Light6fa7b812017-06-16 09:04:29 -0700270 jint GetFirstLine() const {
271 return first_line_;
272 }
273
Alex Lightbad2f512017-06-14 11:33:55 -0700274 private:
275 jvmtiEnv* jvmtienv_;
276 JNIEnv* env_;
277 jmethodID method_;
278 jclass declaring_class_;
279 std::unique_ptr<ScopedClassInfo> class_info_;
280 char* name_;
281 char* signature_;
282 char* generic_;
Alex Light6fa7b812017-06-16 09:04:29 -0700283 jint first_line_;
Alex Lightbad2f512017-06-14 11:33:55 -0700284
285 friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
286};
287
Alex Light43e935d2017-06-19 15:40:40 -0700288class ScopedFieldInfo {
289 public:
290 ScopedFieldInfo(jvmtiEnv* jvmtienv, jclass field_klass, jfieldID field)
291 : jvmtienv_(jvmtienv),
292 declaring_class_(field_klass),
293 field_(field),
294 class_info_(nullptr),
295 name_(nullptr),
296 type_(nullptr),
297 generic_(nullptr) {}
298
299 ~ScopedFieldInfo() {
300 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
301 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(type_));
302 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
303 }
304
305 bool Init() {
306 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
307 return class_info_->Init() &&
308 (jvmtienv_->GetFieldName(
309 declaring_class_, field_, &name_, &type_, &generic_) == JVMTI_ERROR_NONE);
310 }
311
312 const ScopedClassInfo& GetDeclaringClassInfo() const {
313 return *class_info_;
314 }
315
316 jclass GetDeclaringClass() const {
317 return declaring_class_;
318 }
319
320 const char* GetName() const {
321 return name_;
322 }
323
324 const char* GetType() const {
325 return type_;
326 }
327
328 const char* GetGeneric() const {
329 return generic_;
330 }
331
332 private:
333 jvmtiEnv* jvmtienv_;
334 jclass declaring_class_;
335 jfieldID field_;
336 std::unique_ptr<ScopedClassInfo> class_info_;
337 char* name_;
338 char* type_;
339 char* generic_;
340
341 friend std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m);
342};
343
344std::ostream& operator<<(std::ostream &os, const ScopedFieldInfo* m) {
345 return os << *m;
346}
347
348std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m) {
349 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName()
350 << ":" << m.GetType();
351}
352
Alex Lightbad2f512017-06-14 11:33:55 -0700353std::ostream& operator<<(std::ostream &os, const ScopedMethodInfo* m) {
354 return os << *m;
355}
356
357std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
Alex Light6fa7b812017-06-16 09:04:29 -0700358 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature()
359 << " (source: " << m.GetDeclaringClassInfo().GetSourceFileName() << ":"
360 << m.GetFirstLine() << ")";
Alex Lightbad2f512017-06-14 11:33:55 -0700361}
362
Alex Light0af8cde2017-04-20 13:35:05 -0700363static void doJvmtiMethodBind(jvmtiEnv* jvmtienv,
364 JNIEnv* env,
365 jthread thread,
366 jmethodID m,
367 void* address,
368 /*out*/void** out_address) {
369 *out_address = address;
Alex Lightbad2f512017-06-14 11:33:55 -0700370 ScopedThreadInfo thread_info(jvmtienv, env, thread);
371 ScopedMethodInfo method_info(jvmtienv, env, m);
372 if (!method_info.Init()) {
373 LOG(ERROR) << "Unable to get method info!";
Alex Light0af8cde2017-04-20 13:35:05 -0700374 return;
375 }
Alex Lightbad2f512017-06-14 11:33:55 -0700376 LOG(INFO) << "Loading native method \"" << method_info << "\". Thread is "
377 << thread_info.GetName();
Alex Light0af8cde2017-04-20 13:35:05 -0700378}
379
Alex Lightb7edcda2017-04-27 13:20:31 -0700380static std::string GetName(jvmtiEnv* jvmtienv, JNIEnv* jnienv, jobject obj) {
381 jclass klass = jnienv->GetObjectClass(obj);
382 char *cname, *cgen;
383 if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
384 LOG(ERROR) << "Unable to get class name!";
385 jnienv->DeleteLocalRef(klass);
386 return "<UNKNOWN>";
387 }
388 std::string name(cname);
389 if (name == "Ljava/lang/String;") {
390 jstring str = reinterpret_cast<jstring>(obj);
391 const char* val = jnienv->GetStringUTFChars(str, nullptr);
392 if (val == nullptr) {
393 name += " (unable to get value)";
394 } else {
395 std::ostringstream oss;
396 oss << name << " (value: \"" << val << "\")";
397 name = oss.str();
398 jnienv->ReleaseStringUTFChars(str, val);
399 }
400 }
401 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
402 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
403 jnienv->DeleteLocalRef(klass);
404 return name;
405}
406
407static std::string GetValOf(jvmtiEnv* env, JNIEnv* jnienv, std::string type, jvalue val) {
408 std::ostringstream oss;
409 switch (type[0]) {
410 case '[':
411 case 'L':
412 return val.l != nullptr ? GetName(env, jnienv, val.l) : "null";
413 case 'Z':
414 return val.z == JNI_TRUE ? "true" : "false";
415 case 'B':
416 oss << val.b;
417 return oss.str();
418 case 'C':
419 oss << val.c;
420 return oss.str();
421 case 'S':
422 oss << val.s;
423 return oss.str();
424 case 'I':
425 oss << val.i;
426 return oss.str();
427 case 'J':
428 oss << val.j;
429 return oss.str();
430 case 'F':
431 oss << val.f;
432 return oss.str();
433 case 'D':
434 oss << val.d;
435 return oss.str();
436 case 'V':
437 return "<void>";
438 default:
439 return "<ERROR Found type " + type + ">";
440 }
441}
442
Alex Light43e935d2017-06-19 15:40:40 -0700443void JNICALL FieldAccessHook(jvmtiEnv* jvmtienv,
444 JNIEnv* env,
445 jthread thread,
446 jmethodID m,
447 jlocation location,
448 jclass field_klass,
449 jobject object,
450 jfieldID field) {
451 ScopedThreadInfo info(jvmtienv, env, thread);
452 ScopedMethodInfo method_info(jvmtienv, env, m);
453 ScopedFieldInfo field_info(jvmtienv, field_klass, field);
454 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr;
455 ScopedClassInfo obj_class_info(jvmtienv, oklass);
456 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) {
457 LOG(ERROR) << "Unable to get callback info!";
458 return;
459 }
460 LOG(INFO) << "ACCESS field \"" << field_info << "\" on object of "
461 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info
462 << "\" at location 0x" << std::hex << location << ". Thread is \""
463 << info.GetName() << "\".";
464 env->DeleteLocalRef(oklass);
465}
466
467static std::string PrintJValue(jvmtiEnv* jvmtienv, JNIEnv* env, char type, jvalue new_value) {
468 std::ostringstream oss;
469 switch (type) {
470 case 'L': {
471 jobject nv = new_value.l;
472 if (nv == nullptr) {
473 oss << "\"null\"";
474 } else {
475 jclass nv_klass = env->GetObjectClass(nv);
476 ScopedClassInfo nv_class_info(jvmtienv, nv_klass);
477 if (!nv_class_info.Init()) {
478 oss << "with unknown type";
479 } else {
480 oss << "of type \"" << nv_class_info.GetName() << "\"";
481 }
482 env->DeleteLocalRef(nv_klass);
483 }
484 break;
485 }
486 case 'Z': {
487 if (new_value.z) {
488 oss << "true";
489 } else {
490 oss << "false";
491 }
492 break;
493 }
494#define SEND_VALUE(chr, sym, type) \
495 case chr: { \
496 oss << static_cast<type>(new_value.sym); \
497 break; \
498 }
499 SEND_VALUE('B', b, int8_t);
500 SEND_VALUE('C', c, uint16_t);
501 SEND_VALUE('S', s, int16_t);
502 SEND_VALUE('I', i, int32_t);
503 SEND_VALUE('J', j, int64_t);
504 SEND_VALUE('F', f, float);
505 SEND_VALUE('D', d, double);
506#undef SEND_VALUE
507 }
508 return oss.str();
509}
510
511void JNICALL FieldModificationHook(jvmtiEnv* jvmtienv,
512 JNIEnv* env,
513 jthread thread,
514 jmethodID m,
515 jlocation location,
516 jclass field_klass,
517 jobject object,
518 jfieldID field,
519 char type,
520 jvalue new_value) {
521 ScopedThreadInfo info(jvmtienv, env, thread);
522 ScopedMethodInfo method_info(jvmtienv, env, m);
523 ScopedFieldInfo field_info(jvmtienv, field_klass, field);
524 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr;
525 ScopedClassInfo obj_class_info(jvmtienv, oklass);
526 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) {
527 LOG(ERROR) << "Unable to get callback info!";
528 return;
529 }
530 LOG(INFO) << "MODIFY field \"" << field_info << "\" on object of "
531 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info
532 << "\" at location 0x" << std::hex << location << std::dec << ". New value is "
533 << PrintJValue(jvmtienv, env, type, new_value) << ". Thread is \""
534 << info.GetName() << "\".";
535 env->DeleteLocalRef(oklass);
536}
Alex Lightb7edcda2017-04-27 13:20:31 -0700537void JNICALL MethodExitHook(jvmtiEnv* jvmtienv,
538 JNIEnv* env,
539 jthread thread,
540 jmethodID m,
541 jboolean was_popped_by_exception,
542 jvalue val) {
Alex Lightbad2f512017-06-14 11:33:55 -0700543 ScopedThreadInfo info(jvmtienv, env, thread);
544 ScopedMethodInfo method_info(jvmtienv, env, m);
545 if (!method_info.Init()) {
546 LOG(ERROR) << "Unable to get method info!";
Alex Lightb7edcda2017-04-27 13:20:31 -0700547 return;
548 }
Alex Lightbad2f512017-06-14 11:33:55 -0700549 std::string type(method_info.GetSignature());
Andreas Gampe5555dd12017-08-24 13:50:21 -0700550 type = type.substr(type.find(')') + 1);
Alex Lightb7edcda2017-04-27 13:20:31 -0700551 std::string out_val(was_popped_by_exception ? "" : GetValOf(jvmtienv, env, type, val));
Alex Lightbad2f512017-06-14 11:33:55 -0700552 LOG(INFO) << "Leaving method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"."
553 << std::endl
Alex Lightb7edcda2017-04-27 13:20:31 -0700554 << " Cause: " << (was_popped_by_exception ? "exception" : "return ")
555 << out_val << ".";
Alex Lightb7edcda2017-04-27 13:20:31 -0700556}
557
558void JNICALL MethodEntryHook(jvmtiEnv* jvmtienv,
559 JNIEnv* env,
560 jthread thread,
561 jmethodID m) {
Alex Lightbad2f512017-06-14 11:33:55 -0700562 ScopedThreadInfo info(jvmtienv, env, thread);
563 ScopedMethodInfo method_info(jvmtienv, env, m);
564 if (!method_info.Init()) {
565 LOG(ERROR) << "Unable to get method info!";
Alex Lightb7edcda2017-04-27 13:20:31 -0700566 return;
567 }
Alex Lightbad2f512017-06-14 11:33:55 -0700568 LOG(INFO) << "Entering method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"";
Alex Lightb7edcda2017-04-27 13:20:31 -0700569}
570
Alex Light72398652017-06-16 09:08:12 -0700571void JNICALL ClassPrepareHook(jvmtiEnv* jvmtienv,
572 JNIEnv* env,
573 jthread thread,
574 jclass klass) {
Alex Light43e935d2017-06-19 15:40:40 -0700575 StressData* data = nullptr;
576 CHECK_EQ(jvmtienv->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
577 JVMTI_ERROR_NONE);
578 if (data->field_stress) {
579 jint nfields;
580 jfieldID* fields;
581 if (jvmtienv->GetClassFields(klass, &nfields, &fields) != JVMTI_ERROR_NONE) {
582 LOG(ERROR) << "Unable to get a classes fields!";
583 return;
584 }
585 for (jint i = 0; i < nfields; i++) {
586 jfieldID f = fields[i];
587 // Ignore errors
588 jvmtienv->SetFieldAccessWatch(klass, f);
589 jvmtienv->SetFieldModificationWatch(klass, f);
590 }
591 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fields));
Alex Light72398652017-06-16 09:08:12 -0700592 }
Alex Light43e935d2017-06-19 15:40:40 -0700593 if (data->trace_stress) {
594 ScopedThreadInfo info(jvmtienv, env, thread);
595 ScopedClassInfo class_info(jvmtienv, klass);
596 if (!class_info.Init()) {
597 LOG(ERROR) << "Unable to get class info!";
598 return;
599 }
600 LOG(INFO) << "Prepared class \"" << class_info.GetName() << "\". Thread is \""
601 << info.GetName() << "\"";
602 }
Alex Light72398652017-06-16 09:08:12 -0700603}
604
Alex Lightc38c3692017-06-27 15:45:14 -0700605void JNICALL SingleStepHook(jvmtiEnv* jvmtienv,
606 JNIEnv* env,
607 jthread thread,
608 jmethodID method,
609 jlocation location) {
610 ScopedThreadInfo info(jvmtienv, env, thread);
611 ScopedMethodInfo method_info(jvmtienv, env, method);
612 if (!method_info.Init()) {
613 LOG(ERROR) << "Unable to get method info!";
614 return;
615 }
616 LOG(INFO) << "Single step at location: 0x" << std::setw(8) << std::setfill('0') << std::hex
617 << location << " in method " << method_info << " thread: " << info.GetName();
618}
619
Alex Light8f2c6d42017-04-10 16:27:35 -0700620// The hook we are using.
621void JNICALL ClassFileLoadHookSecretNoOp(jvmtiEnv* jvmti,
622 JNIEnv* jni_env ATTRIBUTE_UNUSED,
623 jclass class_being_redefined ATTRIBUTE_UNUSED,
624 jobject loader ATTRIBUTE_UNUSED,
625 const char* name,
626 jobject protection_domain ATTRIBUTE_UNUSED,
627 jint class_data_len,
628 const unsigned char* class_data,
629 jint* new_class_data_len,
630 unsigned char** new_class_data) {
631 std::vector<unsigned char> out;
Alex Lightceae9542017-09-07 13:28:00 -0700632 // Make the jvmti semi-descriptor into the full descriptor.
633 std::string name_str("L");
634 name_str += name;
635 name_str += ";";
Alex Light8f2c6d42017-04-10 16:27:35 -0700636 StressData* data = nullptr;
637 CHECK_EQ(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
638 JVMTI_ERROR_NONE);
639 if (!data->vm_class_loader_initialized) {
640 LOG(WARNING) << "Ignoring load of class " << name << " because VMClassLoader is not yet "
641 << "initialized. Transforming this class could cause spurious test failures.";
642 return;
Alex Lightceae9542017-09-07 13:28:00 -0700643 } else if (DoExtractClassFromData(jvmti, name_str, class_data_len, class_data,
644 /*out*/ new_class_data_len, /*out*/ new_class_data)) {
Alex Light8f2c6d42017-04-10 16:27:35 -0700645 LOG(INFO) << "Extracted class: " << name;
Alex Light8f2c6d42017-04-10 16:27:35 -0700646 } else {
Alex Lightceae9542017-09-07 13:28:00 -0700647 std::cerr << "Unable to extract class " << name << std::endl;
Alex Light8f2c6d42017-04-10 16:27:35 -0700648 *new_class_data_len = 0;
649 *new_class_data = nullptr;
650 }
651}
652
Alex Lightb7edcda2017-04-27 13:20:31 -0700653static std::string AdvanceOption(const std::string& ops) {
654 return ops.substr(ops.find(',') + 1);
Alex Light8f2c6d42017-04-10 16:27:35 -0700655}
656
Alex Lightb7edcda2017-04-27 13:20:31 -0700657static bool HasNextOption(const std::string& ops) {
658 return ops.find(',') != std::string::npos;
659}
660
661static std::string GetOption(const std::string& in) {
662 return in.substr(0, in.find(','));
663}
664
665// Options are
Alex Lightceae9542017-09-07 13:28:00 -0700666// jvmti-stress,[redefine,][trace,][field]
Alex Lightb7edcda2017-04-27 13:20:31 -0700667static void ReadOptions(StressData* data, char* options) {
668 std::string ops(options);
669 CHECK_EQ(GetOption(ops), "jvmti-stress") << "Options should start with jvmti-stress";
670 do {
671 ops = AdvanceOption(ops);
672 std::string cur = GetOption(ops);
673 if (cur == "trace") {
674 data->trace_stress = true;
Alex Lightc38c3692017-06-27 15:45:14 -0700675 } else if (cur == "step") {
676 data->step_stress = true;
Alex Light43e935d2017-06-19 15:40:40 -0700677 } else if (cur == "field") {
678 data->field_stress = true;
Alex Lightb7edcda2017-04-27 13:20:31 -0700679 } else if (cur == "redefine") {
680 data->redefine_stress = true;
Alex Lightb7edcda2017-04-27 13:20:31 -0700681 } else {
682 LOG(FATAL) << "Unknown option: " << GetOption(ops);
683 }
684 } while (HasNextOption(ops));
685}
686
687// Do final setup during the VMInit callback. By this time most things are all setup.
688static void JNICALL PerformFinalSetupVMInit(jvmtiEnv *jvmti_env,
689 JNIEnv* jni_env,
690 jthread thread ATTRIBUTE_UNUSED) {
Alex Light8f2c6d42017-04-10 16:27:35 -0700691 // Load the VMClassLoader class. We will get a ClassNotFound exception because we don't have
692 // visibility but the class will be loaded behind the scenes.
693 LOG(INFO) << "manual load & initialization of class java/lang/VMClassLoader!";
694 jclass klass = jni_env->FindClass("java/lang/VMClassLoader");
Alex Lightb7edcda2017-04-27 13:20:31 -0700695 StressData* data = nullptr;
696 CHECK_EQ(jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
697 JVMTI_ERROR_NONE);
698 // We need to make sure that VMClassLoader is initialized before we start redefining anything
699 // since it can give (non-fatal) error messages if it's initialized after we've redefined BCP
700 // classes. These error messages are expected and no problem but they will mess up our testing
701 // infrastructure.
Alex Light8f2c6d42017-04-10 16:27:35 -0700702 if (klass == nullptr) {
Alex Light42151c02017-04-20 15:54:25 -0700703 // Probably on RI. Clear the exception so we can continue but don't mark vmclassloader as
704 // initialized.
705 LOG(WARNING) << "Unable to find VMClassLoader class!";
706 jni_env->ExceptionClear();
Alex Light8f2c6d42017-04-10 16:27:35 -0700707 } else {
708 // GetMethodID is spec'd to cause the class to be initialized.
709 jni_env->GetMethodID(klass, "hashCode", "()I");
710 jni_env->DeleteLocalRef(klass);
Alex Light8f2c6d42017-04-10 16:27:35 -0700711 data->vm_class_loader_initialized = true;
712 }
Alex Light43e935d2017-06-19 15:40:40 -0700713}
714
715static bool WatchAllFields(JavaVM* vm, jvmtiEnv* jvmti) {
716 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
717 JVMTI_EVENT_CLASS_PREPARE,
718 nullptr) != JVMTI_ERROR_NONE) {
719 LOG(ERROR) << "Couldn't set prepare event!";
720 return false;
Alex Lightb7edcda2017-04-27 13:20:31 -0700721 }
Alex Light43e935d2017-06-19 15:40:40 -0700722 // TODO We really shouldn't need to do this step here.
723 jint nklass;
724 jclass* klasses;
725 if (jvmti->GetLoadedClasses(&nklass, &klasses) != JVMTI_ERROR_NONE) {
726 LOG(WARNING) << "Couldn't get loaded classes! Ignoring.";
727 return true;
728 }
729 JNIEnv* jni = nullptr;
730 if (vm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6)) {
731 LOG(ERROR) << "Unable to get jni env. Ignoring and potentially leaking jobjects.";
732 return false;
733 }
734 for (jint i = 0; i < nklass; i++) {
735 jclass k = klasses[i];
736 ScopedClassInfo sci(jvmti, k);
737 if (sci.Init()) {
738 LOG(INFO) << "NOTE: class " << sci.GetName() << " already loaded.";
739 }
740 jint nfields;
741 jfieldID* fields;
742 jvmtiError err = jvmti->GetClassFields(k, &nfields, &fields);
743 if (err == JVMTI_ERROR_NONE) {
744 for (jint j = 0; j < nfields; j++) {
745 jfieldID f = fields[j];
746 if (jvmti->SetFieldModificationWatch(k, f) != JVMTI_ERROR_NONE ||
747 jvmti->SetFieldAccessWatch(k, f) != JVMTI_ERROR_NONE) {
748 LOG(ERROR) << "Unable to set watches on a field.";
749 return false;
750 }
751 }
752 } else if (err != JVMTI_ERROR_CLASS_NOT_PREPARED) {
753 LOG(ERROR) << "Unexpected error getting class fields!";
754 return false;
755 }
756 jvmti->Deallocate(reinterpret_cast<unsigned char*>(fields));
757 jni->DeleteLocalRef(k);
758 }
759 jvmti->Deallocate(reinterpret_cast<unsigned char*>(klasses));
760 return true;
Alex Light8f2c6d42017-04-10 16:27:35 -0700761}
762
763extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm,
764 char* options,
765 void* reserved ATTRIBUTE_UNUSED) {
766 jvmtiEnv* jvmti = nullptr;
767 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0)) {
768 LOG(ERROR) << "Unable to get jvmti env.";
769 return 1;
770 }
771 StressData* data = nullptr;
772 if (JVMTI_ERROR_NONE != jvmti->Allocate(sizeof(StressData),
773 reinterpret_cast<unsigned char**>(&data))) {
774 LOG(ERROR) << "Unable to allocate data for stress test.";
775 return 1;
776 }
777 memset(data, 0, sizeof(StressData));
778 // Read the options into the static variables that hold them.
779 ReadOptions(data, options);
780 // Save the data
781 if (JVMTI_ERROR_NONE != jvmti->SetEnvironmentLocalStorage(data)) {
782 LOG(ERROR) << "Unable to save stress test data.";
783 return 1;
784 }
785
786 // Just get all capabilities.
Alex Light3d324fd2017-07-20 15:38:52 -0700787 jvmtiCapabilities caps = {
788 .can_tag_objects = 0,
789 .can_generate_field_modification_events = 1,
790 .can_generate_field_access_events = 1,
791 .can_get_bytecodes = 0,
792 .can_get_synthetic_attribute = 0,
793 .can_get_owned_monitor_info = 0,
794 .can_get_current_contended_monitor = 0,
795 .can_get_monitor_info = 0,
796 .can_pop_frame = 0,
797 .can_redefine_classes = 1,
798 .can_signal_thread = 0,
799 .can_get_source_file_name = 1,
800 .can_get_line_numbers = 1,
801 .can_get_source_debug_extension = 0,
802 .can_access_local_variables = 0,
803 .can_maintain_original_method_order = 0,
804 .can_generate_single_step_events = 1,
805 .can_generate_exception_events = 0,
806 .can_generate_frame_pop_events = 0,
807 .can_generate_breakpoint_events = 0,
808 .can_suspend = 0,
809 .can_redefine_any_class = 0,
810 .can_get_current_thread_cpu_time = 0,
811 .can_get_thread_cpu_time = 0,
812 .can_generate_method_entry_events = 1,
813 .can_generate_method_exit_events = 1,
814 .can_generate_all_class_hook_events = 0,
815 .can_generate_compiled_method_load_events = 0,
816 .can_generate_monitor_events = 0,
817 .can_generate_vm_object_alloc_events = 0,
818 .can_generate_native_method_bind_events = 1,
819 .can_generate_garbage_collection_events = 0,
820 .can_generate_object_free_events = 0,
821 .can_force_early_return = 0,
822 .can_get_owned_monitor_stack_depth_info = 0,
823 .can_get_constant_pool = 0,
824 .can_set_native_method_prefix = 0,
825 .can_retransform_classes = 1,
826 .can_retransform_any_class = 0,
827 .can_generate_resource_exhaustion_heap_events = 0,
828 .can_generate_resource_exhaustion_threads_events = 0,
829 };
Alex Light8f2c6d42017-04-10 16:27:35 -0700830 jvmti->AddCapabilities(&caps);
831
832 // Set callbacks.
833 jvmtiEventCallbacks cb;
834 memset(&cb, 0, sizeof(cb));
835 cb.ClassFileLoadHook = ClassFileLoadHookSecretNoOp;
Alex Light0af8cde2017-04-20 13:35:05 -0700836 cb.NativeMethodBind = doJvmtiMethodBind;
Alex Lightb7edcda2017-04-27 13:20:31 -0700837 cb.VMInit = PerformFinalSetupVMInit;
838 cb.MethodEntry = MethodEntryHook;
839 cb.MethodExit = MethodExitHook;
Alex Light43e935d2017-06-19 15:40:40 -0700840 cb.FieldAccess = FieldAccessHook;
841 cb.FieldModification = FieldModificationHook;
Alex Light72398652017-06-16 09:08:12 -0700842 cb.ClassPrepare = ClassPrepareHook;
Alex Lightc38c3692017-06-27 15:45:14 -0700843 cb.SingleStep = SingleStepHook;
Alex Light8f2c6d42017-04-10 16:27:35 -0700844 if (jvmti->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
845 LOG(ERROR) << "Unable to set class file load hook cb!";
846 return 1;
847 }
848 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
Alex Light8f2c6d42017-04-10 16:27:35 -0700849 JVMTI_EVENT_VM_INIT,
850 nullptr) != JVMTI_ERROR_NONE) {
851 LOG(ERROR) << "Unable to enable JVMTI_EVENT_VM_INIT event!";
852 return 1;
853 }
Alex Light43e935d2017-06-19 15:40:40 -0700854 if (data->redefine_stress) {
855 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
856 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
857 nullptr) != JVMTI_ERROR_NONE) {
858 LOG(ERROR) << "Unable to enable CLASS_FILE_LOAD_HOOK event!";
859 return 1;
860 }
861 }
Alex Light72398652017-06-16 09:08:12 -0700862 if (data->trace_stress) {
863 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
864 JVMTI_EVENT_CLASS_PREPARE,
865 nullptr) != JVMTI_ERROR_NONE) {
866 LOG(ERROR) << "Unable to enable CLASS_PREPARE event!";
867 return 1;
868 }
Alex Lightb7edcda2017-04-27 13:20:31 -0700869 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
Alex Light43e935d2017-06-19 15:40:40 -0700870 JVMTI_EVENT_NATIVE_METHOD_BIND,
Alex Lightb7edcda2017-04-27 13:20:31 -0700871 nullptr) != JVMTI_ERROR_NONE) {
Alex Light43e935d2017-06-19 15:40:40 -0700872 LOG(ERROR) << "Unable to enable JVMTI_EVENT_NATIVE_METHOD_BIND event!";
873 return 1;
874 }
875 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
876 JVMTI_EVENT_METHOD_ENTRY,
877 nullptr) != JVMTI_ERROR_NONE) {
878 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_ENTRY event!";
879 return 1;
880 }
881 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
882 JVMTI_EVENT_METHOD_EXIT,
883 nullptr) != JVMTI_ERROR_NONE) {
884 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_EXIT event!";
885 return 1;
886 }
887 }
888 if (data->field_stress) {
889 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
890 JVMTI_EVENT_FIELD_MODIFICATION,
891 nullptr) != JVMTI_ERROR_NONE) {
892 LOG(ERROR) << "Unable to enable FIELD_MODIFICATION event!";
893 return 1;
894 }
895 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
896 JVMTI_EVENT_FIELD_ACCESS,
897 nullptr) != JVMTI_ERROR_NONE) {
898 LOG(ERROR) << "Unable to enable FIELD_ACCESS event!";
899 return 1;
900 }
901 if (!WatchAllFields(vm, jvmti)) {
Alex Lightb7edcda2017-04-27 13:20:31 -0700902 return 1;
903 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700904 }
Alex Lightc38c3692017-06-27 15:45:14 -0700905 if (data->step_stress) {
906 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
907 JVMTI_EVENT_SINGLE_STEP,
908 nullptr) != JVMTI_ERROR_NONE) {
909 return 1;
910 }
911 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700912 return 0;
913}
914
915} // namespace art