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