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