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