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 <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