1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <cstdio> 18 #include <fstream> 19 #include <iomanip> 20 #include <iostream> 21 #include <memory> 22 #include <sstream> 23 #include <strstream> 24 25 #include <jni.h> 26 27 #include "base/utils.h" 28 #include "jvmti.h" 29 30 #pragma clang diagnostic push 31 32 // 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" 35 36 #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 44 #pragma clang diagnostic pop 45 46 namespace art { 47 48 // Should we do a 'full_rewrite' with this test? 49 static constexpr bool kDoFullRewrite = true; 50 51 struct StressData { 52 bool vm_class_loader_initialized; 53 bool trace_stress; 54 bool redefine_stress; 55 bool field_stress; 56 bool step_stress; 57 }; 58 59 static void DeleteLocalRef(JNIEnv* env, jobject obj) { 60 if (obj != nullptr) { 61 env->DeleteLocalRef(obj); 62 } 63 } 64 65 static bool DoExtractClassFromData(jvmtiEnv* env, 66 const std::string& descriptor, 67 jint in_len, 68 const unsigned char* in_data, 69 /*out*/jint* out_len, 70 /*out*/unsigned char** out_data) { 71 dex::Reader reader(in_data, in_len); 72 dex::u4 class_idx = reader.FindClassIndex(descriptor.c_str()); 73 if (class_idx != dex::kNoIndex) { 74 reader.CreateClassIr(class_idx); 75 } else { 76 LOG(ERROR) << "ERROR: Can't find class " << descriptor; 77 return false; 78 } 79 auto dex_ir = reader.GetIr(); 80 81 if (kDoFullRewrite) { 82 for (auto& ir_method : dex_ir->encoded_methods) { 83 if (ir_method->code != nullptr) { 84 lir::CodeIr code_ir(ir_method.get(), dex_ir); 85 lir::ControlFlowGraph cfg_compact(&code_ir, false); 86 lir::ControlFlowGraph cfg_verbose(&code_ir, true); 87 code_ir.Assemble(); 88 } 89 } 90 } 91 dex::Writer writer(dex_ir); 92 93 struct Allocator : public dex::Writer::Allocator { 94 explicit Allocator(jvmtiEnv* jvmti_env) : jvmti_env_(jvmti_env) {} 95 void* Allocate(size_t size) override { 96 unsigned char* out = nullptr; 97 if (JVMTI_ERROR_NONE != jvmti_env_->Allocate(size, &out)) { 98 return nullptr; 99 } else { 100 return out; 101 } 102 } 103 void Free(void* ptr) override { 104 jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(ptr)); 105 } 106 private: 107 jvmtiEnv* jvmti_env_; 108 }; 109 Allocator alloc(env); 110 size_t res_len; 111 unsigned char* res = writer.CreateImage(&alloc, &res_len); 112 if (res != nullptr) { 113 *out_data = res; 114 *out_len = res_len; 115 return true; 116 } else { 117 return false; 118 } 119 } 120 121 class ScopedThreadInfo { 122 public: 123 ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread) 124 : jvmtienv_(jvmtienv), env_(env), free_name_(false) { 125 memset(&info_, 0, sizeof(info_)); 126 if (thread == nullptr) { 127 info_.name = const_cast<char*>("<NULLPTR>"); 128 } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) { 129 info_.name = const_cast<char*>("<UNKNOWN THREAD>"); 130 } else { 131 free_name_ = true; 132 } 133 } 134 135 ~ScopedThreadInfo() { 136 if (free_name_) { 137 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name)); 138 } 139 DeleteLocalRef(env_, info_.thread_group); 140 DeleteLocalRef(env_, info_.context_class_loader); 141 } 142 143 const char* GetName() const { 144 return info_.name; 145 } 146 147 private: 148 jvmtiEnv* jvmtienv_; 149 JNIEnv* env_; 150 bool free_name_; 151 jvmtiThreadInfo info_; 152 }; 153 154 class ScopedClassInfo { 155 public: 156 ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c) 157 : jvmtienv_(jvmtienv), 158 class_(c), 159 name_(nullptr), 160 file_(nullptr), 161 debug_ext_(nullptr) {} 162 163 ~ScopedClassInfo() { 164 if (class_ != nullptr) { 165 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_)); 166 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(file_)); 167 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(debug_ext_)); 168 } 169 } 170 171 bool Init() { 172 if (class_ == nullptr) { 173 name_ = const_cast<char*>("<NONE>"); 174 return true; 175 } else { 176 jvmtiError ret1 = jvmtienv_->GetSourceFileName(class_, &file_); 177 jvmtiError ret2 = jvmtienv_->GetSourceDebugExtension(class_, &debug_ext_); 178 return jvmtienv_->GetClassSignature(class_, &name_, nullptr) == JVMTI_ERROR_NONE && 179 ret1 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY && 180 ret1 != JVMTI_ERROR_INVALID_CLASS && 181 ret2 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY && 182 ret2 != JVMTI_ERROR_INVALID_CLASS; 183 } 184 } 185 186 jclass GetClass() const { 187 return class_; 188 } 189 const char* GetName() const { 190 return name_; 191 } 192 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 } 206 207 private: 208 jvmtiEnv* jvmtienv_; 209 jclass class_; 210 char* name_; 211 char* file_; 212 char* debug_ext_; 213 }; 214 215 class ScopedMethodInfo { 216 public: 217 ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m) 218 : jvmtienv_(jvmtienv), 219 env_(env), 220 method_(m), 221 declaring_class_(nullptr), 222 class_info_(nullptr), 223 name_(nullptr), 224 signature_(nullptr), 225 first_line_(-1) {} 226 227 ~ScopedMethodInfo() { 228 DeleteLocalRef(env_, declaring_class_); 229 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_)); 230 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_)); 231 } 232 233 bool Init() { 234 if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) { 235 return false; 236 } 237 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_)); 238 jint nlines; 239 jvmtiLineNumberEntry* lines; 240 jvmtiError err = jvmtienv_->GetLineNumberTable(method_, &nlines, &lines); 241 if (err == JVMTI_ERROR_NONE) { 242 if (nlines > 0) { 243 first_line_ = lines[0].line_number; 244 } 245 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(lines)); 246 } else if (err != JVMTI_ERROR_ABSENT_INFORMATION && 247 err != JVMTI_ERROR_NATIVE_METHOD) { 248 return false; 249 } 250 return class_info_->Init() && 251 (jvmtienv_->GetMethodName(method_, &name_, &signature_, nullptr) == JVMTI_ERROR_NONE); 252 } 253 254 const ScopedClassInfo& GetDeclaringClassInfo() const { 255 return *class_info_; 256 } 257 258 jclass GetDeclaringClass() const { 259 return declaring_class_; 260 } 261 262 const char* GetName() const { 263 return name_; 264 } 265 266 const char* GetSignature() const { 267 return signature_; 268 } 269 270 jint GetFirstLine() const { 271 return first_line_; 272 } 273 274 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 jint first_line_; 283 284 friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m); 285 }; 286 287 class ScopedFieldInfo { 288 public: 289 ScopedFieldInfo(jvmtiEnv* jvmtienv, jclass field_klass, jfieldID field) 290 : jvmtienv_(jvmtienv), 291 declaring_class_(field_klass), 292 field_(field), 293 class_info_(nullptr), 294 name_(nullptr), 295 type_(nullptr) {} 296 297 ~ScopedFieldInfo() { 298 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_)); 299 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(type_)); 300 } 301 302 bool Init() { 303 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_)); 304 return class_info_->Init() && 305 (jvmtienv_->GetFieldName( 306 declaring_class_, field_, &name_, &type_, nullptr) == JVMTI_ERROR_NONE); 307 } 308 309 const ScopedClassInfo& GetDeclaringClassInfo() const { 310 return *class_info_; 311 } 312 313 jclass GetDeclaringClass() const { 314 return declaring_class_; 315 } 316 317 const char* GetName() const { 318 return name_; 319 } 320 321 const char* GetType() const { 322 return type_; 323 } 324 325 private: 326 jvmtiEnv* jvmtienv_; 327 jclass declaring_class_; 328 jfieldID field_; 329 std::unique_ptr<ScopedClassInfo> class_info_; 330 char* name_; 331 char* type_; 332 333 friend std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m); 334 }; 335 336 std::ostream& operator<<(std::ostream &os, const ScopedFieldInfo* m) { 337 return os << *m; 338 } 339 340 std::ostream& operator<<(std::ostream &os, ScopedFieldInfo const& m) { 341 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() 342 << ":" << m.GetType(); 343 } 344 345 std::ostream& operator<<(std::ostream &os, const ScopedMethodInfo* m) { 346 return os << *m; 347 } 348 349 std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) { 350 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature() 351 << " (source: " << m.GetDeclaringClassInfo().GetSourceFileName() << ":" 352 << m.GetFirstLine() << ")"; 353 } 354 355 static void doJvmtiMethodBind(jvmtiEnv* jvmtienv, 356 JNIEnv* env, 357 jthread thread, 358 jmethodID m, 359 void* address, 360 /*out*/void** out_address) { 361 *out_address = address; 362 ScopedThreadInfo thread_info(jvmtienv, env, thread); 363 ScopedMethodInfo method_info(jvmtienv, env, m); 364 if (!method_info.Init()) { 365 LOG(ERROR) << "Unable to get method info!"; 366 return; 367 } 368 LOG(INFO) << "Loading native method \"" << method_info << "\". Thread is " 369 << thread_info.GetName(); 370 } 371 372 static std::string GetName(jvmtiEnv* jvmtienv, JNIEnv* jnienv, jobject obj) { 373 jclass klass = jnienv->GetObjectClass(obj); 374 char *cname, *cgen; 375 if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) { 376 LOG(ERROR) << "Unable to get class name!"; 377 DeleteLocalRef(jnienv, klass); 378 return "<UNKNOWN>"; 379 } 380 std::string name(cname); 381 if (name == "Ljava/lang/String;") { 382 jstring str = reinterpret_cast<jstring>(obj); 383 const char* val = jnienv->GetStringUTFChars(str, nullptr); 384 if (val == nullptr) { 385 name += " (unable to get value)"; 386 } else { 387 std::ostringstream oss; 388 oss << name << " (value: \"" << val << "\")"; 389 name = oss.str(); 390 jnienv->ReleaseStringUTFChars(str, val); 391 } 392 } 393 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname)); 394 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen)); 395 DeleteLocalRef(jnienv, klass); 396 return name; 397 } 398 399 static std::string GetValOf(jvmtiEnv* env, JNIEnv* jnienv, std::string type, jvalue val) { 400 std::ostringstream oss; 401 switch (type[0]) { 402 case '[': 403 case 'L': 404 return val.l != nullptr ? GetName(env, jnienv, val.l) : "null"; 405 case 'Z': 406 return val.z == JNI_TRUE ? "true" : "false"; 407 case 'B': 408 oss << val.b; 409 return oss.str(); 410 case 'C': 411 oss << val.c; 412 return oss.str(); 413 case 'S': 414 oss << val.s; 415 return oss.str(); 416 case 'I': 417 oss << val.i; 418 return oss.str(); 419 case 'J': 420 oss << val.j; 421 return oss.str(); 422 case 'F': 423 oss << val.f; 424 return oss.str(); 425 case 'D': 426 oss << val.d; 427 return oss.str(); 428 case 'V': 429 return "<void>"; 430 default: 431 return "<ERROR Found type " + type + ">"; 432 } 433 } 434 435 void JNICALL FieldAccessHook(jvmtiEnv* jvmtienv, 436 JNIEnv* env, 437 jthread thread, 438 jmethodID m, 439 jlocation location, 440 jclass field_klass, 441 jobject object, 442 jfieldID field) { 443 ScopedThreadInfo info(jvmtienv, env, thread); 444 ScopedMethodInfo method_info(jvmtienv, env, m); 445 ScopedFieldInfo field_info(jvmtienv, field_klass, field); 446 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr; 447 ScopedClassInfo obj_class_info(jvmtienv, oklass); 448 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) { 449 LOG(ERROR) << "Unable to get callback info!"; 450 return; 451 } 452 LOG(INFO) << "ACCESS field \"" << field_info << "\" on object of " 453 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info 454 << "\" at location 0x" << std::hex << location << ". Thread is \"" 455 << info.GetName() << "\"."; 456 DeleteLocalRef(env, oklass); 457 } 458 459 static std::string PrintJValue(jvmtiEnv* jvmtienv, JNIEnv* env, char type, jvalue new_value) { 460 std::ostringstream oss; 461 switch (type) { 462 case 'L': { 463 jobject nv = new_value.l; 464 if (nv == nullptr) { 465 oss << "\"null\""; 466 } else { 467 jclass nv_klass = env->GetObjectClass(nv); 468 ScopedClassInfo nv_class_info(jvmtienv, nv_klass); 469 if (!nv_class_info.Init()) { 470 oss << "with unknown type"; 471 } else { 472 oss << "of type \"" << nv_class_info.GetName() << "\""; 473 } 474 DeleteLocalRef(env, nv_klass); 475 } 476 break; 477 } 478 case 'Z': { 479 if (new_value.z) { 480 oss << "true"; 481 } else { 482 oss << "false"; 483 } 484 break; 485 } 486 #define SEND_VALUE(chr, sym, type) \ 487 case chr: { \ 488 oss << static_cast<type>(new_value.sym); \ 489 break; \ 490 } 491 SEND_VALUE('B', b, int8_t); 492 SEND_VALUE('C', c, uint16_t); 493 SEND_VALUE('S', s, int16_t); 494 SEND_VALUE('I', i, int32_t); 495 SEND_VALUE('J', j, int64_t); 496 SEND_VALUE('F', f, float); 497 SEND_VALUE('D', d, double); 498 #undef SEND_VALUE 499 } 500 return oss.str(); 501 } 502 503 void JNICALL FieldModificationHook(jvmtiEnv* jvmtienv, 504 JNIEnv* env, 505 jthread thread, 506 jmethodID m, 507 jlocation location, 508 jclass field_klass, 509 jobject object, 510 jfieldID field, 511 char type, 512 jvalue new_value) { 513 ScopedThreadInfo info(jvmtienv, env, thread); 514 ScopedMethodInfo method_info(jvmtienv, env, m); 515 ScopedFieldInfo field_info(jvmtienv, field_klass, field); 516 jclass oklass = (object != nullptr) ? env->GetObjectClass(object) : nullptr; 517 ScopedClassInfo obj_class_info(jvmtienv, oklass); 518 if (!method_info.Init() || !field_info.Init() || !obj_class_info.Init()) { 519 LOG(ERROR) << "Unable to get callback info!"; 520 return; 521 } 522 LOG(INFO) << "MODIFY field \"" << field_info << "\" on object of " 523 << "type \"" << obj_class_info.GetName() << "\" in method \"" << method_info 524 << "\" at location 0x" << std::hex << location << std::dec << ". New value is " 525 << PrintJValue(jvmtienv, env, type, new_value) << ". Thread is \"" 526 << info.GetName() << "\"."; 527 DeleteLocalRef(env, oklass); 528 } 529 void JNICALL MethodExitHook(jvmtiEnv* jvmtienv, 530 JNIEnv* env, 531 jthread thread, 532 jmethodID m, 533 jboolean was_popped_by_exception, 534 jvalue val) { 535 ScopedThreadInfo info(jvmtienv, env, thread); 536 ScopedMethodInfo method_info(jvmtienv, env, m); 537 if (!method_info.Init()) { 538 LOG(ERROR) << "Unable to get method info!"; 539 return; 540 } 541 std::string type(method_info.GetSignature()); 542 type = type.substr(type.find(')') + 1); 543 std::string out_val(was_popped_by_exception ? "" : GetValOf(jvmtienv, env, type, val)); 544 LOG(INFO) << "Leaving method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"." 545 << std::endl 546 << " Cause: " << (was_popped_by_exception ? "exception" : "return ") 547 << out_val << "."; 548 } 549 550 void JNICALL MethodEntryHook(jvmtiEnv* jvmtienv, 551 JNIEnv* env, 552 jthread thread, 553 jmethodID m) { 554 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!"; 558 return; 559 } 560 LOG(INFO) << "Entering method \"" << method_info << "\". Thread is \"" << info.GetName() << "\""; 561 } 562 563 void JNICALL ClassPrepareHook(jvmtiEnv* jvmtienv, 564 JNIEnv* env, 565 jthread thread, 566 jclass klass) { 567 StressData* data = nullptr; 568 CHECK_EQ(jvmtienv->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)), 569 JVMTI_ERROR_NONE); 570 if (data->field_stress) { 571 jint nfields; 572 jfieldID* fields; 573 if (jvmtienv->GetClassFields(klass, &nfields, &fields) != JVMTI_ERROR_NONE) { 574 LOG(ERROR) << "Unable to get a classes fields!"; 575 return; 576 } 577 for (jint i = 0; i < nfields; i++) { 578 jfieldID f = fields[i]; 579 // Ignore errors 580 jvmtienv->SetFieldAccessWatch(klass, f); 581 jvmtienv->SetFieldModificationWatch(klass, f); 582 } 583 jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fields)); 584 } 585 if (data->trace_stress) { 586 ScopedThreadInfo info(jvmtienv, env, thread); 587 ScopedClassInfo class_info(jvmtienv, klass); 588 if (!class_info.Init()) { 589 LOG(ERROR) << "Unable to get class info!"; 590 return; 591 } 592 LOG(INFO) << "Prepared class \"" << class_info.GetName() << "\". Thread is \"" 593 << info.GetName() << "\""; 594 } 595 } 596 597 void JNICALL SingleStepHook(jvmtiEnv* jvmtienv, 598 JNIEnv* env, 599 jthread thread, 600 jmethodID method, 601 jlocation location) { 602 ScopedThreadInfo info(jvmtienv, env, thread); 603 ScopedMethodInfo method_info(jvmtienv, env, method); 604 if (!method_info.Init()) { 605 LOG(ERROR) << "Unable to get method info!"; 606 return; 607 } 608 LOG(INFO) << "Single step at location: 0x" << std::setw(8) << std::setfill('0') << std::hex 609 << location << " in method " << method_info << " thread: " << info.GetName(); 610 } 611 612 // The hook we are using. 613 void JNICALL ClassFileLoadHookSecretNoOp(jvmtiEnv* jvmti, 614 JNIEnv* jni_env ATTRIBUTE_UNUSED, 615 jclass class_being_redefined ATTRIBUTE_UNUSED, 616 jobject loader ATTRIBUTE_UNUSED, 617 const char* name, 618 jobject protection_domain ATTRIBUTE_UNUSED, 619 jint class_data_len, 620 const unsigned char* class_data, 621 jint* new_class_data_len, 622 unsigned char** new_class_data) { 623 std::vector<unsigned char> out; 624 // Make the jvmti semi-descriptor into the full descriptor. 625 std::string name_str("L"); 626 name_str += name; 627 name_str += ";"; 628 StressData* data = nullptr; 629 CHECK_EQ(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)), 630 JVMTI_ERROR_NONE); 631 if (!data->vm_class_loader_initialized) { 632 LOG(WARNING) << "Ignoring load of class " << name << " because VMClassLoader is not yet " 633 << "initialized. Transforming this class could cause spurious test failures."; 634 return; 635 } else if (DoExtractClassFromData(jvmti, name_str, class_data_len, class_data, 636 /*out*/ new_class_data_len, /*out*/ new_class_data)) { 637 LOG(INFO) << "Extracted class: " << name; 638 } else { 639 std::cerr << "Unable to extract class " << name << std::endl; 640 *new_class_data_len = 0; 641 *new_class_data = nullptr; 642 } 643 } 644 645 static std::string AdvanceOption(const std::string& ops) { 646 return ops.substr(ops.find(',') + 1); 647 } 648 649 static bool HasNextOption(const std::string& ops) { 650 return ops.find(',') != std::string::npos; 651 } 652 653 static std::string GetOption(const std::string& in) { 654 return in.substr(0, in.find(',')); 655 } 656 657 // Options are 658 // jvmti-stress,[redefine,][trace,][field] 659 static void ReadOptions(StressData* data, char* options) { 660 std::string ops(options); 661 CHECK_EQ(GetOption(ops), "jvmti-stress") << "Options should start with jvmti-stress"; 662 do { 663 ops = AdvanceOption(ops); 664 std::string cur = GetOption(ops); 665 if (cur == "trace") { 666 data->trace_stress = true; 667 } else if (cur == "step") { 668 data->step_stress = true; 669 } else if (cur == "field") { 670 data->field_stress = true; 671 } else if (cur == "redefine") { 672 data->redefine_stress = true; 673 } else { 674 LOG(FATAL) << "Unknown option: " << GetOption(ops); 675 } 676 } while (HasNextOption(ops)); 677 } 678 679 // Do final setup during the VMInit callback. By this time most things are all setup. 680 static void JNICALL PerformFinalSetupVMInit(jvmtiEnv *jvmti_env, 681 JNIEnv* jni_env, 682 jthread thread ATTRIBUTE_UNUSED) { 683 // Load the VMClassLoader class. We will get a ClassNotFound exception because we don't have 684 // visibility but the class will be loaded behind the scenes. 685 LOG(INFO) << "manual load & initialization of class java/lang/VMClassLoader!"; 686 jclass klass = jni_env->FindClass("java/lang/VMClassLoader"); 687 StressData* data = nullptr; 688 CHECK_EQ(jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)), 689 JVMTI_ERROR_NONE); 690 // We need to make sure that VMClassLoader is initialized before we start redefining anything 691 // since it can give (non-fatal) error messages if it's initialized after we've redefined BCP 692 // classes. These error messages are expected and no problem but they will mess up our testing 693 // infrastructure. 694 if (klass == nullptr) { 695 // Probably on RI. Clear the exception so we can continue but don't mark vmclassloader as 696 // initialized. 697 LOG(WARNING) << "Unable to find VMClassLoader class!"; 698 jni_env->ExceptionClear(); 699 } else { 700 // GetMethodID is spec'd to cause the class to be initialized. 701 jni_env->GetMethodID(klass, "hashCode", "()I"); 702 DeleteLocalRef(jni_env, klass); 703 data->vm_class_loader_initialized = true; 704 } 705 } 706 707 static bool WatchAllFields(JavaVM* vm, jvmtiEnv* jvmti) { 708 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, 709 JVMTI_EVENT_CLASS_PREPARE, 710 nullptr) != JVMTI_ERROR_NONE) { 711 LOG(ERROR) << "Couldn't set prepare event!"; 712 return false; 713 } 714 // TODO We really shouldn't need to do this step here. 715 jint nklass; 716 jclass* klasses; 717 if (jvmti->GetLoadedClasses(&nklass, &klasses) != JVMTI_ERROR_NONE) { 718 LOG(WARNING) << "Couldn't get loaded classes! Ignoring."; 719 return true; 720 } 721 JNIEnv* jni = nullptr; 722 if (vm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6)) { 723 LOG(ERROR) << "Unable to get jni env. Ignoring and potentially leaking jobjects."; 724 return false; 725 } 726 for (jint i = 0; i < nklass; i++) { 727 jclass k = klasses[i]; 728 ScopedClassInfo sci(jvmti, k); 729 if (sci.Init()) { 730 LOG(INFO) << "NOTE: class " << sci.GetName() << " already loaded."; 731 } 732 jint nfields; 733 jfieldID* fields; 734 jvmtiError err = jvmti->GetClassFields(k, &nfields, &fields); 735 if (err == JVMTI_ERROR_NONE) { 736 for (jint j = 0; j < nfields; j++) { 737 jfieldID f = fields[j]; 738 if (jvmti->SetFieldModificationWatch(k, f) != JVMTI_ERROR_NONE || 739 jvmti->SetFieldAccessWatch(k, f) != JVMTI_ERROR_NONE) { 740 LOG(ERROR) << "Unable to set watches on a field."; 741 return false; 742 } 743 } 744 } else if (err != JVMTI_ERROR_CLASS_NOT_PREPARED) { 745 LOG(ERROR) << "Unexpected error getting class fields!"; 746 return false; 747 } 748 jvmti->Deallocate(reinterpret_cast<unsigned char*>(fields)); 749 DeleteLocalRef(jni, k); 750 } 751 jvmti->Deallocate(reinterpret_cast<unsigned char*>(klasses)); 752 return true; 753 } 754 755 extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, 756 char* options, 757 void* reserved ATTRIBUTE_UNUSED) { 758 jvmtiEnv* jvmti = nullptr; 759 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0)) { 760 LOG(ERROR) << "Unable to get jvmti env."; 761 return 1; 762 } 763 StressData* data = nullptr; 764 if (JVMTI_ERROR_NONE != jvmti->Allocate(sizeof(StressData), 765 reinterpret_cast<unsigned char**>(&data))) { 766 LOG(ERROR) << "Unable to allocate data for stress test."; 767 return 1; 768 } 769 memset(data, 0, sizeof(StressData)); 770 // Read the options into the static variables that hold them. 771 ReadOptions(data, options); 772 // Save the data 773 if (JVMTI_ERROR_NONE != jvmti->SetEnvironmentLocalStorage(data)) { 774 LOG(ERROR) << "Unable to save stress test data."; 775 return 1; 776 } 777 778 // Just get all capabilities. 779 jvmtiCapabilities caps = { 780 .can_tag_objects = 0, 781 .can_generate_field_modification_events = 1, 782 .can_generate_field_access_events = 1, 783 .can_get_bytecodes = 0, 784 .can_get_synthetic_attribute = 0, 785 .can_get_owned_monitor_info = 0, 786 .can_get_current_contended_monitor = 0, 787 .can_get_monitor_info = 0, 788 .can_pop_frame = 0, 789 .can_redefine_classes = 1, 790 .can_signal_thread = 0, 791 .can_get_source_file_name = 1, 792 .can_get_line_numbers = 1, 793 .can_get_source_debug_extension = 1, 794 .can_access_local_variables = 0, 795 .can_maintain_original_method_order = 0, 796 .can_generate_single_step_events = 1, 797 .can_generate_exception_events = 0, 798 .can_generate_frame_pop_events = 0, 799 .can_generate_breakpoint_events = 0, 800 .can_suspend = 0, 801 .can_redefine_any_class = 0, 802 .can_get_current_thread_cpu_time = 0, 803 .can_get_thread_cpu_time = 0, 804 .can_generate_method_entry_events = 1, 805 .can_generate_method_exit_events = 1, 806 .can_generate_all_class_hook_events = 0, 807 .can_generate_compiled_method_load_events = 0, 808 .can_generate_monitor_events = 0, 809 .can_generate_vm_object_alloc_events = 0, 810 .can_generate_native_method_bind_events = 1, 811 .can_generate_garbage_collection_events = 0, 812 .can_generate_object_free_events = 0, 813 .can_force_early_return = 0, 814 .can_get_owned_monitor_stack_depth_info = 0, 815 .can_get_constant_pool = 0, 816 .can_set_native_method_prefix = 0, 817 .can_retransform_classes = 1, 818 .can_retransform_any_class = 0, 819 .can_generate_resource_exhaustion_heap_events = 0, 820 .can_generate_resource_exhaustion_threads_events = 0, 821 }; 822 jvmti->AddCapabilities(&caps); 823 824 // Set callbacks. 825 jvmtiEventCallbacks cb; 826 memset(&cb, 0, sizeof(cb)); 827 cb.ClassFileLoadHook = ClassFileLoadHookSecretNoOp; 828 cb.NativeMethodBind = doJvmtiMethodBind; 829 cb.VMInit = PerformFinalSetupVMInit; 830 cb.MethodEntry = MethodEntryHook; 831 cb.MethodExit = MethodExitHook; 832 cb.FieldAccess = FieldAccessHook; 833 cb.FieldModification = FieldModificationHook; 834 cb.ClassPrepare = ClassPrepareHook; 835 cb.SingleStep = SingleStepHook; 836 if (jvmti->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) { 837 LOG(ERROR) << "Unable to set class file load hook cb!"; 838 return 1; 839 } 840 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, 841 JVMTI_EVENT_VM_INIT, 842 nullptr) != JVMTI_ERROR_NONE) { 843 LOG(ERROR) << "Unable to enable JVMTI_EVENT_VM_INIT event!"; 844 return 1; 845 } 846 if (data->redefine_stress) { 847 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, 848 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, 849 nullptr) != JVMTI_ERROR_NONE) { 850 LOG(ERROR) << "Unable to enable CLASS_FILE_LOAD_HOOK event!"; 851 return 1; 852 } 853 } 854 if (data->trace_stress) { 855 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, 856 JVMTI_EVENT_CLASS_PREPARE, 857 nullptr) != JVMTI_ERROR_NONE) { 858 LOG(ERROR) << "Unable to enable CLASS_PREPARE event!"; 859 return 1; 860 } 861 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, 862 JVMTI_EVENT_NATIVE_METHOD_BIND, 863 nullptr) != JVMTI_ERROR_NONE) { 864 LOG(ERROR) << "Unable to enable JVMTI_EVENT_NATIVE_METHOD_BIND event!"; 865 return 1; 866 } 867 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, 868 JVMTI_EVENT_METHOD_ENTRY, 869 nullptr) != JVMTI_ERROR_NONE) { 870 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_ENTRY event!"; 871 return 1; 872 } 873 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, 874 JVMTI_EVENT_METHOD_EXIT, 875 nullptr) != JVMTI_ERROR_NONE) { 876 LOG(ERROR) << "Unable to enable JVMTI_EVENT_METHOD_EXIT event!"; 877 return 1; 878 } 879 } 880 if (data->field_stress) { 881 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, 882 JVMTI_EVENT_FIELD_MODIFICATION, 883 nullptr) != JVMTI_ERROR_NONE) { 884 LOG(ERROR) << "Unable to enable FIELD_MODIFICATION event!"; 885 return 1; 886 } 887 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, 888 JVMTI_EVENT_FIELD_ACCESS, 889 nullptr) != JVMTI_ERROR_NONE) { 890 LOG(ERROR) << "Unable to enable FIELD_ACCESS event!"; 891 return 1; 892 } 893 if (!WatchAllFields(vm, jvmti)) { 894 return 1; 895 } 896 } 897 if (data->step_stress) { 898 if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, 899 JVMTI_EVENT_SINGLE_STEP, 900 nullptr) != JVMTI_ERROR_NONE) { 901 return 1; 902 } 903 } 904 return 0; 905 } 906 907 extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) { 908 return Agent_OnLoad(vm, options, reserved); 909 } 910 911 } // namespace art 912