blob: 0eba7426c0926de5f464dc703f0f5270859ceb7c [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
David Sehrc431b9d2018-03-02 12:01:51 -080027#include "base/utils.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070028#include "jvmti.h"
Alex Light8f2c6d42017-04-10 16:27:35 -070029
Alex Lightbfe41af2017-09-07 13:30:47 -070030#pragma clang diagnostic push
Alex Light21a71442017-09-07 13:33:35 -070031
Alex Lightbfe41af2017-09-07 13:30:47 -070032// Slicer's headers have code that triggers these warnings. b/65298177
33#pragma clang diagnostic ignored "-Wunused-parameter"
34#pragma clang diagnostic ignored "-Wsign-compare"
Alex Lightceae9542017-09-07 13:28:00 -070035
Alex Light281242f2018-02-15 14:17:57 -080036#include "slicer/code_ir.h"
37#include "slicer/control_flow_graph.h"
38#include "slicer/dex_ir.h"
39#include "slicer/dex_ir_builder.h"
40#include "slicer/instrumentation.h"
41#include "slicer/reader.h"
42#include "slicer/writer.h"
43
Alex Lightbfe41af2017-09-07 13:30:47 -070044#pragma clang diagnostic pop
45
Alex Light8f2c6d42017-04-10 16:27:35 -070046namespace art {
47
48// Should we do a 'full_rewrite' with this test?
49static constexpr bool kDoFullRewrite = true;
50
51struct StressData {
Alex Light8f2c6d42017-04-10 16:27:35 -070052 bool vm_class_loader_initialized;
Alex Lightb7edcda2017-04-27 13:20:31 -070053 bool trace_stress;
54 bool redefine_stress;
Alex Light43e935d2017-06-19 15:40:40 -070055 bool field_stress;
Alex Lightc38c3692017-06-27 15:45:14 -070056 bool step_stress;
Alex Light8f2c6d42017-04-10 16:27:35 -070057};
58
Alex Lightceae9542017-09-07 13:28:00 -070059static bool DoExtractClassFromData(jvmtiEnv* env,
60 const std::string& descriptor,
Alex Light8f2c6d42017-04-10 16:27:35 -070061 jint in_len,
62 const unsigned char* in_data,
Alex Lightceae9542017-09-07 13:28:00 -070063 /*out*/jint* out_len,
64 /*out*/unsigned char** out_data) {
65 dex::Reader reader(in_data, in_len);
66 dex::u4 class_idx = reader.FindClassIndex(descriptor.c_str());
67 if (class_idx != dex::kNoIndex) {
68 reader.CreateClassIr(class_idx);
69 } else {
70 LOG(ERROR) << "ERROR: Can't find class " << descriptor;
Alex Light8f2c6d42017-04-10 16:27:35 -070071 return false;
72 }
Alex Lightceae9542017-09-07 13:28:00 -070073 auto dex_ir = reader.GetIr();
74
75 if (kDoFullRewrite) {
76 for (auto& ir_method : dex_ir->encoded_methods) {
77 if (ir_method->code != nullptr) {
78 lir::CodeIr code_ir(ir_method.get(), dex_ir);
79 lir::ControlFlowGraph cfg_compact(&code_ir, false);
80 lir::ControlFlowGraph cfg_verbose(&code_ir, true);
81 code_ir.Assemble();
82 }
83 }
84 }
85 dex::Writer writer(dex_ir);
86
87 struct Allocator : public dex::Writer::Allocator {
88 explicit Allocator(jvmtiEnv* jvmti_env) : jvmti_env_(jvmti_env) {}
89 virtual void* Allocate(size_t size) {
90 unsigned char* out = nullptr;
91 if (JVMTI_ERROR_NONE != jvmti_env_->Allocate(size, &out)) {
92 return nullptr;
93 } else {
94 return out;
95 }
96 }
97 virtual void Free(void* ptr) {
98 jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
99 }
100 private:
101 jvmtiEnv* jvmti_env_;
102 };
103 Allocator alloc(env);
104 size_t res_len;
105 unsigned char* res = writer.CreateImage(&alloc, &res_len);
106 if (res != nullptr) {
107 *out_data = res;
108 *out_len = res_len;
109 return true;
110 } else {
111 return false;
112 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700113}
114
Alex Lightbad2f512017-06-14 11:33:55 -0700115class ScopedThreadInfo {
116 public:
117 ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread)
118 : jvmtienv_(jvmtienv), env_(env), free_name_(false) {
119 memset(&info_, 0, sizeof(info_));
120 if (thread == nullptr) {
121 info_.name = const_cast<char*>("<NULLPTR>");
122 } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) {
123 info_.name = const_cast<char*>("<UNKNOWN THREAD>");
124 } else {
125 free_name_ = true;
126 }
127 }
128
129 ~ScopedThreadInfo() {
130 if (free_name_) {
131 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name));
132 }
133 env_->DeleteLocalRef(info_.thread_group);
134 env_->DeleteLocalRef(info_.context_class_loader);
135 }
136
137 const char* GetName() const {
138 return info_.name;
139 }
140
141 private:
142 jvmtiEnv* jvmtienv_;
143 JNIEnv* env_;
144 bool free_name_;
145 jvmtiThreadInfo info_;
146};
147
148class ScopedClassInfo {
149 public:
150 ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c)
151 : jvmtienv_(jvmtienv),
152 class_(c),
153 name_(nullptr),
Alex Light6fa7b812017-06-16 09:04:29 -0700154 generic_(nullptr),
155 file_(nullptr),
156 debug_ext_(nullptr) {}
Alex Lightbad2f512017-06-14 11:33:55 -0700157
158 ~ScopedClassInfo() {
Alex Light43e935d2017-06-19 15:40:40 -0700159 if (class_ != nullptr) {
160 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
161 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
Alex Light6fa7b812017-06-16 09:04:29 -0700162 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(file_));
163 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(debug_ext_));
Alex Light43e935d2017-06-19 15:40:40 -0700164 }
Alex Lightbad2f512017-06-14 11:33:55 -0700165 }
166
167 bool Init() {
Alex Light43e935d2017-06-19 15:40:40 -0700168 if (class_ == nullptr) {
169 name_ = const_cast<char*>("<NONE>");
170 generic_ = const_cast<char*>("<NONE>");
171 return true;
172 } else {
Alex Light6fa7b812017-06-16 09:04:29 -0700173 jvmtiError ret1 = jvmtienv_->GetSourceFileName(class_, &file_);
174 jvmtiError ret2 = jvmtienv_->GetSourceDebugExtension(class_, &debug_ext_);
175 return jvmtienv_->GetClassSignature(class_, &name_, &generic_) == JVMTI_ERROR_NONE &&
176 ret1 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
177 ret1 != JVMTI_ERROR_INVALID_CLASS &&
178 ret2 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
179 ret2 != JVMTI_ERROR_INVALID_CLASS;
Alex Light43e935d2017-06-19 15:40:40 -0700180 }
Alex Lightbad2f512017-06-14 11:33:55 -0700181 }
182
183 jclass GetClass() const {
184 return class_;
185 }
186 const char* GetName() const {
187 return name_;
188 }
189 const char* GetGeneric() const {
190 return generic_;
191 }
Alex Light6fa7b812017-06-16 09:04:29 -0700192 const char* GetSourceDebugExtension() const {
193 if (debug_ext_ == nullptr) {
194 return "<UNKNOWN_SOURCE_DEBUG_EXTENSION>";
195 } else {
196 return debug_ext_;
197 }
198 }
199 const char* GetSourceFileName() const {
200 if (file_ == nullptr) {
201 return "<UNKNOWN_FILE>";
202 } else {
203 return file_;
204 }
205 }
Alex Lightbad2f512017-06-14 11:33:55 -0700206
207 private:
208 jvmtiEnv* jvmtienv_;
209 jclass class_;
210 char* name_;
211 char* generic_;
Alex Light6fa7b812017-06-16 09:04:29 -0700212 char* file_;
213 char* debug_ext_;
Alex Lightbad2f512017-06-14 11:33:55 -0700214};
215
216class ScopedMethodInfo {
217 public:
218 ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m)
219 : jvmtienv_(jvmtienv),
220 env_(env),
221 method_(m),
222 declaring_class_(nullptr),
223 class_info_(nullptr),
224 name_(nullptr),
225 signature_(nullptr),
Alex Light6fa7b812017-06-16 09:04:29 -0700226 generic_(nullptr),
227 first_line_(-1) {}
Alex Lightbad2f512017-06-14 11:33:55 -0700228
229 ~ScopedMethodInfo() {
230 env_->DeleteLocalRef(declaring_class_);
231 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
232 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
233 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
234 }
235
236 bool Init() {
237 if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
238 return false;
239 }
240 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
Alex Light6fa7b812017-06-16 09:04:29 -0700241 jint nlines;
242 jvmtiLineNumberEntry* lines;
243 jvmtiError err = jvmtienv_->GetLineNumberTable(method_, &nlines, &lines);
244 if (err == JVMTI_ERROR_NONE) {
245 if (nlines > 0) {
246 first_line_ = lines[0].line_number;
247 }
248 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(lines));
249 } else if (err != JVMTI_ERROR_ABSENT_INFORMATION &&
250 err != JVMTI_ERROR_NATIVE_METHOD) {
251 return false;
252 }
Alex Lightbad2f512017-06-14 11:33:55 -0700253 return class_info_->Init() &&
254 (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
255 }
256
257 const ScopedClassInfo& GetDeclaringClassInfo() const {
258 return *class_info_;
259 }
260
261 jclass GetDeclaringClass() const {
262 return declaring_class_;
263 }
264
265 const char* GetName() const {
266 return name_;
267 }
268
269 const char* GetSignature() const {
270 return signature_;
271 }
272
273 const char* GetGeneric() const {
274 return generic_;
275 }
276
Alex Light6fa7b812017-06-16 09:04:29 -0700277 jint GetFirstLine() const {
278 return first_line_;
279 }
280
Alex Lightbad2f512017-06-14 11:33:55 -0700281 private:
282 jvmtiEnv* jvmtienv_;
283 JNIEnv* env_;
284 jmethodID method_;
285 jclass declaring_class_;
286 std::unique_ptr<ScopedClassInfo> class_info_;
287 char* name_;
288 char* signature_;
289 char* generic_;
Alex Light6fa7b812017-06-16 09:04:29 -0700290 jint first_line_;
Alex Lightbad2f512017-06-14 11:33:55 -0700291
292 friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
293};
294
Alex Light43e935d2017-06-19 15:40:40 -0700295class ScopedFieldInfo {
296 public:
297 ScopedFieldInfo(jvmtiEnv* jvmtienv, jclass field_klass, jfieldID field)
298 : jvmtienv_(jvmtienv),
299 declaring_class_(field_klass),
300 field_(field),
301 class_info_(nullptr),
302 name_(nullptr),
303 type_(nullptr),
304 generic_(nullptr) {}
305
306 ~ScopedFieldInfo() {
307 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
308 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(type_));
309 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
310 }
311
312 bool Init() {
313 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
314 return class_info_->Init() &&
315 (jvmtienv_->GetFieldName(
316 declaring_class_, field_, &name_, &type_, &generic_) == JVMTI_ERROR_NONE);
317 }
318
319 const ScopedClassInfo& GetDeclaringClassInfo() const {
320 return *class_info_;
321 }
322
323 jclass GetDeclaringClass() const {
324 return declaring_class_;
325 }
326
327 const char* GetName() const {
328 return name_;
329 }
330
331 const char* GetType() const {
332 return type_;
333 }
334
335 const char* GetGeneric() const {
336 return generic_;
337 }
338
339 private:
340 jvmtiEnv* jvmtienv_;
341 jclass declaring_class_;
342 jfieldID field_;
343 std::unique_ptr<ScopedClassInfo> class_info_;
344 char* name_;
345 char* type_;
346 char* generic_;
347
348 friend std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m);
349};
350
351std::ostream& operator<<(std::ostream &os, const ScopedFieldInfo* m) {
352 return os << *m;
353}
354
355std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m) {
356 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName()
357 << ":" << m.GetType();
358}
359
Alex Lightbad2f512017-06-14 11:33:55 -0700360std::ostream& operator<<(std::ostream &os, const ScopedMethodInfo* m) {
361 return os << *m;
362}
363
364std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
Alex Light6fa7b812017-06-16 09:04:29 -0700365 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature()
366 << " (source: " << m.GetDeclaringClassInfo().GetSourceFileName() << ":"
367 << m.GetFirstLine() << ")";
Alex Lightbad2f512017-06-14 11:33:55 -0700368}
369
Alex Light0af8cde2017-04-20 13:35:05 -0700370static void doJvmtiMethodBind(jvmtiEnv* jvmtienv,
371 JNIEnv* env,
372 jthread thread,
373 jmethodID m,
374 void* address,
375 /*out*/void** out_address) {
376 *out_address = address;
Alex Lightbad2f512017-06-14 11:33:55 -0700377 ScopedThreadInfo thread_info(jvmtienv, env, thread);
378 ScopedMethodInfo method_info(jvmtienv, env, m);
379 if (!method_info.Init()) {
380 LOG(ERROR) << "Unable to get method info!";
Alex Light0af8cde2017-04-20 13:35:05 -0700381 return;
382 }
Alex Lightbad2f512017-06-14 11:33:55 -0700383 LOG(INFO) << "Loading native method \"" << method_info << "\". Thread is "
384 << thread_info.GetName();
Alex Light0af8cde2017-04-20 13:35:05 -0700385}
386
Alex Lightb7edcda2017-04-27 13:20:31 -0700387static std::string GetName(jvmtiEnv* jvmtienv, JNIEnv* jnienv, jobject obj) {
388 jclass klass = jnienv->GetObjectClass(obj);
389 char *cname, *cgen;
390 if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
391 LOG(ERROR) << "Unable to get class name!";
392 jnienv->DeleteLocalRef(klass);
393 return "<UNKNOWN>";
394 }
395 std::string name(cname);
396 if (name == "Ljava/lang/String;") {
397 jstring str = reinterpret_cast<jstring>(obj);
398 const char* val = jnienv->GetStringUTFChars(str, nullptr);
399 if (val == nullptr) {
400 name += " (unable to get value)";
401 } else {
402 std::ostringstream oss;
403 oss << name << " (value: \"" << val << "\")";
404 name = oss.str();
405 jnienv->ReleaseStringUTFChars(str, val);
406 }
407 }
408 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
409 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
410 jnienv->DeleteLocalRef(klass);
411 return name;
412}
413
414static std::string GetValOf(jvmtiEnv* env, JNIEnv* jnienv, std::string type, jvalue val) {
415 std::ostringstream oss;
416 switch (type[0]) {
417 case '[':
418 case 'L':
419 return val.l != nullptr ? GetName(env, jnienv, val.l) : "null";
420 case 'Z':
421 return val.z == JNI_TRUE ? "true" : "false";
422 case 'B':
423 oss << val.b;
424 return oss.str();
425 case 'C':
426 oss << val.c;
427 return oss.str();
428 case 'S':
429 oss << val.s;
430 return oss.str();
431 case 'I':
432 oss << val.i;
433 return oss.str();
434 case 'J':
435 oss << val.j;
436 return oss.str();
437 case 'F':
438 oss << val.f;
439 return oss.str();
440 case 'D':
441 oss << val.d;
442 return oss.str();
443 case 'V':
444 return "<void>";
445 default:
446 return "<ERROR Found type " + type + ">";
447 }
448}
449
Alex Light43e935d2017-06-19 15:40:40 -0700450void JNICALL FieldAccessHook(jvmtiEnv* jvmtienv,
451 JNIEnv* env,
452 jthread thread,
453 jmethodID m,
454 jlocation location,
455 jclass field_klass,
456 jobject object,
457 jfieldID field) {
458 ScopedThreadInfo info(jvmtienv, env, thread);
459 ScopedMethodInfo method_info(jvmtienv, env, m);
460 ScopedFieldInfo field_info(jvmtienv, field_klass, field);
461 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr;
462 ScopedClassInfo obj_class_info(jvmtienv, oklass);
463 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) {
464 LOG(ERROR) << "Unable to get callback info!";
465 return;
466 }
467 LOG(INFO) << "ACCESS field \"" << field_info << "\" on object of "
468 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info
469 << "\" at location 0x" << std::hex << location << ". Thread is \""
470 << info.GetName() << "\".";
471 env->DeleteLocalRef(oklass);
472}
473
474static std::string PrintJValue(jvmtiEnv* jvmtienv, JNIEnv* env, char type, jvalue new_value) {
475 std::ostringstream oss;
476 switch (type) {
477 case 'L': {
478 jobject nv = new_value.l;
479 if (nv == nullptr) {
480 oss << "\"null\"";
481 } else {
482 jclass nv_klass = env->GetObjectClass(nv);
483 ScopedClassInfo nv_class_info(jvmtienv, nv_klass);
484 if (!nv_class_info.Init()) {
485 oss << "with unknown type";
486 } else {
487 oss << "of type \"" << nv_class_info.GetName() << "\"";
488 }
489 env->DeleteLocalRef(nv_klass);
490 }
491 break;
492 }
493 case 'Z': {
494 if (new_value.z) {
495 oss << "true";
496 } else {
497 oss << "false";
498 }
499 break;
500 }
501#define SEND_VALUE(chr, sym, type) \
502 case chr: { \
503 oss << static_cast<type>(new_value.sym); \
504 break; \
505 }
506 SEND_VALUE('B', b, int8_t);
507 SEND_VALUE('C', c, uint16_t);
508 SEND_VALUE('S', s, int16_t);
509 SEND_VALUE('I', i, int32_t);
510 SEND_VALUE('J', j, int64_t);
511 SEND_VALUE('F', f, float);
512 SEND_VALUE('D', d, double);
513#undef SEND_VALUE
514 }
515 return oss.str();
516}
517
518void JNICALL FieldModificationHook(jvmtiEnv* jvmtienv,
519 JNIEnv* env,
520 jthread thread,
521 jmethodID m,
522 jlocation location,
523 jclass field_klass,
524 jobject object,
525 jfieldID field,
526 char type,
527 jvalue new_value) {
528 ScopedThreadInfo info(jvmtienv, env, thread);
529 ScopedMethodInfo method_info(jvmtienv, env, m);
530 ScopedFieldInfo field_info(jvmtienv, field_klass, field);
531 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr;
532 ScopedClassInfo obj_class_info(jvmtienv, oklass);
533 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) {
534 LOG(ERROR) << "Unable to get callback info!";
535 return;
536 }
537 LOG(INFO) << "MODIFY field \"" << field_info << "\" on object of "
538 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info
539 << "\" at location 0x" << std::hex << location << std::dec << ". New value is "
540 << PrintJValue(jvmtienv, env, type, new_value) << ". Thread is \""
541 << info.GetName() << "\".";
542 env->DeleteLocalRef(oklass);
543}
Alex Lightb7edcda2017-04-27 13:20:31 -0700544void JNICALL MethodExitHook(jvmtiEnv* jvmtienv,
545 JNIEnv* env,
546 jthread thread,
547 jmethodID m,
548 jboolean was_popped_by_exception,
549 jvalue val) {
Alex Lightbad2f512017-06-14 11:33:55 -0700550 ScopedThreadInfo info(jvmtienv, env, thread);
551 ScopedMethodInfo method_info(jvmtienv, env, m);
552 if (!method_info.Init()) {
553 LOG(ERROR) << "Unable to get method info!";
Alex Lightb7edcda2017-04-27 13:20:31 -0700554 return;
555 }
Alex Lightbad2f512017-06-14 11:33:55 -0700556 std::string type(method_info.GetSignature());
Andreas Gampe5555dd12017-08-24 13:50:21 -0700557 type = type.substr(type.find(')') + 1);
Alex Lightb7edcda2017-04-27 13:20:31 -0700558 std::string out_val(was_popped_by_exception ? "" : GetValOf(jvmtienv, env, type, val));
Alex Lightbad2f512017-06-14 11:33:55 -0700559 LOG(INFO) << "Leaving method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"."
560 << std::endl
Alex Lightb7edcda2017-04-27 13:20:31 -0700561 << " Cause: " << (was_popped_by_exception ? "exception" : "return ")
562 << out_val << ".";
Alex Lightb7edcda2017-04-27 13:20:31 -0700563}
564
565void JNICALL MethodEntryHook(jvmtiEnv* jvmtienv,
566 JNIEnv* env,
567 jthread thread,
568 jmethodID m) {
Alex Lightbad2f512017-06-14 11:33:55 -0700569 ScopedThreadInfo info(jvmtienv, env, thread);
570 ScopedMethodInfo method_info(jvmtienv, env, m);
571 if (!method_info.Init()) {
572 LOG(ERROR) << "Unable to get method info!";
Alex Lightb7edcda2017-04-27 13:20:31 -0700573 return;
574 }
Alex Lightbad2f512017-06-14 11:33:55 -0700575 LOG(INFO) << "Entering method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"";
Alex Lightb7edcda2017-04-27 13:20:31 -0700576}
577
Alex Light72398652017-06-16 09:08:12 -0700578void JNICALL ClassPrepareHook(jvmtiEnv* jvmtienv,
579 JNIEnv* env,
580 jthread thread,
581 jclass klass) {
Alex Light43e935d2017-06-19 15:40:40 -0700582 StressData* data = nullptr;
583 CHECK_EQ(jvmtienv->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
584 JVMTI_ERROR_NONE);
585 if (data->field_stress) {
586 jint nfields;
587 jfieldID* fields;
588 if (jvmtienv->GetClassFields(klass, &nfields, &fields) != JVMTI_ERROR_NONE) {
589 LOG(ERROR) << "Unable to get a classes fields!";
590 return;
591 }
592 for (jint i = 0; i < nfields; i++) {
593 jfieldID f = fields[i];
594 // Ignore errors
595 jvmtienv->SetFieldAccessWatch(klass, f);
596 jvmtienv->SetFieldModificationWatch(klass, f);
597 }
598 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fields));
Alex Light72398652017-06-16 09:08:12 -0700599 }
Alex Light43e935d2017-06-19 15:40:40 -0700600 if (data->trace_stress) {
601 ScopedThreadInfo info(jvmtienv, env, thread);
602 ScopedClassInfo class_info(jvmtienv, klass);
603 if (!class_info.Init()) {
604 LOG(ERROR) << "Unable to get class info!";
605 return;
606 }
607 LOG(INFO) << "Prepared class \"" << class_info.GetName() << "\". Thread is \""
608 << info.GetName() << "\"";
609 }
Alex Light72398652017-06-16 09:08:12 -0700610}
611
Alex Lightc38c3692017-06-27 15:45:14 -0700612void JNICALL SingleStepHook(jvmtiEnv* jvmtienv,
613 JNIEnv* env,
614 jthread thread,
615 jmethodID method,
616 jlocation location) {
617 ScopedThreadInfo info(jvmtienv, env, thread);
618 ScopedMethodInfo method_info(jvmtienv, env, method);
619 if (!method_info.Init()) {
620 LOG(ERROR) << "Unable to get method info!";
621 return;
622 }
623 LOG(INFO) << "Single step at location: 0x" << std::setw(8) << std::setfill('0') << std::hex
624 << location << " in method " << method_info << " thread: " << info.GetName();
625}
626
Alex Light8f2c6d42017-04-10 16:27:35 -0700627// The hook we are using.
628void JNICALL ClassFileLoadHookSecretNoOp(jvmtiEnv* jvmti,
629 JNIEnv* jni_env ATTRIBUTE_UNUSED,
630 jclass class_being_redefined ATTRIBUTE_UNUSED,
631 jobject loader ATTRIBUTE_UNUSED,
632 const char* name,
633 jobject protection_domain ATTRIBUTE_UNUSED,
634 jint class_data_len,
635 const unsigned char* class_data,
636 jint* new_class_data_len,
637 unsigned char** new_class_data) {
638 std::vector<unsigned char> out;
Alex Lightceae9542017-09-07 13:28:00 -0700639 // Make the jvmti semi-descriptor into the full descriptor.
640 std::string name_str("L");
641 name_str += name;
642 name_str += ";";
Alex Light8f2c6d42017-04-10 16:27:35 -0700643 StressData* data = nullptr;
644 CHECK_EQ(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
645 JVMTI_ERROR_NONE);
646 if (!data->vm_class_loader_initialized) {
647 LOG(WARNING) << "Ignoring load of class " << name << " because VMClassLoader is not yet "
648 << "initialized. Transforming this class could cause spurious test failures.";
649 return;
Alex Lightceae9542017-09-07 13:28:00 -0700650 } else if (DoExtractClassFromData(jvmti, name_str, class_data_len, class_data,
651 /*out*/ new_class_data_len, /*out*/ new_class_data)) {
Alex Light8f2c6d42017-04-10 16:27:35 -0700652 LOG(INFO) << "Extracted class: " << name;
Alex Light8f2c6d42017-04-10 16:27:35 -0700653 } else {
Alex Lightceae9542017-09-07 13:28:00 -0700654 std::cerr << "Unable to extract class " << name << std::endl;
Alex Light8f2c6d42017-04-10 16:27:35 -0700655 *new_class_data_len = 0;
656 *new_class_data = nullptr;
657 }
658}
659
Alex Lightb7edcda2017-04-27 13:20:31 -0700660static std::string AdvanceOption(const std::string& ops) {
661 return ops.substr(ops.find(',') + 1);
Alex Light8f2c6d42017-04-10 16:27:35 -0700662}
663
Alex Lightb7edcda2017-04-27 13:20:31 -0700664static bool HasNextOption(const std::string& ops) {
665 return ops.find(',') != std::string::npos;
666}
667
668static std::string GetOption(const std::string& in) {
669 return in.substr(0, in.find(','));
670}
671
672// Options are
Alex Lightceae9542017-09-07 13:28:00 -0700673// jvmti-stress,[redefine,][trace,][field]
Alex Lightb7edcda2017-04-27 13:20:31 -0700674static void ReadOptions(StressData* data, char* options) {
675 std::string ops(options);
676 CHECK_EQ(GetOption(ops), "jvmti-stress") << "Options should start with jvmti-stress";
677 do {
678 ops = AdvanceOption(ops);
679 std::string cur = GetOption(ops);
680 if (cur == "trace") {
681 data->trace_stress = true;
Alex Lightc38c3692017-06-27 15:45:14 -0700682 } else if (cur == "step") {
683 data->step_stress = true;
Alex Light43e935d2017-06-19 15:40:40 -0700684 } else if (cur == "field") {
685 data->field_stress = true;
Alex Lightb7edcda2017-04-27 13:20:31 -0700686 } else if (cur == "redefine") {
687 data->redefine_stress = true;
Alex Lightb7edcda2017-04-27 13:20:31 -0700688 } else {
689 LOG(FATAL) << "Unknown option: " << GetOption(ops);
690 }
691 } while (HasNextOption(ops));
692}
693
694// Do final setup during the VMInit callback. By this time most things are all setup.
695static void JNICALL PerformFinalSetupVMInit(jvmtiEnv *jvmti_env,
696 JNIEnv* jni_env,
697 jthread thread ATTRIBUTE_UNUSED) {
Alex Light8f2c6d42017-04-10 16:27:35 -0700698 // Load the VMClassLoader class. We will get a ClassNotFound exception because we don't have
699 // visibility but the class will be loaded behind the scenes.
700 LOG(INFO) << "manual load & initialization of class java/lang/VMClassLoader!";
701 jclass klass = jni_env->FindClass("java/lang/VMClassLoader");
Alex Lightb7edcda2017-04-27 13:20:31 -0700702 StressData* data = nullptr;
703 CHECK_EQ(jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
704 JVMTI_ERROR_NONE);
705 // We need to make sure that VMClassLoader is initialized before we start redefining anything
706 // since it can give (non-fatal) error messages if it's initialized after we've redefined BCP
707 // classes. These error messages are expected and no problem but they will mess up our testing
708 // infrastructure.
Alex Light8f2c6d42017-04-10 16:27:35 -0700709 if (klass == nullptr) {
Alex Light42151c02017-04-20 15:54:25 -0700710 // Probably on RI. Clear the exception so we can continue but don't mark vmclassloader as
711 // initialized.
712 LOG(WARNING) << "Unable to find VMClassLoader class!";
713 jni_env->ExceptionClear();
Alex Light8f2c6d42017-04-10 16:27:35 -0700714 } else {
715 // GetMethodID is spec'd to cause the class to be initialized.
716 jni_env->GetMethodID(klass, "hashCode", "()I");
717 jni_env->DeleteLocalRef(klass);
Alex Light8f2c6d42017-04-10 16:27:35 -0700718 data->vm_class_loader_initialized = true;
719 }
Alex Light43e935d2017-06-19 15:40:40 -0700720}
721
722static bool WatchAllFields(JavaVM* vm, jvmtiEnv* jvmti) {
723 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
724 JVMTI_EVENT_CLASS_PREPARE,
725 nullptr) != JVMTI_ERROR_NONE) {
726 LOG(ERROR) << "Couldn't set prepare event!";
727 return false;
Alex Lightb7edcda2017-04-27 13:20:31 -0700728 }
Alex Light43e935d2017-06-19 15:40:40 -0700729 // TODO We really shouldn't need to do this step here.
730 jint nklass;
731 jclass* klasses;
732 if (jvmti->GetLoadedClasses(&nklass, &klasses) != JVMTI_ERROR_NONE) {
733 LOG(WARNING) << "Couldn't get loaded classes! Ignoring.";
734 return true;
735 }
736 JNIEnv* jni = nullptr;
737 if (vm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6)) {
738 LOG(ERROR) << "Unable to get jni env. Ignoring and potentially leaking jobjects.";
739 return false;
740 }
741 for (jint i = 0; i < nklass; i++) {
742 jclass k = klasses[i];
743 ScopedClassInfo sci(jvmti, k);
744 if (sci.Init()) {
745 LOG(INFO) << "NOTE: class " << sci.GetName() << " already loaded.";
746 }
747 jint nfields;
748 jfieldID* fields;
749 jvmtiError err = jvmti->GetClassFields(k, &nfields, &fields);
750 if (err == JVMTI_ERROR_NONE) {
751 for (jint j = 0; j < nfields; j++) {
752 jfieldID f = fields[j];
753 if (jvmti->SetFieldModificationWatch(k, f) != JVMTI_ERROR_NONE ||
754 jvmti->SetFieldAccessWatch(k, f) != JVMTI_ERROR_NONE) {
755 LOG(ERROR) << "Unable to set watches on a field.";
756 return false;
757 }
758 }
759 } else if (err != JVMTI_ERROR_CLASS_NOT_PREPARED) {
760 LOG(ERROR) << "Unexpected error getting class fields!";
761 return false;
762 }
763 jvmti->Deallocate(reinterpret_cast<unsigned char*>(fields));
764 jni->DeleteLocalRef(k);
765 }
766 jvmti->Deallocate(reinterpret_cast<unsigned char*>(klasses));
767 return true;
Alex Light8f2c6d42017-04-10 16:27:35 -0700768}
769
770extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm,
771 char* options,
772 void* reserved ATTRIBUTE_UNUSED) {
773 jvmtiEnv* jvmti = nullptr;
774 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0)) {
775 LOG(ERROR) << "Unable to get jvmti env.";
776 return 1;
777 }
778 StressData* data = nullptr;
779 if (JVMTI_ERROR_NONE != jvmti->Allocate(sizeof(StressData),
780 reinterpret_cast<unsigned char**>(&data))) {
781 LOG(ERROR) << "Unable to allocate data for stress test.";
782 return 1;
783 }
784 memset(data, 0, sizeof(StressData));
785 // Read the options into the static variables that hold them.
786 ReadOptions(data, options);
787 // Save the data
788 if (JVMTI_ERROR_NONE != jvmti->SetEnvironmentLocalStorage(data)) {
789 LOG(ERROR) << "Unable to save stress test data.";
790 return 1;
791 }
792
793 // Just get all capabilities.
Alex Light3d324fd2017-07-20 15:38:52 -0700794 jvmtiCapabilities caps = {
795 .can_tag_objects = 0,
796 .can_generate_field_modification_events = 1,
797 .can_generate_field_access_events = 1,
798 .can_get_bytecodes = 0,
799 .can_get_synthetic_attribute = 0,
800 .can_get_owned_monitor_info = 0,
801 .can_get_current_contended_monitor = 0,
802 .can_get_monitor_info = 0,
803 .can_pop_frame = 0,
804 .can_redefine_classes = 1,
805 .can_signal_thread = 0,
806 .can_get_source_file_name = 1,
807 .can_get_line_numbers = 1,
Alex Lightc2a082a2018-01-12 09:16:28 -0800808 .can_get_source_debug_extension = 1,
Alex Light3d324fd2017-07-20 15:38:52 -0700809 .can_access_local_variables = 0,
810 .can_maintain_original_method_order = 0,
811 .can_generate_single_step_events = 1,
812 .can_generate_exception_events = 0,
813 .can_generate_frame_pop_events = 0,
814 .can_generate_breakpoint_events = 0,
815 .can_suspend = 0,
816 .can_redefine_any_class = 0,
817 .can_get_current_thread_cpu_time = 0,
818 .can_get_thread_cpu_time = 0,
819 .can_generate_method_entry_events = 1,
820 .can_generate_method_exit_events = 1,
821 .can_generate_all_class_hook_events = 0,
822 .can_generate_compiled_method_load_events = 0,
823 .can_generate_monitor_events = 0,
824 .can_generate_vm_object_alloc_events = 0,
825 .can_generate_native_method_bind_events = 1,
826 .can_generate_garbage_collection_events = 0,
827 .can_generate_object_free_events = 0,
828 .can_force_early_return = 0,
829 .can_get_owned_monitor_stack_depth_info = 0,
830 .can_get_constant_pool = 0,
831 .can_set_native_method_prefix = 0,
832 .can_retransform_classes = 1,
833 .can_retransform_any_class = 0,
834 .can_generate_resource_exhaustion_heap_events = 0,
835 .can_generate_resource_exhaustion_threads_events = 0,
836 };
Alex Light8f2c6d42017-04-10 16:27:35 -0700837 jvmti->AddCapabilities(&caps);
838
839 // Set callbacks.
840 jvmtiEventCallbacks cb;
841 memset(&cb, 0, sizeof(cb));
842 cb.ClassFileLoadHook = ClassFileLoadHookSecretNoOp;
Alex Light0af8cde2017-04-20 13:35:05 -0700843 cb.NativeMethodBind = doJvmtiMethodBind;
Alex Lightb7edcda2017-04-27 13:20:31 -0700844 cb.VMInit = PerformFinalSetupVMInit;
845 cb.MethodEntry = MethodEntryHook;
846 cb.MethodExit = MethodExitHook;
Alex Light43e935d2017-06-19 15:40:40 -0700847 cb.FieldAccess = FieldAccessHook;
848 cb.FieldModification = FieldModificationHook;
Alex Light72398652017-06-16 09:08:12 -0700849 cb.ClassPrepare = ClassPrepareHook;
Alex Lightc38c3692017-06-27 15:45:14 -0700850 cb.SingleStep = SingleStepHook;
Alex Light8f2c6d42017-04-10 16:27:35 -0700851 if (jvmti->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
852 LOG(ERROR) << "Unable to set class file load hook cb!";
853 return 1;
854 }
855 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
Alex Light8f2c6d42017-04-10 16:27:35 -0700856 JVMTI_EVENT_VM_INIT,
857 nullptr) != JVMTI_ERROR_NONE) {
858 LOG(ERROR) << "Unable to enable JVMTI_EVENT_VM_INIT event!";
859 return 1;
860 }
Alex Light43e935d2017-06-19 15:40:40 -0700861 if (data->redefine_stress) {
862 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
863 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
864 nullptr) != JVMTI_ERROR_NONE) {
865 LOG(ERROR) << "Unable to enable CLASS_FILE_LOAD_HOOK event!";
866 return 1;
867 }
868 }
Alex Light72398652017-06-16 09:08:12 -0700869 if (data->trace_stress) {
870 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
871 JVMTI_EVENT_CLASS_PREPARE,
872 nullptr) != JVMTI_ERROR_NONE) {
873 LOG(ERROR) << "Unable to enable CLASS_PREPARE event!";
874 return 1;
875 }
Alex Lightb7edcda2017-04-27 13:20:31 -0700876 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
Alex Light43e935d2017-06-19 15:40:40 -0700877 JVMTI_EVENT_NATIVE_METHOD_BIND,
Alex Lightb7edcda2017-04-27 13:20:31 -0700878 nullptr) != JVMTI_ERROR_NONE) {
Alex Light43e935d2017-06-19 15:40:40 -0700879 LOG(ERROR) << "Unable to enable JVMTI_EVENT_NATIVE_METHOD_BIND event!";
880 return 1;
881 }
882 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
883 JVMTI_EVENT_METHOD_ENTRY,
884 nullptr) != JVMTI_ERROR_NONE) {
885 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_ENTRY event!";
886 return 1;
887 }
888 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
889 JVMTI_EVENT_METHOD_EXIT,
890 nullptr) != JVMTI_ERROR_NONE) {
891 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_EXIT event!";
892 return 1;
893 }
894 }
895 if (data->field_stress) {
896 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
897 JVMTI_EVENT_FIELD_MODIFICATION,
898 nullptr) != JVMTI_ERROR_NONE) {
899 LOG(ERROR) << "Unable to enable FIELD_MODIFICATION event!";
900 return 1;
901 }
902 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
903 JVMTI_EVENT_FIELD_ACCESS,
904 nullptr) != JVMTI_ERROR_NONE) {
905 LOG(ERROR) << "Unable to enable FIELD_ACCESS event!";
906 return 1;
907 }
908 if (!WatchAllFields(vm, jvmti)) {
Alex Lightb7edcda2017-04-27 13:20:31 -0700909 return 1;
910 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700911 }
Alex Lightc38c3692017-06-27 15:45:14 -0700912 if (data->step_stress) {
913 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
914 JVMTI_EVENT_SINGLE_STEP,
915 nullptr) != JVMTI_ERROR_NONE) {
916 return 1;
917 }
918 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700919 return 0;
920}
921
Alex Light88659142018-05-15 10:53:06 -0700922extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
923 return Agent_OnLoad(vm, options, reserved);
924}
925
Alex Light8f2c6d42017-04-10 16:27:35 -0700926} // namespace art