blob: 7fc289faeba5d6dd6f33ee2988c39cf8cd8a807e [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 Lightbfe41af2017-09-07 13:30:47 -070031#pragma clang diagnostic push
Alex Light21a71442017-09-07 13:33:35 -070032// slicer defines its own CHECK. b/65422458
33#pragma push_macro("CHECK")
34#undef CHECK
35
Alex Lightbfe41af2017-09-07 13:30:47 -070036// Slicer's headers have code that triggers these warnings. b/65298177
37#pragma clang diagnostic ignored "-Wunused-parameter"
38#pragma clang diagnostic ignored "-Wsign-compare"
Alex Lightceae9542017-09-07 13:28:00 -070039#include "code_ir.h"
40#include "control_flow_graph.h"
41#include "dex_ir.h"
42#include "dex_ir_builder.h"
43#include "instrumentation.h"
44#include "reader.h"
45#include "writer.h"
46
Alex Light21a71442017-09-07 13:33:35 -070047#pragma pop_macro("CHECK")
Alex Lightbfe41af2017-09-07 13:30:47 -070048#pragma clang diagnostic pop
49
Alex Light8f2c6d42017-04-10 16:27:35 -070050namespace art {
51
52// Should we do a 'full_rewrite' with this test?
53static constexpr bool kDoFullRewrite = true;
54
55struct StressData {
Alex Light8f2c6d42017-04-10 16:27:35 -070056 bool vm_class_loader_initialized;
Alex Lightb7edcda2017-04-27 13:20:31 -070057 bool trace_stress;
58 bool redefine_stress;
Alex Light43e935d2017-06-19 15:40:40 -070059 bool field_stress;
Alex Lightc38c3692017-06-27 15:45:14 -070060 bool step_stress;
Alex Light8f2c6d42017-04-10 16:27:35 -070061};
62
Alex Lightceae9542017-09-07 13:28:00 -070063static bool DoExtractClassFromData(jvmtiEnv* env,
64 const std::string& descriptor,
Alex Light8f2c6d42017-04-10 16:27:35 -070065 jint in_len,
66 const unsigned char* in_data,
Alex Lightceae9542017-09-07 13:28:00 -070067 /*out*/jint* out_len,
68 /*out*/unsigned char** out_data) {
69 dex::Reader reader(in_data, in_len);
70 dex::u4 class_idx = reader.FindClassIndex(descriptor.c_str());
71 if (class_idx != dex::kNoIndex) {
72 reader.CreateClassIr(class_idx);
73 } else {
74 LOG(ERROR) << "ERROR: Can't find class " << descriptor;
Alex Light8f2c6d42017-04-10 16:27:35 -070075 return false;
76 }
Alex Lightceae9542017-09-07 13:28:00 -070077 auto dex_ir = reader.GetIr();
78
79 if (kDoFullRewrite) {
80 for (auto& ir_method : dex_ir->encoded_methods) {
81 if (ir_method->code != nullptr) {
82 lir::CodeIr code_ir(ir_method.get(), dex_ir);
83 lir::ControlFlowGraph cfg_compact(&code_ir, false);
84 lir::ControlFlowGraph cfg_verbose(&code_ir, true);
85 code_ir.Assemble();
86 }
87 }
88 }
89 dex::Writer writer(dex_ir);
90
91 struct Allocator : public dex::Writer::Allocator {
92 explicit Allocator(jvmtiEnv* jvmti_env) : jvmti_env_(jvmti_env) {}
93 virtual void* Allocate(size_t size) {
94 unsigned char* out = nullptr;
95 if (JVMTI_ERROR_NONE != jvmti_env_->Allocate(size, &out)) {
96 return nullptr;
97 } else {
98 return out;
99 }
100 }
101 virtual void Free(void* ptr) {
102 jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
103 }
104 private:
105 jvmtiEnv* jvmti_env_;
106 };
107 Allocator alloc(env);
108 size_t res_len;
109 unsigned char* res = writer.CreateImage(&alloc, &res_len);
110 if (res != nullptr) {
111 *out_data = res;
112 *out_len = res_len;
113 return true;
114 } else {
115 return false;
116 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700117}
118
Alex Lightbad2f512017-06-14 11:33:55 -0700119class ScopedThreadInfo {
120 public:
121 ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread)
122 : jvmtienv_(jvmtienv), env_(env), free_name_(false) {
123 memset(&info_, 0, sizeof(info_));
124 if (thread == nullptr) {
125 info_.name = const_cast<char*>("<NULLPTR>");
126 } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) {
127 info_.name = const_cast<char*>("<UNKNOWN THREAD>");
128 } else {
129 free_name_ = true;
130 }
131 }
132
133 ~ScopedThreadInfo() {
134 if (free_name_) {
135 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name));
136 }
137 env_->DeleteLocalRef(info_.thread_group);
138 env_->DeleteLocalRef(info_.context_class_loader);
139 }
140
141 const char* GetName() const {
142 return info_.name;
143 }
144
145 private:
146 jvmtiEnv* jvmtienv_;
147 JNIEnv* env_;
148 bool free_name_;
149 jvmtiThreadInfo info_;
150};
151
152class ScopedClassInfo {
153 public:
154 ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c)
155 : jvmtienv_(jvmtienv),
156 class_(c),
157 name_(nullptr),
Alex Light6fa7b812017-06-16 09:04:29 -0700158 generic_(nullptr),
159 file_(nullptr),
160 debug_ext_(nullptr) {}
Alex Lightbad2f512017-06-14 11:33:55 -0700161
162 ~ScopedClassInfo() {
Alex Light43e935d2017-06-19 15:40:40 -0700163 if (class_ != nullptr) {
164 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
165 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
Alex Light6fa7b812017-06-16 09:04:29 -0700166 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(file_));
167 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(debug_ext_));
Alex Light43e935d2017-06-19 15:40:40 -0700168 }
Alex Lightbad2f512017-06-14 11:33:55 -0700169 }
170
171 bool Init() {
Alex Light43e935d2017-06-19 15:40:40 -0700172 if (class_ == nullptr) {
173 name_ = const_cast<char*>("<NONE>");
174 generic_ = const_cast<char*>("<NONE>");
175 return true;
176 } else {
Alex Light6fa7b812017-06-16 09:04:29 -0700177 jvmtiError ret1 = jvmtienv_->GetSourceFileName(class_, &file_);
178 jvmtiError ret2 = jvmtienv_->GetSourceDebugExtension(class_, &debug_ext_);
179 return jvmtienv_->GetClassSignature(class_, &name_, &generic_) == JVMTI_ERROR_NONE &&
180 ret1 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
181 ret1 != JVMTI_ERROR_INVALID_CLASS &&
182 ret2 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
183 ret2 != JVMTI_ERROR_INVALID_CLASS;
Alex Light43e935d2017-06-19 15:40:40 -0700184 }
Alex Lightbad2f512017-06-14 11:33:55 -0700185 }
186
187 jclass GetClass() const {
188 return class_;
189 }
190 const char* GetName() const {
191 return name_;
192 }
193 const char* GetGeneric() const {
194 return generic_;
195 }
Alex Light6fa7b812017-06-16 09:04:29 -0700196 const char* GetSourceDebugExtension() const {
197 if (debug_ext_ == nullptr) {
198 return "<UNKNOWN_SOURCE_DEBUG_EXTENSION>";
199 } else {
200 return debug_ext_;
201 }
202 }
203 const char* GetSourceFileName() const {
204 if (file_ == nullptr) {
205 return "<UNKNOWN_FILE>";
206 } else {
207 return file_;
208 }
209 }
Alex Lightbad2f512017-06-14 11:33:55 -0700210
211 private:
212 jvmtiEnv* jvmtienv_;
213 jclass class_;
214 char* name_;
215 char* generic_;
Alex Light6fa7b812017-06-16 09:04:29 -0700216 char* file_;
217 char* debug_ext_;
Alex Lightbad2f512017-06-14 11:33:55 -0700218};
219
220class ScopedMethodInfo {
221 public:
222 ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m)
223 : jvmtienv_(jvmtienv),
224 env_(env),
225 method_(m),
226 declaring_class_(nullptr),
227 class_info_(nullptr),
228 name_(nullptr),
229 signature_(nullptr),
Alex Light6fa7b812017-06-16 09:04:29 -0700230 generic_(nullptr),
231 first_line_(-1) {}
Alex Lightbad2f512017-06-14 11:33:55 -0700232
233 ~ScopedMethodInfo() {
234 env_->DeleteLocalRef(declaring_class_);
235 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
236 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
237 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
238 }
239
240 bool Init() {
241 if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
242 return false;
243 }
244 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
Alex Light6fa7b812017-06-16 09:04:29 -0700245 jint nlines;
246 jvmtiLineNumberEntry* lines;
247 jvmtiError err = jvmtienv_->GetLineNumberTable(method_, &nlines, &lines);
248 if (err == JVMTI_ERROR_NONE) {
249 if (nlines > 0) {
250 first_line_ = lines[0].line_number;
251 }
252 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(lines));
253 } else if (err != JVMTI_ERROR_ABSENT_INFORMATION &&
254 err != JVMTI_ERROR_NATIVE_METHOD) {
255 return false;
256 }
Alex Lightbad2f512017-06-14 11:33:55 -0700257 return class_info_->Init() &&
258 (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
259 }
260
261 const ScopedClassInfo& GetDeclaringClassInfo() const {
262 return *class_info_;
263 }
264
265 jclass GetDeclaringClass() const {
266 return declaring_class_;
267 }
268
269 const char* GetName() const {
270 return name_;
271 }
272
273 const char* GetSignature() const {
274 return signature_;
275 }
276
277 const char* GetGeneric() const {
278 return generic_;
279 }
280
Alex Light6fa7b812017-06-16 09:04:29 -0700281 jint GetFirstLine() const {
282 return first_line_;
283 }
284
Alex Lightbad2f512017-06-14 11:33:55 -0700285 private:
286 jvmtiEnv* jvmtienv_;
287 JNIEnv* env_;
288 jmethodID method_;
289 jclass declaring_class_;
290 std::unique_ptr<ScopedClassInfo> class_info_;
291 char* name_;
292 char* signature_;
293 char* generic_;
Alex Light6fa7b812017-06-16 09:04:29 -0700294 jint first_line_;
Alex Lightbad2f512017-06-14 11:33:55 -0700295
296 friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
297};
298
Alex Light43e935d2017-06-19 15:40:40 -0700299class ScopedFieldInfo {
300 public:
301 ScopedFieldInfo(jvmtiEnv* jvmtienv, jclass field_klass, jfieldID field)
302 : jvmtienv_(jvmtienv),
303 declaring_class_(field_klass),
304 field_(field),
305 class_info_(nullptr),
306 name_(nullptr),
307 type_(nullptr),
308 generic_(nullptr) {}
309
310 ~ScopedFieldInfo() {
311 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
312 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(type_));
313 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
314 }
315
316 bool Init() {
317 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
318 return class_info_->Init() &&
319 (jvmtienv_->GetFieldName(
320 declaring_class_, field_, &name_, &type_, &generic_) == JVMTI_ERROR_NONE);
321 }
322
323 const ScopedClassInfo& GetDeclaringClassInfo() const {
324 return *class_info_;
325 }
326
327 jclass GetDeclaringClass() const {
328 return declaring_class_;
329 }
330
331 const char* GetName() const {
332 return name_;
333 }
334
335 const char* GetType() const {
336 return type_;
337 }
338
339 const char* GetGeneric() const {
340 return generic_;
341 }
342
343 private:
344 jvmtiEnv* jvmtienv_;
345 jclass declaring_class_;
346 jfieldID field_;
347 std::unique_ptr<ScopedClassInfo> class_info_;
348 char* name_;
349 char* type_;
350 char* generic_;
351
352 friend std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m);
353};
354
355std::ostream& operator<<(std::ostream &os, const ScopedFieldInfo* m) {
356 return os << *m;
357}
358
359std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m) {
360 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName()
361 << ":" << m.GetType();
362}
363
Alex Lightbad2f512017-06-14 11:33:55 -0700364std::ostream& operator<<(std::ostream &os, const ScopedMethodInfo* m) {
365 return os << *m;
366}
367
368std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
Alex Light6fa7b812017-06-16 09:04:29 -0700369 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature()
370 << " (source: " << m.GetDeclaringClassInfo().GetSourceFileName() << ":"
371 << m.GetFirstLine() << ")";
Alex Lightbad2f512017-06-14 11:33:55 -0700372}
373
Alex Light0af8cde2017-04-20 13:35:05 -0700374static void doJvmtiMethodBind(jvmtiEnv* jvmtienv,
375 JNIEnv* env,
376 jthread thread,
377 jmethodID m,
378 void* address,
379 /*out*/void** out_address) {
380 *out_address = address;
Alex Lightbad2f512017-06-14 11:33:55 -0700381 ScopedThreadInfo thread_info(jvmtienv, env, thread);
382 ScopedMethodInfo method_info(jvmtienv, env, m);
383 if (!method_info.Init()) {
384 LOG(ERROR) << "Unable to get method info!";
Alex Light0af8cde2017-04-20 13:35:05 -0700385 return;
386 }
Alex Lightbad2f512017-06-14 11:33:55 -0700387 LOG(INFO) << "Loading native method \"" << method_info << "\". Thread is "
388 << thread_info.GetName();
Alex Light0af8cde2017-04-20 13:35:05 -0700389}
390
Alex Lightb7edcda2017-04-27 13:20:31 -0700391static std::string GetName(jvmtiEnv* jvmtienv, JNIEnv* jnienv, jobject obj) {
392 jclass klass = jnienv->GetObjectClass(obj);
393 char *cname, *cgen;
394 if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
395 LOG(ERROR) << "Unable to get class name!";
396 jnienv->DeleteLocalRef(klass);
397 return "<UNKNOWN>";
398 }
399 std::string name(cname);
400 if (name == "Ljava/lang/String;") {
401 jstring str = reinterpret_cast<jstring>(obj);
402 const char* val = jnienv->GetStringUTFChars(str, nullptr);
403 if (val == nullptr) {
404 name += " (unable to get value)";
405 } else {
406 std::ostringstream oss;
407 oss << name << " (value: \"" << val << "\")";
408 name = oss.str();
409 jnienv->ReleaseStringUTFChars(str, val);
410 }
411 }
412 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
413 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
414 jnienv->DeleteLocalRef(klass);
415 return name;
416}
417
418static std::string GetValOf(jvmtiEnv* env, JNIEnv* jnienv, std::string type, jvalue val) {
419 std::ostringstream oss;
420 switch (type[0]) {
421 case '[':
422 case 'L':
423 return val.l != nullptr ? GetName(env, jnienv, val.l) : "null";
424 case 'Z':
425 return val.z == JNI_TRUE ? "true" : "false";
426 case 'B':
427 oss << val.b;
428 return oss.str();
429 case 'C':
430 oss << val.c;
431 return oss.str();
432 case 'S':
433 oss << val.s;
434 return oss.str();
435 case 'I':
436 oss << val.i;
437 return oss.str();
438 case 'J':
439 oss << val.j;
440 return oss.str();
441 case 'F':
442 oss << val.f;
443 return oss.str();
444 case 'D':
445 oss << val.d;
446 return oss.str();
447 case 'V':
448 return "<void>";
449 default:
450 return "<ERROR Found type " + type + ">";
451 }
452}
453
Alex Light43e935d2017-06-19 15:40:40 -0700454void JNICALL FieldAccessHook(jvmtiEnv* jvmtienv,
455 JNIEnv* env,
456 jthread thread,
457 jmethodID m,
458 jlocation location,
459 jclass field_klass,
460 jobject object,
461 jfieldID field) {
462 ScopedThreadInfo info(jvmtienv, env, thread);
463 ScopedMethodInfo method_info(jvmtienv, env, m);
464 ScopedFieldInfo field_info(jvmtienv, field_klass, field);
465 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr;
466 ScopedClassInfo obj_class_info(jvmtienv, oklass);
467 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) {
468 LOG(ERROR) << "Unable to get callback info!";
469 return;
470 }
471 LOG(INFO) << "ACCESS field \"" << field_info << "\" on object of "
472 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info
473 << "\" at location 0x" << std::hex << location << ". Thread is \""
474 << info.GetName() << "\".";
475 env->DeleteLocalRef(oklass);
476}
477
478static std::string PrintJValue(jvmtiEnv* jvmtienv, JNIEnv* env, char type, jvalue new_value) {
479 std::ostringstream oss;
480 switch (type) {
481 case 'L': {
482 jobject nv = new_value.l;
483 if (nv == nullptr) {
484 oss << "\"null\"";
485 } else {
486 jclass nv_klass = env->GetObjectClass(nv);
487 ScopedClassInfo nv_class_info(jvmtienv, nv_klass);
488 if (!nv_class_info.Init()) {
489 oss << "with unknown type";
490 } else {
491 oss << "of type \"" << nv_class_info.GetName() << "\"";
492 }
493 env->DeleteLocalRef(nv_klass);
494 }
495 break;
496 }
497 case 'Z': {
498 if (new_value.z) {
499 oss << "true";
500 } else {
501 oss << "false";
502 }
503 break;
504 }
505#define SEND_VALUE(chr, sym, type) \
506 case chr: { \
507 oss << static_cast<type>(new_value.sym); \
508 break; \
509 }
510 SEND_VALUE('B', b, int8_t);
511 SEND_VALUE('C', c, uint16_t);
512 SEND_VALUE('S', s, int16_t);
513 SEND_VALUE('I', i, int32_t);
514 SEND_VALUE('J', j, int64_t);
515 SEND_VALUE('F', f, float);
516 SEND_VALUE('D', d, double);
517#undef SEND_VALUE
518 }
519 return oss.str();
520}
521
522void JNICALL FieldModificationHook(jvmtiEnv* jvmtienv,
523 JNIEnv* env,
524 jthread thread,
525 jmethodID m,
526 jlocation location,
527 jclass field_klass,
528 jobject object,
529 jfieldID field,
530 char type,
531 jvalue new_value) {
532 ScopedThreadInfo info(jvmtienv, env, thread);
533 ScopedMethodInfo method_info(jvmtienv, env, m);
534 ScopedFieldInfo field_info(jvmtienv, field_klass, field);
535 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr;
536 ScopedClassInfo obj_class_info(jvmtienv, oklass);
537 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) {
538 LOG(ERROR) << "Unable to get callback info!";
539 return;
540 }
541 LOG(INFO) << "MODIFY field \"" << field_info << "\" on object of "
542 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info
543 << "\" at location 0x" << std::hex << location << std::dec << ". New value is "
544 << PrintJValue(jvmtienv, env, type, new_value) << ". Thread is \""
545 << info.GetName() << "\".";
546 env->DeleteLocalRef(oklass);
547}
Alex Lightb7edcda2017-04-27 13:20:31 -0700548void JNICALL MethodExitHook(jvmtiEnv* jvmtienv,
549 JNIEnv* env,
550 jthread thread,
551 jmethodID m,
552 jboolean was_popped_by_exception,
553 jvalue val) {
Alex Lightbad2f512017-06-14 11:33:55 -0700554 ScopedThreadInfo info(jvmtienv, env, thread);
555 ScopedMethodInfo method_info(jvmtienv, env, m);
556 if (!method_info.Init()) {
557 LOG(ERROR) << "Unable to get method info!";
Alex Lightb7edcda2017-04-27 13:20:31 -0700558 return;
559 }
Alex Lightbad2f512017-06-14 11:33:55 -0700560 std::string type(method_info.GetSignature());
Andreas Gampe5555dd12017-08-24 13:50:21 -0700561 type = type.substr(type.find(')') + 1);
Alex Lightb7edcda2017-04-27 13:20:31 -0700562 std::string out_val(was_popped_by_exception ? "" : GetValOf(jvmtienv, env, type, val));
Alex Lightbad2f512017-06-14 11:33:55 -0700563 LOG(INFO) << "Leaving method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"."
564 << std::endl
Alex Lightb7edcda2017-04-27 13:20:31 -0700565 << " Cause: " << (was_popped_by_exception ? "exception" : "return ")
566 << out_val << ".";
Alex Lightb7edcda2017-04-27 13:20:31 -0700567}
568
569void JNICALL MethodEntryHook(jvmtiEnv* jvmtienv,
570 JNIEnv* env,
571 jthread thread,
572 jmethodID m) {
Alex Lightbad2f512017-06-14 11:33:55 -0700573 ScopedThreadInfo info(jvmtienv, env, thread);
574 ScopedMethodInfo method_info(jvmtienv, env, m);
575 if (!method_info.Init()) {
576 LOG(ERROR) << "Unable to get method info!";
Alex Lightb7edcda2017-04-27 13:20:31 -0700577 return;
578 }
Alex Lightbad2f512017-06-14 11:33:55 -0700579 LOG(INFO) << "Entering method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"";
Alex Lightb7edcda2017-04-27 13:20:31 -0700580}
581
Alex Light72398652017-06-16 09:08:12 -0700582void JNICALL ClassPrepareHook(jvmtiEnv* jvmtienv,
583 JNIEnv* env,
584 jthread thread,
585 jclass klass) {
Alex Light43e935d2017-06-19 15:40:40 -0700586 StressData* data = nullptr;
587 CHECK_EQ(jvmtienv->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
588 JVMTI_ERROR_NONE);
589 if (data->field_stress) {
590 jint nfields;
591 jfieldID* fields;
592 if (jvmtienv->GetClassFields(klass, &nfields, &fields) != JVMTI_ERROR_NONE) {
593 LOG(ERROR) << "Unable to get a classes fields!";
594 return;
595 }
596 for (jint i = 0; i < nfields; i++) {
597 jfieldID f = fields[i];
598 // Ignore errors
599 jvmtienv->SetFieldAccessWatch(klass, f);
600 jvmtienv->SetFieldModificationWatch(klass, f);
601 }
602 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fields));
Alex Light72398652017-06-16 09:08:12 -0700603 }
Alex Light43e935d2017-06-19 15:40:40 -0700604 if (data->trace_stress) {
605 ScopedThreadInfo info(jvmtienv, env, thread);
606 ScopedClassInfo class_info(jvmtienv, klass);
607 if (!class_info.Init()) {
608 LOG(ERROR) << "Unable to get class info!";
609 return;
610 }
611 LOG(INFO) << "Prepared class \"" << class_info.GetName() << "\". Thread is \""
612 << info.GetName() << "\"";
613 }
Alex Light72398652017-06-16 09:08:12 -0700614}
615
Alex Lightc38c3692017-06-27 15:45:14 -0700616void JNICALL SingleStepHook(jvmtiEnv* jvmtienv,
617 JNIEnv* env,
618 jthread thread,
619 jmethodID method,
620 jlocation location) {
621 ScopedThreadInfo info(jvmtienv, env, thread);
622 ScopedMethodInfo method_info(jvmtienv, env, method);
623 if (!method_info.Init()) {
624 LOG(ERROR) << "Unable to get method info!";
625 return;
626 }
627 LOG(INFO) << "Single step at location: 0x" << std::setw(8) << std::setfill('0') << std::hex
628 << location << " in method " << method_info << " thread: " << info.GetName();
629}
630
Alex Light8f2c6d42017-04-10 16:27:35 -0700631// The hook we are using.
632void JNICALL ClassFileLoadHookSecretNoOp(jvmtiEnv* jvmti,
633 JNIEnv* jni_env ATTRIBUTE_UNUSED,
634 jclass class_being_redefined ATTRIBUTE_UNUSED,
635 jobject loader ATTRIBUTE_UNUSED,
636 const char* name,
637 jobject protection_domain ATTRIBUTE_UNUSED,
638 jint class_data_len,
639 const unsigned char* class_data,
640 jint* new_class_data_len,
641 unsigned char** new_class_data) {
642 std::vector<unsigned char> out;
Alex Lightceae9542017-09-07 13:28:00 -0700643 // Make the jvmti semi-descriptor into the full descriptor.
644 std::string name_str("L");
645 name_str += name;
646 name_str += ";";
Alex Light8f2c6d42017-04-10 16:27:35 -0700647 StressData* data = nullptr;
648 CHECK_EQ(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
649 JVMTI_ERROR_NONE);
650 if (!data->vm_class_loader_initialized) {
651 LOG(WARNING) << "Ignoring load of class " << name << " because VMClassLoader is not yet "
652 << "initialized. Transforming this class could cause spurious test failures.";
653 return;
Alex Lightceae9542017-09-07 13:28:00 -0700654 } else if (DoExtractClassFromData(jvmti, name_str, class_data_len, class_data,
655 /*out*/ new_class_data_len, /*out*/ new_class_data)) {
Alex Light8f2c6d42017-04-10 16:27:35 -0700656 LOG(INFO) << "Extracted class: " << name;
Alex Light8f2c6d42017-04-10 16:27:35 -0700657 } else {
Alex Lightceae9542017-09-07 13:28:00 -0700658 std::cerr << "Unable to extract class " << name << std::endl;
Alex Light8f2c6d42017-04-10 16:27:35 -0700659 *new_class_data_len = 0;
660 *new_class_data = nullptr;
661 }
662}
663
Alex Lightb7edcda2017-04-27 13:20:31 -0700664static std::string AdvanceOption(const std::string& ops) {
665 return ops.substr(ops.find(',') + 1);
Alex Light8f2c6d42017-04-10 16:27:35 -0700666}
667
Alex Lightb7edcda2017-04-27 13:20:31 -0700668static bool HasNextOption(const std::string& ops) {
669 return ops.find(',') != std::string::npos;
670}
671
672static std::string GetOption(const std::string& in) {
673 return in.substr(0, in.find(','));
674}
675
676// Options are
Alex Lightceae9542017-09-07 13:28:00 -0700677// jvmti-stress,[redefine,][trace,][field]
Alex Lightb7edcda2017-04-27 13:20:31 -0700678static void ReadOptions(StressData* data, char* options) {
679 std::string ops(options);
680 CHECK_EQ(GetOption(ops), "jvmti-stress") << "Options should start with jvmti-stress";
681 do {
682 ops = AdvanceOption(ops);
683 std::string cur = GetOption(ops);
684 if (cur == "trace") {
685 data->trace_stress = true;
Alex Lightc38c3692017-06-27 15:45:14 -0700686 } else if (cur == "step") {
687 data->step_stress = true;
Alex Light43e935d2017-06-19 15:40:40 -0700688 } else if (cur == "field") {
689 data->field_stress = true;
Alex Lightb7edcda2017-04-27 13:20:31 -0700690 } else if (cur == "redefine") {
691 data->redefine_stress = true;
Alex Lightb7edcda2017-04-27 13:20:31 -0700692 } else {
693 LOG(FATAL) << "Unknown option: " << GetOption(ops);
694 }
695 } while (HasNextOption(ops));
696}
697
698// Do final setup during the VMInit callback. By this time most things are all setup.
699static void JNICALL PerformFinalSetupVMInit(jvmtiEnv *jvmti_env,
700 JNIEnv* jni_env,
701 jthread thread ATTRIBUTE_UNUSED) {
Alex Light8f2c6d42017-04-10 16:27:35 -0700702 // Load the VMClassLoader class. We will get a ClassNotFound exception because we don't have
703 // visibility but the class will be loaded behind the scenes.
704 LOG(INFO) << "manual load & initialization of class java/lang/VMClassLoader!";
705 jclass klass = jni_env->FindClass("java/lang/VMClassLoader");
Alex Lightb7edcda2017-04-27 13:20:31 -0700706 StressData* data = nullptr;
707 CHECK_EQ(jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
708 JVMTI_ERROR_NONE);
709 // We need to make sure that VMClassLoader is initialized before we start redefining anything
710 // since it can give (non-fatal) error messages if it's initialized after we've redefined BCP
711 // classes. These error messages are expected and no problem but they will mess up our testing
712 // infrastructure.
Alex Light8f2c6d42017-04-10 16:27:35 -0700713 if (klass == nullptr) {
Alex Light42151c02017-04-20 15:54:25 -0700714 // Probably on RI. Clear the exception so we can continue but don't mark vmclassloader as
715 // initialized.
716 LOG(WARNING) << "Unable to find VMClassLoader class!";
717 jni_env->ExceptionClear();
Alex Light8f2c6d42017-04-10 16:27:35 -0700718 } else {
719 // GetMethodID is spec'd to cause the class to be initialized.
720 jni_env->GetMethodID(klass, "hashCode", "()I");
721 jni_env->DeleteLocalRef(klass);
Alex Light8f2c6d42017-04-10 16:27:35 -0700722 data->vm_class_loader_initialized = true;
723 }
Alex Light43e935d2017-06-19 15:40:40 -0700724}
725
726static bool WatchAllFields(JavaVM* vm, jvmtiEnv* jvmti) {
727 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
728 JVMTI_EVENT_CLASS_PREPARE,
729 nullptr) != JVMTI_ERROR_NONE) {
730 LOG(ERROR) << "Couldn't set prepare event!";
731 return false;
Alex Lightb7edcda2017-04-27 13:20:31 -0700732 }
Alex Light43e935d2017-06-19 15:40:40 -0700733 // TODO We really shouldn't need to do this step here.
734 jint nklass;
735 jclass* klasses;
736 if (jvmti->GetLoadedClasses(&nklass, &klasses) != JVMTI_ERROR_NONE) {
737 LOG(WARNING) << "Couldn't get loaded classes! Ignoring.";
738 return true;
739 }
740 JNIEnv* jni = nullptr;
741 if (vm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6)) {
742 LOG(ERROR) << "Unable to get jni env. Ignoring and potentially leaking jobjects.";
743 return false;
744 }
745 for (jint i = 0; i < nklass; i++) {
746 jclass k = klasses[i];
747 ScopedClassInfo sci(jvmti, k);
748 if (sci.Init()) {
749 LOG(INFO) << "NOTE: class " << sci.GetName() << " already loaded.";
750 }
751 jint nfields;
752 jfieldID* fields;
753 jvmtiError err = jvmti->GetClassFields(k, &nfields, &fields);
754 if (err == JVMTI_ERROR_NONE) {
755 for (jint j = 0; j < nfields; j++) {
756 jfieldID f = fields[j];
757 if (jvmti->SetFieldModificationWatch(k, f) != JVMTI_ERROR_NONE ||
758 jvmti->SetFieldAccessWatch(k, f) != JVMTI_ERROR_NONE) {
759 LOG(ERROR) << "Unable to set watches on a field.";
760 return false;
761 }
762 }
763 } else if (err != JVMTI_ERROR_CLASS_NOT_PREPARED) {
764 LOG(ERROR) << "Unexpected error getting class fields!";
765 return false;
766 }
767 jvmti->Deallocate(reinterpret_cast<unsigned char*>(fields));
768 jni->DeleteLocalRef(k);
769 }
770 jvmti->Deallocate(reinterpret_cast<unsigned char*>(klasses));
771 return true;
Alex Light8f2c6d42017-04-10 16:27:35 -0700772}
773
774extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm,
775 char* options,
776 void* reserved ATTRIBUTE_UNUSED) {
777 jvmtiEnv* jvmti = nullptr;
778 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0)) {
779 LOG(ERROR) << "Unable to get jvmti env.";
780 return 1;
781 }
782 StressData* data = nullptr;
783 if (JVMTI_ERROR_NONE != jvmti->Allocate(sizeof(StressData),
784 reinterpret_cast<unsigned char**>(&data))) {
785 LOG(ERROR) << "Unable to allocate data for stress test.";
786 return 1;
787 }
788 memset(data, 0, sizeof(StressData));
789 // Read the options into the static variables that hold them.
790 ReadOptions(data, options);
791 // Save the data
792 if (JVMTI_ERROR_NONE != jvmti->SetEnvironmentLocalStorage(data)) {
793 LOG(ERROR) << "Unable to save stress test data.";
794 return 1;
795 }
796
797 // Just get all capabilities.
Alex Light3d324fd2017-07-20 15:38:52 -0700798 jvmtiCapabilities caps = {
799 .can_tag_objects = 0,
800 .can_generate_field_modification_events = 1,
801 .can_generate_field_access_events = 1,
802 .can_get_bytecodes = 0,
803 .can_get_synthetic_attribute = 0,
804 .can_get_owned_monitor_info = 0,
805 .can_get_current_contended_monitor = 0,
806 .can_get_monitor_info = 0,
807 .can_pop_frame = 0,
808 .can_redefine_classes = 1,
809 .can_signal_thread = 0,
810 .can_get_source_file_name = 1,
811 .can_get_line_numbers = 1,
Alex Lightc2a082a2018-01-12 09:16:28 -0800812 .can_get_source_debug_extension = 1,
Alex Light3d324fd2017-07-20 15:38:52 -0700813 .can_access_local_variables = 0,
814 .can_maintain_original_method_order = 0,
815 .can_generate_single_step_events = 1,
816 .can_generate_exception_events = 0,
817 .can_generate_frame_pop_events = 0,
818 .can_generate_breakpoint_events = 0,
819 .can_suspend = 0,
820 .can_redefine_any_class = 0,
821 .can_get_current_thread_cpu_time = 0,
822 .can_get_thread_cpu_time = 0,
823 .can_generate_method_entry_events = 1,
824 .can_generate_method_exit_events = 1,
825 .can_generate_all_class_hook_events = 0,
826 .can_generate_compiled_method_load_events = 0,
827 .can_generate_monitor_events = 0,
828 .can_generate_vm_object_alloc_events = 0,
829 .can_generate_native_method_bind_events = 1,
830 .can_generate_garbage_collection_events = 0,
831 .can_generate_object_free_events = 0,
832 .can_force_early_return = 0,
833 .can_get_owned_monitor_stack_depth_info = 0,
834 .can_get_constant_pool = 0,
835 .can_set_native_method_prefix = 0,
836 .can_retransform_classes = 1,
837 .can_retransform_any_class = 0,
838 .can_generate_resource_exhaustion_heap_events = 0,
839 .can_generate_resource_exhaustion_threads_events = 0,
840 };
Alex Light8f2c6d42017-04-10 16:27:35 -0700841 jvmti->AddCapabilities(&caps);
842
843 // Set callbacks.
844 jvmtiEventCallbacks cb;
845 memset(&cb, 0, sizeof(cb));
846 cb.ClassFileLoadHook = ClassFileLoadHookSecretNoOp;
Alex Light0af8cde2017-04-20 13:35:05 -0700847 cb.NativeMethodBind = doJvmtiMethodBind;
Alex Lightb7edcda2017-04-27 13:20:31 -0700848 cb.VMInit = PerformFinalSetupVMInit;
849 cb.MethodEntry = MethodEntryHook;
850 cb.MethodExit = MethodExitHook;
Alex Light43e935d2017-06-19 15:40:40 -0700851 cb.FieldAccess = FieldAccessHook;
852 cb.FieldModification = FieldModificationHook;
Alex Light72398652017-06-16 09:08:12 -0700853 cb.ClassPrepare = ClassPrepareHook;
Alex Lightc38c3692017-06-27 15:45:14 -0700854 cb.SingleStep = SingleStepHook;
Alex Light8f2c6d42017-04-10 16:27:35 -0700855 if (jvmti->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
856 LOG(ERROR) << "Unable to set class file load hook cb!";
857 return 1;
858 }
859 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
Alex Light8f2c6d42017-04-10 16:27:35 -0700860 JVMTI_EVENT_VM_INIT,
861 nullptr) != JVMTI_ERROR_NONE) {
862 LOG(ERROR) << "Unable to enable JVMTI_EVENT_VM_INIT event!";
863 return 1;
864 }
Alex Light43e935d2017-06-19 15:40:40 -0700865 if (data->redefine_stress) {
866 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
867 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
868 nullptr) != JVMTI_ERROR_NONE) {
869 LOG(ERROR) << "Unable to enable CLASS_FILE_LOAD_HOOK event!";
870 return 1;
871 }
872 }
Alex Light72398652017-06-16 09:08:12 -0700873 if (data->trace_stress) {
874 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
875 JVMTI_EVENT_CLASS_PREPARE,
876 nullptr) != JVMTI_ERROR_NONE) {
877 LOG(ERROR) << "Unable to enable CLASS_PREPARE event!";
878 return 1;
879 }
Alex Lightb7edcda2017-04-27 13:20:31 -0700880 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
Alex Light43e935d2017-06-19 15:40:40 -0700881 JVMTI_EVENT_NATIVE_METHOD_BIND,
Alex Lightb7edcda2017-04-27 13:20:31 -0700882 nullptr) != JVMTI_ERROR_NONE) {
Alex Light43e935d2017-06-19 15:40:40 -0700883 LOG(ERROR) << "Unable to enable JVMTI_EVENT_NATIVE_METHOD_BIND event!";
884 return 1;
885 }
886 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
887 JVMTI_EVENT_METHOD_ENTRY,
888 nullptr) != JVMTI_ERROR_NONE) {
889 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_ENTRY event!";
890 return 1;
891 }
892 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
893 JVMTI_EVENT_METHOD_EXIT,
894 nullptr) != JVMTI_ERROR_NONE) {
895 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_EXIT event!";
896 return 1;
897 }
898 }
899 if (data->field_stress) {
900 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
901 JVMTI_EVENT_FIELD_MODIFICATION,
902 nullptr) != JVMTI_ERROR_NONE) {
903 LOG(ERROR) << "Unable to enable FIELD_MODIFICATION event!";
904 return 1;
905 }
906 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
907 JVMTI_EVENT_FIELD_ACCESS,
908 nullptr) != JVMTI_ERROR_NONE) {
909 LOG(ERROR) << "Unable to enable FIELD_ACCESS event!";
910 return 1;
911 }
912 if (!WatchAllFields(vm, jvmti)) {
Alex Lightb7edcda2017-04-27 13:20:31 -0700913 return 1;
914 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700915 }
Alex Lightc38c3692017-06-27 15:45:14 -0700916 if (data->step_stress) {
917 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
918 JVMTI_EVENT_SINGLE_STEP,
919 nullptr) != JVMTI_ERROR_NONE) {
920 return 1;
921 }
922 }
Alex Light8f2c6d42017-04-10 16:27:35 -0700923 return 0;
924}
925
926} // namespace art