1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 
16 #include <android-base/logging.h>
17 
18 #include <atomic>
19 #include <iostream>
20 #include <istream>
21 #include <iomanip>
22 #include <jni.h>
23 #include <jvmti.h>
24 #include <limits>
25 #include <memory>
26 #include <string>
27 #include <sstream>
28 #include <vector>
29 
30 namespace tifast {
31 
32 #define EVENT(x) JVMTI_EVENT_ ## x
33 
34 namespace {
35 
36 // Special art ti-version number. We will use this as a fallback if we cannot get a regular JVMTI
37 // env.
38 static constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000;
39 
Unused(Args...args ATTRIBUTE_UNUSED)40 template <typename ...Args> static void Unused(Args... args ATTRIBUTE_UNUSED) {}
41 
42 // jthread is a typedef of jobject so we use this to allow the templates to distinguish them.
43 struct jthreadContainer { jthread thread; };
44 // jlocation is a typedef of jlong so use this to distinguish the less common jlong.
45 struct jlongContainer { jlong val; };
46 
AddCapsForEvent(jvmtiEvent event,jvmtiCapabilities * caps)47 static void AddCapsForEvent(jvmtiEvent event, jvmtiCapabilities* caps) {
48   switch (event) {
49 #define DO_CASE(name, cap_name) \
50     case EVENT(name):           \
51       caps->cap_name = 1;       \
52       break
53     DO_CASE(SINGLE_STEP, can_generate_single_step_events);
54     DO_CASE(METHOD_ENTRY, can_generate_method_entry_events);
55     DO_CASE(METHOD_EXIT, can_generate_method_exit_events);
56     DO_CASE(NATIVE_METHOD_BIND, can_generate_native_method_bind_events);
57     DO_CASE(EXCEPTION, can_generate_exception_events);
58     DO_CASE(EXCEPTION_CATCH, can_generate_exception_events);
59     DO_CASE(COMPILED_METHOD_LOAD, can_generate_compiled_method_load_events);
60     DO_CASE(COMPILED_METHOD_UNLOAD, can_generate_compiled_method_load_events);
61     DO_CASE(MONITOR_CONTENDED_ENTER, can_generate_monitor_events);
62     DO_CASE(MONITOR_CONTENDED_ENTERED, can_generate_monitor_events);
63     DO_CASE(MONITOR_WAIT, can_generate_monitor_events);
64     DO_CASE(MONITOR_WAITED, can_generate_monitor_events);
65     DO_CASE(VM_OBJECT_ALLOC, can_generate_vm_object_alloc_events);
66     DO_CASE(GARBAGE_COLLECTION_START, can_generate_garbage_collection_events);
67     DO_CASE(GARBAGE_COLLECTION_FINISH, can_generate_garbage_collection_events);
68 #undef DO_CASE
69     default: break;
70   }
71 }
72 
73 // Setup for all supported events. Give a macro with fun(name, event_num, args)
74 #define FOR_ALL_SUPPORTED_JNI_EVENTS(fun) \
75     fun(SingleStep, EVENT(SINGLE_STEP), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, jlocation loc), (jvmti, jni, jthreadContainer{.thread = thread}, meth, loc)) \
76     fun(MethodEntry, EVENT(METHOD_ENTRY), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth), (jvmti, jni, jthreadContainer{.thread = thread}, meth)) \
77     fun(MethodExit, EVENT(METHOD_EXIT), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, jboolean jb, jvalue jv), (jvmti, jni, jthreadContainer{.thread = thread}, meth, jb, jv)) \
78     fun(NativeMethodBind, EVENT(NATIVE_METHOD_BIND), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, void* v1, void** v2), (jvmti, jni, jthreadContainer{.thread = thread}, meth, v1, v2)) \
79     fun(Exception, EVENT(EXCEPTION), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth1, jlocation loc1, jobject obj, jmethodID meth2, jlocation loc2), (jvmti, jni, jthreadContainer{.thread = thread}, meth1, loc1, obj, meth2, loc2)) \
80     fun(ExceptionCatch, EVENT(EXCEPTION_CATCH), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, jlocation loc, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, meth, loc, obj)) \
81     fun(ThreadStart, EVENT(THREAD_START), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread), (jvmti, jni, jthreadContainer{.thread = thread})) \
82     fun(ThreadEnd, EVENT(THREAD_END), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread), (jvmti, jni, jthreadContainer{.thread = thread})) \
83     fun(ClassLoad, EVENT(CLASS_LOAD), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass), (jvmti, jni, jthreadContainer{.thread = thread}, klass) ) \
84     fun(ClassPrepare, EVENT(CLASS_PREPARE), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass), (jvmti, jni, jthreadContainer{.thread = thread}, klass)) \
85     fun(ClassFileLoadHook, EVENT(CLASS_FILE_LOAD_HOOK), (jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, jobject obj1, const char* c1, jobject obj2, jint i1, const unsigned char* c2, jint* ip1, unsigned char** cp1), (jvmti, jni, klass, obj1, c1, obj2, i1, c2, ip1, cp1)) \
86     fun(MonitorContendedEnter, EVENT(MONITOR_CONTENDED_ENTER), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, obj)) \
87     fun(MonitorContendedEntered, EVENT(MONITOR_CONTENDED_ENTERED), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, obj)) \
88     fun(MonitorWait, EVENT(MONITOR_WAIT), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj, jlong l1), (jvmti, jni, jthreadContainer{.thread = thread}, obj, jlongContainer{.val = l1})) \
89     fun(MonitorWaited, EVENT(MONITOR_WAITED), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj, jboolean b1), (jvmti, jni, jthreadContainer{.thread = thread}, obj, b1)) \
90     fun(ResourceExhausted, EVENT(RESOURCE_EXHAUSTED), (jvmtiEnv* jvmti, JNIEnv* jni, jint i1, const void* cv, const char* cc), (jvmti, jni, i1, cv, cc)) \
91     fun(VMObjectAlloc, EVENT(VM_OBJECT_ALLOC), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj, jclass klass, jlong l1), (jvmti, jni, jthreadContainer{.thread = thread}, obj, klass, jlongContainer{.val = l1})) \
92     fun(VMInit, EVENT(VM_INIT), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread), (jvmti, jni, jthreadContainer{.thread = thread})) \
93     fun(VMStart, EVENT(VM_START), (jvmtiEnv* jvmti, JNIEnv* jni), (jvmti, jni)) \
94     fun(VMDeath, EVENT(VM_DEATH), (jvmtiEnv* jvmti, JNIEnv* jni), (jvmti, jni)) \
95 
96 #define FOR_ALL_SUPPORTED_NO_JNI_EVENTS(fun) \
97     fun(CompiledMethodLoad, EVENT(COMPILED_METHOD_LOAD), (jvmtiEnv* jvmti, jmethodID meth, jint i1, const void* cv1, jint i2, const jvmtiAddrLocationMap* alm, const void* cv2), (jvmti, meth, i1, cv1, i2, alm, cv2)) \
98     fun(CompiledMethodUnload, EVENT(COMPILED_METHOD_UNLOAD), (jvmtiEnv* jvmti, jmethodID meth, const void* cv1), (jvmti, meth, cv1)) \
99     fun(DynamicCodeGenerated, EVENT(DYNAMIC_CODE_GENERATED), (jvmtiEnv* jvmti, const char* cc, const void* cv, jint i1), (jvmti, cc, cv, i1)) \
100     fun(DataDumpRequest, EVENT(DATA_DUMP_REQUEST), (jvmtiEnv* jvmti), (jvmti)) \
101     fun(GarbageCollectionStart, EVENT(GARBAGE_COLLECTION_START), (jvmtiEnv* jvmti), (jvmti)) \
102     fun(GarbageCollectionFinish, EVENT(GARBAGE_COLLECTION_FINISH), (jvmtiEnv* jvmti), (jvmti))
103 
104 #define FOR_ALL_SUPPORTED_EVENTS(fun) \
105     FOR_ALL_SUPPORTED_JNI_EVENTS(fun) \
106     FOR_ALL_SUPPORTED_NO_JNI_EVENTS(fun)
107 
108 static const jvmtiEvent kAllEvents[] = {
109 #define GET_EVENT(a, event, b, c) event,
110 FOR_ALL_SUPPORTED_EVENTS(GET_EVENT)
111 #undef GET_EVENT
112 };
113 
114 #define GENERATE_EMPTY_FUNCTION(name, number, args, argnames) \
115     static void JNICALL empty ## name  args { Unused argnames ; }
FOR_ALL_SUPPORTED_EVENTS(GENERATE_EMPTY_FUNCTION)116 FOR_ALL_SUPPORTED_EVENTS(GENERATE_EMPTY_FUNCTION)
117 #undef GENERATE_EMPTY_FUNCTION
118 
119 static jvmtiEventCallbacks kEmptyCallbacks {
120 #define CREATE_EMPTY_EVENT_CALLBACKS(name, num, args, argnames) \
121     .name = empty ## name,
122   FOR_ALL_SUPPORTED_EVENTS(CREATE_EMPTY_EVENT_CALLBACKS)
123 #undef CREATE_EMPTY_EVENT_CALLBACKS
124 };
125 
DeleteLocalRef(JNIEnv * env,jobject obj)126 static void DeleteLocalRef(JNIEnv* env, jobject obj) {
127   if (obj != nullptr && env != nullptr) {
128     env->DeleteLocalRef(obj);
129   }
130 }
131 
132 class ScopedThreadInfo {
133  public:
ScopedThreadInfo(jvmtiEnv * jvmtienv,JNIEnv * env,jthread thread)134   ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread)
135       : jvmtienv_(jvmtienv), env_(env), free_name_(false) {
136     if (thread == nullptr) {
137       info_.name = const_cast<char*>("<NULLPTR>");
138     } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) {
139       info_.name = const_cast<char*>("<UNKNOWN THREAD>");
140     } else {
141       free_name_ = true;
142     }
143   }
144 
~ScopedThreadInfo()145   ~ScopedThreadInfo() {
146     if (free_name_) {
147       jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name));
148     }
149     DeleteLocalRef(env_, info_.thread_group);
150     DeleteLocalRef(env_, info_.context_class_loader);
151   }
152 
GetName() const153   const char* GetName() const {
154     return info_.name;
155   }
156 
157  private:
158   jvmtiEnv* jvmtienv_;
159   JNIEnv* env_;
160   bool free_name_;
161   jvmtiThreadInfo info_{};
162 };
163 
164 class ScopedClassInfo {
165  public:
ScopedClassInfo(jvmtiEnv * jvmtienv,jclass c)166   ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c) : jvmtienv_(jvmtienv), class_(c) {}
167 
~ScopedClassInfo()168   ~ScopedClassInfo() {
169     if (class_ != nullptr) {
170       jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
171       jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
172       jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(file_));
173       jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(debug_ext_));
174     }
175   }
176 
Init(bool get_generic=true)177   bool Init(bool get_generic = true) {
178     if (class_ == nullptr) {
179       name_ = const_cast<char*>("<NONE>");
180       generic_ = const_cast<char*>("<NONE>");
181       return true;
182     } else {
183       jvmtiError ret1 = jvmtienv_->GetSourceFileName(class_, &file_);
184       jvmtiError ret2 = jvmtienv_->GetSourceDebugExtension(class_, &debug_ext_);
185       char** gen_ptr = &generic_;
186       if (!get_generic) {
187         generic_ = nullptr;
188         gen_ptr = nullptr;
189       }
190       return jvmtienv_->GetClassSignature(class_, &name_, gen_ptr) == JVMTI_ERROR_NONE &&
191           ret1 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
192           ret1 != JVMTI_ERROR_INVALID_CLASS &&
193           ret2 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
194           ret2 != JVMTI_ERROR_INVALID_CLASS;
195     }
196   }
197 
GetClass() const198   jclass GetClass() const {
199     return class_;
200   }
201 
GetName() const202   const char* GetName() const {
203     return name_;
204   }
205 
GetGeneric() const206   const char* GetGeneric() const {
207     return generic_;
208   }
209 
GetSourceDebugExtension() const210   const char* GetSourceDebugExtension() const {
211     if (debug_ext_ == nullptr) {
212       return "<UNKNOWN_SOURCE_DEBUG_EXTENSION>";
213     } else {
214       return debug_ext_;
215     }
216   }
GetSourceFileName() const217   const char* GetSourceFileName() const {
218     if (file_ == nullptr) {
219       return "<UNKNOWN_FILE>";
220     } else {
221       return file_;
222     }
223   }
224 
225  private:
226   jvmtiEnv* jvmtienv_;
227   jclass class_;
228   char* name_ = nullptr;
229   char* generic_ = nullptr;
230   char* file_ = nullptr;
231   char* debug_ext_ = nullptr;
232 
233   friend std::ostream& operator<<(std::ostream &os, ScopedClassInfo const& m);
234 };
235 
236 class ScopedMethodInfo {
237  public:
ScopedMethodInfo(jvmtiEnv * jvmtienv,JNIEnv * env,jmethodID m)238   ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m)
239       : jvmtienv_(jvmtienv), env_(env), method_(m) {}
240 
~ScopedMethodInfo()241   ~ScopedMethodInfo() {
242     DeleteLocalRef(env_, declaring_class_);
243     jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
244     jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
245     jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
246   }
247 
Init(bool get_generic=true)248   bool Init(bool get_generic = true) {
249     if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
250       return false;
251     }
252     class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
253     jint nlines;
254     jvmtiLineNumberEntry* lines;
255     jvmtiError err = jvmtienv_->GetLineNumberTable(method_, &nlines, &lines);
256     if (err == JVMTI_ERROR_NONE) {
257       if (nlines > 0) {
258         first_line_ = lines[0].line_number;
259       }
260       jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(lines));
261     } else if (err != JVMTI_ERROR_ABSENT_INFORMATION &&
262                err != JVMTI_ERROR_NATIVE_METHOD) {
263       return false;
264     }
265     return class_info_->Init(get_generic) &&
266         (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
267   }
268 
GetDeclaringClassInfo() const269   const ScopedClassInfo& GetDeclaringClassInfo() const {
270     return *class_info_;
271   }
272 
GetDeclaringClass() const273   jclass GetDeclaringClass() const {
274     return declaring_class_;
275   }
276 
GetName() const277   const char* GetName() const {
278     return name_;
279   }
280 
GetSignature() const281   const char* GetSignature() const {
282     return signature_;
283   }
284 
GetGeneric() const285   const char* GetGeneric() const {
286     return generic_;
287   }
288 
GetFirstLine() const289   jint GetFirstLine() const {
290     return first_line_;
291   }
292 
293  private:
294   jvmtiEnv* jvmtienv_;
295   JNIEnv* env_;
296   jmethodID method_;
297   jclass declaring_class_ = nullptr;
298   std::unique_ptr<ScopedClassInfo> class_info_;
299   char* name_ = nullptr;
300   char* signature_ = nullptr;
301   char* generic_ = nullptr;
302   jint first_line_ = -1;
303 
304   friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
305 };
306 
operator <<(std::ostream & os,ScopedClassInfo const & c)307 std::ostream& operator<<(std::ostream &os, ScopedClassInfo const& c) {
308   const char* generic = c.GetGeneric();
309   if (generic != nullptr) {
310     return os << c.GetName() << "<" << generic << ">" << " file: " << c.GetSourceFileName();
311   } else {
312     return os << c.GetName() << " file: " << c.GetSourceFileName();
313   }
314 }
315 
operator <<(std::ostream & os,ScopedMethodInfo const & m)316 std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
317   return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature()
318             << " (source: " << m.GetDeclaringClassInfo().GetSourceFileName() << ":"
319             << m.GetFirstLine() << ")";
320 }
321 
322 
323 class LogPrinter {
324  public:
LogPrinter(jvmtiEvent event)325   explicit LogPrinter(jvmtiEvent event) : event_(event) {}
326 
PrintRestNoJNI(jvmtiEnv * jvmti,Args...args)327   template <typename ...Args> void PrintRestNoJNI(jvmtiEnv* jvmti, Args... args) {
328     PrintRest(jvmti, static_cast<JNIEnv*>(nullptr), args...);
329   }
330 
331   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, JNIEnv* env, Args... args);
332   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
333                                              JNIEnv* env,
334                                              jlongContainer l,
335                                              Args... args);
336   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
337                                              JNIEnv* env,
338                                              jthreadContainer thr,
339                                              Args... args);
340   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
341                                              JNIEnv* env,
342                                              jboolean i,
343                                              Args... args);
344   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
345                                              JNIEnv* env,
346                                              jint i,
347                                              Args... args);
348   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
349                                              JNIEnv* env,
350                                              jclass klass,
351                                              Args... args);
352   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
353                                              JNIEnv* env,
354                                              jmethodID meth,
355                                              Args... args);
356   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
357                                              JNIEnv* env,
358                                              jlocation loc,
359                                              Args... args);
360   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
361                                              JNIEnv* env,
362                                              jint* ip,
363                                              Args... args);
364   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
365                                              JNIEnv* env,
366                                              const void* loc,
367                                              Args... args);
368   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
369                                              JNIEnv* env,
370                                              void* loc,
371                                              Args... args);
372   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
373                                              JNIEnv* env,
374                                              void** loc,
375                                              Args... args);
376   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
377                                              JNIEnv* env,
378                                              unsigned char** v,
379                                              Args... args);
380   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
381                                              JNIEnv* env,
382                                              const unsigned char* v,
383                                              Args... args);
384   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
385                                              JNIEnv* env,
386                                              const char* v,
387                                              Args... args);
388   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
389                                              JNIEnv* env,
390                                              const jvmtiAddrLocationMap* v,
391                                              Args... args);
392   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
393                                              JNIEnv* env,
394                                              jvalue v,
395                                              Args... args);
396   template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
397                                              JNIEnv* env,
398                                              jobject v,
399                                              Args... args);
400 
GetResult()401   std::string GetResult() {
402     std::string out_str = stream.str();
403     return start_args + out_str;
404   }
405 
406  private:
407   jvmtiEvent event_;
408   std::string start_args;
409   std::ostringstream stream;
410 };
411 
412 // Base case
PrintRest(jvmtiEnv * jvmti ATTRIBUTE_UNUSED,JNIEnv * jni)413 template<> void LogPrinter::PrintRest(jvmtiEnv* jvmti ATTRIBUTE_UNUSED, JNIEnv* jni) {
414   if (jni == nullptr) {
415     start_args = "jvmtiEnv*";
416   } else {
417     start_args = "jvmtiEnv*, JNIEnv*";
418   }
419 }
420 
421 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,const jvmtiAddrLocationMap * v,Args...args)422 void LogPrinter::PrintRest(jvmtiEnv* jvmti,
423                            JNIEnv* jni,
424                            const jvmtiAddrLocationMap* v,
425                            Args... args) {
426   if (v != nullptr) {
427     stream << ", const jvmtiAddrLocationMap*[start_address: "
428            << v->start_address << ", location: " << v->location << "]";
429   } else {
430     stream << ", const jvmtiAddrLocationMap*[nullptr]";
431   }
432   PrintRest(jvmti, jni, args...);
433 }
434 
435 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jint * v,Args...args)436 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jint* v, Args... args) {
437   stream << ", jint*[" << static_cast<const void*>(v) << "]";
438   PrintRest(jvmti, jni, args...);
439 }
440 
441 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,const void * v,Args...args)442 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const void* v, Args... args) {
443   stream << ", const void*[" << v << "]";
444   PrintRest(jvmti, jni, args...);
445 }
446 
447 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,unsigned char ** v,Args...args)448 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, unsigned char** v, Args... args) {
449   stream << ", unsigned char**[" << static_cast<const void*>(v) << "]";
450   PrintRest(jvmti, jni, args...);
451 }
452 
453 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,const unsigned char * v,Args...args)454 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const unsigned char* v, Args... args) {
455   stream << ", const unsigned char*[" << static_cast<const void*>(v) << "]";
456   PrintRest(jvmti, jni, args...);
457 }
458 
459 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,const char * v,Args...args)460 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const char* v, Args... args) {
461   stream << ", const char*[" << v << "]";
462   PrintRest(jvmti, jni, args...);
463 }
464 
465 template<typename... Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jvalue v,Args...args)466 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jvalue v, Args... args) {
467   std::ostringstream hex;
468   hex << std::hex << v.j;
469   std::ostringstream char_val;
470   if (std::isprint(v.c) && v.c < std::numeric_limits<unsigned char>::max()) {
471     char_val << "'" << static_cast<unsigned char>(v.c) << "'";
472   } else {
473     char_val << "0x" << std::hex << reinterpret_cast<uint16_t>(v.c);
474   }
475   stream << ", jvalue[{<hex: 0x" << hex.str() << ">"
476          << ", .z=" << (v.z ? "true" : "false")
477          << ", .b=" << static_cast<int32_t>(v.b)
478          << ", .c=" << char_val.str()
479          << ", .s=" << static_cast<int32_t>(v.s)
480          << ", .i=" << v.i
481          << ", .j=" << v.j
482          << ", .f=" << v.f
483          << ", .d=" << v.d
484          << ", .l=" << v.l << "}]";
485   PrintRest(jvmti, jni, args...);
486 }
487 
488 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,void ** v,Args...args)489 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, void** v, Args... args) {
490   stream << ", void**[" << v << "]";
491   PrintRest(jvmti, jni, args...);
492 }
493 
494 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,void * v,Args...args)495 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, void* v, Args... args) {
496   stream << ", void*[" << v << "]";
497   PrintRest(jvmti, jni, args...);
498 }
499 
500 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jlongContainer l,Args...args)501 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jlongContainer l, Args... args) {
502   stream << ", jlong[" << l.val << ", hex: 0x" << std::hex << l.val << "]";
503   PrintRest(jvmti, jni, args...);
504 }
505 
506 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jlocation l,Args...args)507 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jlocation l, Args... args) {
508   stream << ", jlocation[" << l << ", hex: 0x" << std::hex << l << "]";
509   PrintRest(jvmti, jni, args...);
510 }
511 
512 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jboolean b,Args...args)513 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jboolean b, Args... args) {
514   stream << ", jboolean[" << (b ? "true" : "false") << "]";
515   PrintRest(jvmti, jni, args...);
516 }
517 
518 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jint i,Args...args)519 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jint i, Args... args) {
520   stream << ", jint[" << i << ", hex: 0x" << std::hex << i << "]";
521   PrintRest(jvmti, jni, args...);
522 }
523 
524 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jobject obj,Args...args)525 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jobject obj, Args... args) {
526   if (obj == nullptr) {
527     stream << ", jobject[nullptr]";
528   } else {
529     jni->PushLocalFrame(1);
530     jclass klass = jni->GetObjectClass(obj);
531     ScopedClassInfo sci(jvmti, klass);
532     if (sci.Init(event_ != JVMTI_EVENT_VM_OBJECT_ALLOC)) {
533       stream << ", jobject[type: " << sci << "]";
534     } else {
535       stream << ", jobject[type: TYPE UNKNOWN]";
536     }
537     jni->PopLocalFrame(nullptr);
538   }
539   PrintRest(jvmti, jni, args...);
540 }
541 
542 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jthreadContainer thr,Args...args)543 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jthreadContainer thr, Args... args) {
544   ScopedThreadInfo sti(jvmti, jni, thr.thread);
545   stream << ", jthread[" << sti.GetName() << "]";
546   PrintRest(jvmti, jni, args...);
547 }
548 
549 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jclass klass,Args...args)550 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, Args... args) {
551   ScopedClassInfo sci(jvmti, klass);
552   if (sci.Init(/*get_generic=*/event_ != JVMTI_EVENT_VM_OBJECT_ALLOC)) {
553     stream << ", jclass[" << sci << "]";
554   } else {
555     stream << ", jclass[TYPE UNKNOWN]";
556   }
557   PrintRest(jvmti, jni, args...);
558 }
559 
560 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jmethodID meth,Args...args)561 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jmethodID meth, Args... args) {
562   ScopedMethodInfo smi(jvmti, jni, meth);
563   if (smi.Init()) {
564     stream << ", jmethodID[" << smi << "]";
565   } else {
566     stream << ", jmethodID[METHOD UNKNOWN]";
567   }
568   PrintRest(jvmti, jni, args...);
569 }
570 
571 #define GENERATE_LOG_FUNCTION_JNI(name, event, args, argnames) \
572     static void JNICALL log ## name  args { \
573       LogPrinter printer(event); \
574       printer.PrintRest argnames; \
575       LOG(INFO) << "Got event " << #name << "(" << printer.GetResult() << ")"; \
576     } \
577 
578 #define GENERATE_LOG_FUNCTION_NO_JNI(name, event, args, argnames) \
579     static void JNICALL log ## name  args { \
580       LogPrinter printer(event); \
581       printer.PrintRestNoJNI argnames; \
582       LOG(INFO) << "Got event " << #name << "(" << printer.GetResult() << ")"; \
583     } \
584 
585 FOR_ALL_SUPPORTED_JNI_EVENTS(GENERATE_LOG_FUNCTION_JNI)
FOR_ALL_SUPPORTED_NO_JNI_EVENTS(GENERATE_LOG_FUNCTION_NO_JNI)586 FOR_ALL_SUPPORTED_NO_JNI_EVENTS(GENERATE_LOG_FUNCTION_NO_JNI)
587 #undef GENERATE_LOG_FUNCTION
588 
589 static jvmtiEventCallbacks kLogCallbacks {
590 #define CREATE_LOG_EVENT_CALLBACK(name, num, args, argnames) \
591     .name = log ## name,
592   FOR_ALL_SUPPORTED_EVENTS(CREATE_LOG_EVENT_CALLBACK)
593 #undef CREATE_LOG_EVENT_CALLBACK
594 };
595 
EventToName(jvmtiEvent desired_event)596 static std::string EventToName(jvmtiEvent desired_event) {
597 #define CHECK_NAME(name, event, args, argnames) \
598   if (desired_event == (event)) { \
599     return #name; \
600   }
601   FOR_ALL_SUPPORTED_EVENTS(CHECK_NAME);
602   LOG(FATAL) << "Unknown event " << desired_event;
603   __builtin_unreachable();
604 #undef CHECK_NAME
605 }
NameToEvent(const std::string & desired_name)606 static jvmtiEvent NameToEvent(const std::string& desired_name) {
607 #define CHECK_NAME(name, event, args, argnames) \
608   if (desired_name == #name) { \
609     return event; \
610   }
611   FOR_ALL_SUPPORTED_EVENTS(CHECK_NAME);
612   LOG(FATAL) << "Unknown event " << desired_name;
613   __builtin_unreachable();
614 #undef CHECK_NAME
615 }
616 
617 #undef FOR_ALL_SUPPORTED_JNI_EVENTS
618 #undef FOR_ALL_SUPPORTED_NO_JNI_EVENTS
619 #undef FOR_ALL_SUPPORTED_EVENTS
620 
GetAllAvailableEvents(jvmtiEnv * jvmti)621 static std::vector<jvmtiEvent> GetAllAvailableEvents(jvmtiEnv* jvmti) {
622   std::vector<jvmtiEvent> out;
623   jvmtiCapabilities caps{};
624   jvmti->GetPotentialCapabilities(&caps);
625   uint8_t caps_bytes[sizeof(caps)];
626   memcpy(caps_bytes, &caps, sizeof(caps));
627   for (jvmtiEvent e : kAllEvents) {
628     jvmtiCapabilities req{};
629     AddCapsForEvent(e, &req);
630     uint8_t req_bytes[sizeof(req)];
631     memcpy(req_bytes, &req, sizeof(req));
632     bool good = true;
633     for (size_t i = 0; i < sizeof(caps); i++) {
634       if ((req_bytes[i] & caps_bytes[i]) != req_bytes[i]) {
635         good = false;
636         break;
637       }
638     }
639     if (good) {
640       out.push_back(e);
641     } else {
642       LOG(WARNING) << "Unable to get capabilities for event " << EventToName(e);
643     }
644   }
645   return out;
646 }
647 
GetRequestedEventList(jvmtiEnv * jvmti,const std::string & args)648 static std::vector<jvmtiEvent> GetRequestedEventList(jvmtiEnv* jvmti, const std::string& args) {
649   std::vector<jvmtiEvent> res;
650   std::stringstream args_stream(args);
651   std::string item;
652   while (std::getline(args_stream, item, ',')) {
653     if (item == "") {
654       continue;
655     } else if (item == "all") {
656       return GetAllAvailableEvents(jvmti);
657     }
658     res.push_back(NameToEvent(item));
659   }
660   return res;
661 }
662 
SetupJvmtiEnv(JavaVM * vm,jvmtiEnv ** jvmti)663 static jint SetupJvmtiEnv(JavaVM* vm, jvmtiEnv** jvmti) {
664   jint res = 0;
665   res = vm->GetEnv(reinterpret_cast<void**>(jvmti), JVMTI_VERSION_1_1);
666 
667   if (res != JNI_OK || *jvmti == nullptr) {
668     LOG(ERROR) << "Unable to access JVMTI, error code " << res;
669     return vm->GetEnv(reinterpret_cast<void**>(jvmti), kArtTiVersion);
670   }
671   return res;
672 }
673 
674 }  // namespace
675 
AgentStart(JavaVM * vm,char * options,void * reserved ATTRIBUTE_UNUSED)676 static jint AgentStart(JavaVM* vm,
677                        char* options,
678                        void* reserved ATTRIBUTE_UNUSED) {
679   jvmtiEnv* jvmti = nullptr;
680   jvmtiError error = JVMTI_ERROR_NONE;
681   if (SetupJvmtiEnv(vm, &jvmti) != JNI_OK) {
682     LOG(ERROR) << "Could not get JVMTI env or ArtTiEnv!";
683     return JNI_ERR;
684   }
685   std::string args(options);
686   bool is_log = false;
687   if (args.compare(0, 3, "log") == 0) {
688     is_log = true;
689     args = args.substr(3);
690   }
691 
692   std::vector<jvmtiEvent> events = GetRequestedEventList(jvmti, args);
693 
694   jvmtiCapabilities caps{};
695   for (jvmtiEvent e : events) {
696     AddCapsForEvent(e, &caps);
697   }
698   if (is_log) {
699     caps.can_get_line_numbers = 1;
700     caps.can_get_source_file_name = 1;
701     caps.can_get_source_debug_extension = 1;
702   }
703   error = jvmti->AddCapabilities(&caps);
704   if (error != JVMTI_ERROR_NONE) {
705     LOG(ERROR) << "Unable to set caps";
706     return JNI_ERR;
707   }
708 
709   if (is_log) {
710     error = jvmti->SetEventCallbacks(&kLogCallbacks, static_cast<jint>(sizeof(kLogCallbacks)));
711   } else {
712     error = jvmti->SetEventCallbacks(&kEmptyCallbacks, static_cast<jint>(sizeof(kEmptyCallbacks)));
713   }
714   if (error != JVMTI_ERROR_NONE) {
715     LOG(ERROR) << "Unable to set event callbacks.";
716     return JNI_ERR;
717   }
718   for (jvmtiEvent e : events) {
719     error = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
720                                             e,
721                                             nullptr /* all threads */);
722     if (error != JVMTI_ERROR_NONE) {
723       LOG(ERROR) << "Unable to enable event " << e;
724       return JNI_ERR;
725     }
726   }
727   return JNI_OK;
728 }
729 
730 // Late attachment (e.g. 'am attach-agent').
Agent_OnAttach(JavaVM * vm,char * options,void * reserved)731 extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *vm, char* options, void* reserved) {
732   return AgentStart(vm, options, reserved);
733 }
734 
735 // Early attachment
Agent_OnLoad(JavaVM * jvm,char * options,void * reserved)736 extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* jvm, char* options, void* reserved) {
737   return AgentStart(jvm, options, reserved);
738 }
739 
740 }  // namespace tifast
741 
742