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