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 {non_}jni_fun(name, event_num, args)
74 #define FOR_ALL_SUPPORTED_EVENTS_DIFFERENT(jni_fun, non_jni_fun) \
75 jni_fun(VMInit, EVENT(VM_INIT), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread), (jvmti, jni, jthreadContainer{.thread = thread})) \
76 jni_fun(VMDeath, EVENT(VM_DEATH), (jvmtiEnv* jvmti, JNIEnv* jni), (jvmti, jni)) \
77 jni_fun(ThreadStart, EVENT(THREAD_START), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread), (jvmti, jni, jthreadContainer{.thread = thread})) \
78 jni_fun(ThreadEnd, EVENT(THREAD_END), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread), (jvmti, jni, jthreadContainer{.thread = thread})) \
79 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)) \
80 jni_fun(ClassLoad, EVENT(CLASS_LOAD), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass), (jvmti, jni, jthreadContainer{.thread = thread}, klass) ) \
81 jni_fun(ClassPrepare, EVENT(CLASS_PREPARE), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass), (jvmti, jni, jthreadContainer{.thread = thread}, klass)) \
82 jni_fun(VMStart, EVENT(VM_START), (jvmtiEnv* jvmti, JNIEnv* jni), (jvmti, jni)) \
83 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)) \
84 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)) \
85 jni_fun(SingleStep, EVENT(SINGLE_STEP), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, jlocation loc), (jvmti, jni, jthreadContainer{.thread = thread}, meth, loc)) \
86 jni_fun(MethodEntry, EVENT(METHOD_ENTRY), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth), (jvmti, jni, jthreadContainer{.thread = thread}, meth)) \
87 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)) \
88 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)) \
89 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)) \
90 non_jni_fun(CompiledMethodUnload, EVENT(COMPILED_METHOD_UNLOAD), (jvmtiEnv* jvmti, jmethodID meth, const void* cv1), (jvmti, meth, cv1)) \
91 non_jni_fun(DynamicCodeGenerated, EVENT(DYNAMIC_CODE_GENERATED), (jvmtiEnv* jvmti, const char* cc, const void* cv, jint i1), (jvmti, cc, cv, i1)) \
92 non_jni_fun(DataDumpRequest, EVENT(DATA_DUMP_REQUEST), (jvmtiEnv* jvmti), (jvmti)) \
93 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})) \
94 jni_fun(MonitorWaited, EVENT(MONITOR_WAITED), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj, jboolean b1), (jvmti, jni, jthreadContainer{.thread = thread}, obj, b1)) \
95 jni_fun(MonitorContendedEnter, EVENT(MONITOR_CONTENDED_ENTER), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, obj)) \
96 jni_fun(MonitorContendedEntered, EVENT(MONITOR_CONTENDED_ENTERED), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, obj)) \
97 jni_fun(ResourceExhausted, EVENT(RESOURCE_EXHAUSTED), (jvmtiEnv* jvmti, JNIEnv* jni, jint i1, const void* cv, const char* cc), (jvmti, jni, i1, cv, cc)) \
98 non_jni_fun(GarbageCollectionStart, EVENT(GARBAGE_COLLECTION_START), (jvmtiEnv* jvmti), (jvmti)) \
99 non_jni_fun(GarbageCollectionFinish, EVENT(GARBAGE_COLLECTION_FINISH), (jvmtiEnv* jvmti), (jvmti)) \
100 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})) \
101
102 #define FOR_ALL_SUPPORTED_EVENTS(fun) \
103 FOR_ALL_SUPPORTED_EVENTS_DIFFERENT(fun, fun)
104
105 static const jvmtiEvent kAllEvents[] = {
106 #define GET_EVENT(a, event, b, c) event,
107 FOR_ALL_SUPPORTED_EVENTS(GET_EVENT)
108 #undef GET_EVENT
109 };
110
111 #define GENERATE_EMPTY_FUNCTION(name, number, args, argnames) \
112 static void JNICALL empty ## name args { Unused argnames ; }
FOR_ALL_SUPPORTED_EVENTS(GENERATE_EMPTY_FUNCTION)113 FOR_ALL_SUPPORTED_EVENTS(GENERATE_EMPTY_FUNCTION)
114 #undef GENERATE_EMPTY_FUNCTION
115
116 static jvmtiEventCallbacks kEmptyCallbacks {
117 #define CREATE_EMPTY_EVENT_CALLBACKS(name, num, args, argnames) \
118 .name = empty ## name,
119 FOR_ALL_SUPPORTED_EVENTS(CREATE_EMPTY_EVENT_CALLBACKS)
120 #undef CREATE_EMPTY_EVENT_CALLBACKS
121 };
122
DeleteLocalRef(JNIEnv * env,jobject obj)123 static void DeleteLocalRef(JNIEnv* env, jobject obj) {
124 if (obj != nullptr && env != nullptr) {
125 env->DeleteLocalRef(obj);
126 }
127 }
128
129 class ScopedThreadInfo {
130 public:
ScopedThreadInfo(jvmtiEnv * jvmtienv,JNIEnv * env,jthread thread)131 ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread)
132 : jvmtienv_(jvmtienv), env_(env), free_name_(false) {
133 if (thread == nullptr) {
134 info_.name = const_cast<char*>("<NULLPTR>");
135 } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) {
136 info_.name = const_cast<char*>("<UNKNOWN THREAD>");
137 } else {
138 free_name_ = true;
139 }
140 }
141
~ScopedThreadInfo()142 ~ScopedThreadInfo() {
143 if (free_name_) {
144 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name));
145 }
146 DeleteLocalRef(env_, info_.thread_group);
147 DeleteLocalRef(env_, info_.context_class_loader);
148 }
149
GetName() const150 const char* GetName() const {
151 return info_.name;
152 }
153
154 private:
155 jvmtiEnv* jvmtienv_;
156 JNIEnv* env_;
157 bool free_name_;
158 jvmtiThreadInfo info_{};
159 };
160
161 class ScopedClassInfo {
162 public:
ScopedClassInfo(jvmtiEnv * jvmtienv,jclass c)163 ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c) : jvmtienv_(jvmtienv), class_(c) {}
164
~ScopedClassInfo()165 ~ScopedClassInfo() {
166 if (class_ != nullptr) {
167 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
168 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
169 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(file_));
170 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(debug_ext_));
171 }
172 }
173
Init(bool get_generic=true)174 bool Init(bool get_generic = true) {
175 if (class_ == nullptr) {
176 name_ = const_cast<char*>("<NONE>");
177 generic_ = const_cast<char*>("<NONE>");
178 return true;
179 } else {
180 jvmtiError ret1 = jvmtienv_->GetSourceFileName(class_, &file_);
181 jvmtiError ret2 = jvmtienv_->GetSourceDebugExtension(class_, &debug_ext_);
182 char** gen_ptr = &generic_;
183 if (!get_generic) {
184 generic_ = nullptr;
185 gen_ptr = nullptr;
186 }
187 return jvmtienv_->GetClassSignature(class_, &name_, gen_ptr) == JVMTI_ERROR_NONE &&
188 ret1 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
189 ret1 != JVMTI_ERROR_INVALID_CLASS &&
190 ret2 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
191 ret2 != JVMTI_ERROR_INVALID_CLASS;
192 }
193 }
194
GetClass() const195 jclass GetClass() const {
196 return class_;
197 }
198
GetName() const199 const char* GetName() const {
200 return name_;
201 }
202
GetGeneric() const203 const char* GetGeneric() const {
204 return generic_;
205 }
206
GetSourceDebugExtension() const207 const char* GetSourceDebugExtension() const {
208 if (debug_ext_ == nullptr) {
209 return "<UNKNOWN_SOURCE_DEBUG_EXTENSION>";
210 } else {
211 return debug_ext_;
212 }
213 }
GetSourceFileName() const214 const char* GetSourceFileName() const {
215 if (file_ == nullptr) {
216 return "<UNKNOWN_FILE>";
217 } else {
218 return file_;
219 }
220 }
221
222 private:
223 jvmtiEnv* jvmtienv_;
224 jclass class_;
225 char* name_ = nullptr;
226 char* generic_ = nullptr;
227 char* file_ = nullptr;
228 char* debug_ext_ = nullptr;
229
230 friend std::ostream& operator<<(std::ostream &os, ScopedClassInfo const& m);
231 };
232
233 class ScopedMethodInfo {
234 public:
ScopedMethodInfo(jvmtiEnv * jvmtienv,JNIEnv * env,jmethodID m)235 ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m)
236 : jvmtienv_(jvmtienv), env_(env), method_(m) {}
237
~ScopedMethodInfo()238 ~ScopedMethodInfo() {
239 DeleteLocalRef(env_, declaring_class_);
240 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
241 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
242 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
243 }
244
Init(bool get_generic=true)245 bool Init(bool get_generic = true) {
246 if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
247 return false;
248 }
249 class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
250 jint nlines;
251 jvmtiLineNumberEntry* lines;
252 jvmtiError err = jvmtienv_->GetLineNumberTable(method_, &nlines, &lines);
253 if (err == JVMTI_ERROR_NONE) {
254 if (nlines > 0) {
255 first_line_ = lines[0].line_number;
256 }
257 jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(lines));
258 } else if (err != JVMTI_ERROR_ABSENT_INFORMATION &&
259 err != JVMTI_ERROR_NATIVE_METHOD) {
260 return false;
261 }
262 return class_info_->Init(get_generic) &&
263 (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
264 }
265
GetDeclaringClassInfo() const266 const ScopedClassInfo& GetDeclaringClassInfo() const {
267 return *class_info_;
268 }
269
GetDeclaringClass() const270 jclass GetDeclaringClass() const {
271 return declaring_class_;
272 }
273
GetName() const274 const char* GetName() const {
275 return name_;
276 }
277
GetSignature() const278 const char* GetSignature() const {
279 return signature_;
280 }
281
GetGeneric() const282 const char* GetGeneric() const {
283 return generic_;
284 }
285
GetFirstLine() const286 jint GetFirstLine() const {
287 return first_line_;
288 }
289
290 private:
291 jvmtiEnv* jvmtienv_;
292 JNIEnv* env_;
293 jmethodID method_;
294 jclass declaring_class_ = nullptr;
295 std::unique_ptr<ScopedClassInfo> class_info_;
296 char* name_ = nullptr;
297 char* signature_ = nullptr;
298 char* generic_ = nullptr;
299 jint first_line_ = -1;
300
301 friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
302 };
303
operator <<(std::ostream & os,ScopedClassInfo const & c)304 std::ostream& operator<<(std::ostream &os, ScopedClassInfo const& c) {
305 const char* generic = c.GetGeneric();
306 if (generic != nullptr) {
307 return os << c.GetName() << "<" << generic << ">" << " file: " << c.GetSourceFileName();
308 } else {
309 return os << c.GetName() << " file: " << c.GetSourceFileName();
310 }
311 }
312
operator <<(std::ostream & os,ScopedMethodInfo const & m)313 std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
314 return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature()
315 << " (source: " << m.GetDeclaringClassInfo().GetSourceFileName() << ":"
316 << m.GetFirstLine() << ")";
317 }
318
319
320 class LogPrinter {
321 public:
LogPrinter(jvmtiEvent event)322 explicit LogPrinter(jvmtiEvent event) : event_(event) {}
323
PrintRestNoJNI(jvmtiEnv * jvmti,Args...args)324 template <typename ...Args> void PrintRestNoJNI(jvmtiEnv* jvmti, Args... args) {
325 PrintRest(jvmti, static_cast<JNIEnv*>(nullptr), args...);
326 }
327
328 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, JNIEnv* env, Args... args);
329 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
330 JNIEnv* env,
331 jlongContainer l,
332 Args... args);
333 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
334 JNIEnv* env,
335 jthreadContainer thr,
336 Args... args);
337 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
338 JNIEnv* env,
339 jboolean i,
340 Args... args);
341 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
342 JNIEnv* env,
343 jint i,
344 Args... args);
345 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
346 JNIEnv* env,
347 jclass klass,
348 Args... args);
349 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
350 JNIEnv* env,
351 jmethodID meth,
352 Args... args);
353 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
354 JNIEnv* env,
355 jlocation loc,
356 Args... args);
357 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
358 JNIEnv* env,
359 jint* ip,
360 Args... args);
361 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
362 JNIEnv* env,
363 const void* loc,
364 Args... args);
365 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
366 JNIEnv* env,
367 void* loc,
368 Args... args);
369 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
370 JNIEnv* env,
371 void** loc,
372 Args... args);
373 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
374 JNIEnv* env,
375 unsigned char** v,
376 Args... args);
377 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
378 JNIEnv* env,
379 const unsigned char* v,
380 Args... args);
381 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
382 JNIEnv* env,
383 const char* v,
384 Args... args);
385 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
386 JNIEnv* env,
387 const jvmtiAddrLocationMap* v,
388 Args... args);
389 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
390 JNIEnv* env,
391 jvalue v,
392 Args... args);
393 template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
394 JNIEnv* env,
395 jobject v,
396 Args... args);
397
GetResult()398 std::string GetResult() {
399 std::string out_str = stream.str();
400 return start_args + out_str;
401 }
402
403 private:
404 jvmtiEvent event_;
405 std::string start_args;
406 std::ostringstream stream;
407 };
408
409 // Base case
PrintRest(jvmtiEnv * jvmti ATTRIBUTE_UNUSED,JNIEnv * jni)410 template<> void LogPrinter::PrintRest(jvmtiEnv* jvmti ATTRIBUTE_UNUSED, JNIEnv* jni) {
411 if (jni == nullptr) {
412 start_args = "jvmtiEnv*";
413 } else {
414 start_args = "jvmtiEnv*, JNIEnv*";
415 }
416 }
417
418 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,const jvmtiAddrLocationMap * v,Args...args)419 void LogPrinter::PrintRest(jvmtiEnv* jvmti,
420 JNIEnv* jni,
421 const jvmtiAddrLocationMap* v,
422 Args... args) {
423 if (v != nullptr) {
424 stream << ", const jvmtiAddrLocationMap*[start_address: "
425 << v->start_address << ", location: " << v->location << "]";
426 } else {
427 stream << ", const jvmtiAddrLocationMap*[nullptr]";
428 }
429 PrintRest(jvmti, jni, args...);
430 }
431
432 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jint * v,Args...args)433 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jint* v, Args... args) {
434 stream << ", jint*[" << static_cast<const void*>(v) << "]";
435 PrintRest(jvmti, jni, args...);
436 }
437
438 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,const void * v,Args...args)439 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const void* v, Args... args) {
440 stream << ", const void*[" << v << "]";
441 PrintRest(jvmti, jni, args...);
442 }
443
444 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,unsigned char ** v,Args...args)445 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, unsigned char** v, Args... args) {
446 stream << ", unsigned char**[" << static_cast<const void*>(v) << "]";
447 PrintRest(jvmti, jni, args...);
448 }
449
450 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,const unsigned char * v,Args...args)451 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const unsigned char* v, Args... args) {
452 stream << ", const unsigned char*[" << static_cast<const void*>(v) << "]";
453 PrintRest(jvmti, jni, args...);
454 }
455
456 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,const char * v,Args...args)457 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const char* v, Args... args) {
458 stream << ", const char*[" << v << "]";
459 PrintRest(jvmti, jni, args...);
460 }
461
462 template<typename... Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jvalue v,Args...args)463 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jvalue v, Args... args) {
464 std::ostringstream hex;
465 hex << std::hex << v.j;
466 std::ostringstream char_val;
467 if (std::isprint(v.c) && v.c < std::numeric_limits<unsigned char>::max()) {
468 char_val << "'" << static_cast<unsigned char>(v.c) << "'";
469 } else {
470 char_val << "0x" << std::hex << reinterpret_cast<uint16_t>(v.c);
471 }
472 stream << ", jvalue[{<hex: 0x" << hex.str() << ">"
473 << ", .z=" << (v.z ? "true" : "false")
474 << ", .b=" << static_cast<int32_t>(v.b)
475 << ", .c=" << char_val.str()
476 << ", .s=" << static_cast<int32_t>(v.s)
477 << ", .i=" << v.i
478 << ", .j=" << v.j
479 << ", .f=" << v.f
480 << ", .d=" << v.d
481 << ", .l=" << v.l << "}]";
482 PrintRest(jvmti, jni, args...);
483 }
484
485 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,void ** v,Args...args)486 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, void** v, Args... args) {
487 stream << ", void**[" << v << "]";
488 PrintRest(jvmti, jni, args...);
489 }
490
491 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,void * v,Args...args)492 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, void* v, Args... args) {
493 stream << ", void*[" << v << "]";
494 PrintRest(jvmti, jni, args...);
495 }
496
497 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jlongContainer l,Args...args)498 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jlongContainer l, Args... args) {
499 stream << ", jlong[" << l.val << ", hex: 0x" << std::hex << l.val << "]";
500 PrintRest(jvmti, jni, args...);
501 }
502
503 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jlocation l,Args...args)504 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jlocation l, Args... args) {
505 stream << ", jlocation[" << l << ", hex: 0x" << std::hex << l << "]";
506 PrintRest(jvmti, jni, args...);
507 }
508
509 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jboolean b,Args...args)510 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jboolean b, Args... args) {
511 stream << ", jboolean[" << (b ? "true" : "false") << "]";
512 PrintRest(jvmti, jni, args...);
513 }
514
515 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jint i,Args...args)516 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jint i, Args... args) {
517 stream << ", jint[" << i << ", hex: 0x" << std::hex << i << "]";
518 PrintRest(jvmti, jni, args...);
519 }
520
521 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jobject obj,Args...args)522 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jobject obj, Args... args) {
523 if (obj == nullptr) {
524 stream << ", jobject[nullptr]";
525 } else {
526 jni->PushLocalFrame(1);
527 jclass klass = jni->GetObjectClass(obj);
528 ScopedClassInfo sci(jvmti, klass);
529 if (sci.Init(event_ != JVMTI_EVENT_VM_OBJECT_ALLOC)) {
530 stream << ", jobject[type: " << sci << "]";
531 } else {
532 stream << ", jobject[type: TYPE UNKNOWN]";
533 }
534 jni->PopLocalFrame(nullptr);
535 }
536 PrintRest(jvmti, jni, args...);
537 }
538
539 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jthreadContainer thr,Args...args)540 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jthreadContainer thr, Args... args) {
541 ScopedThreadInfo sti(jvmti, jni, thr.thread);
542 stream << ", jthread[" << sti.GetName() << "]";
543 PrintRest(jvmti, jni, args...);
544 }
545
546 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jclass klass,Args...args)547 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, Args... args) {
548 ScopedClassInfo sci(jvmti, klass);
549 if (sci.Init(/*get_generic=*/event_ != JVMTI_EVENT_VM_OBJECT_ALLOC)) {
550 stream << ", jclass[" << sci << "]";
551 } else {
552 stream << ", jclass[TYPE UNKNOWN]";
553 }
554 PrintRest(jvmti, jni, args...);
555 }
556
557 template<typename ...Args>
PrintRest(jvmtiEnv * jvmti,JNIEnv * jni,jmethodID meth,Args...args)558 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jmethodID meth, Args... args) {
559 ScopedMethodInfo smi(jvmti, jni, meth);
560 if (smi.Init()) {
561 stream << ", jmethodID[" << smi << "]";
562 } else {
563 stream << ", jmethodID[METHOD UNKNOWN]";
564 }
565 PrintRest(jvmti, jni, args...);
566 }
567
568 #define GENERATE_LOG_FUNCTION_JNI(name, event, args, argnames) \
569 static void JNICALL log ## name args { \
570 LogPrinter printer(event); \
571 printer.PrintRest argnames; \
572 LOG(INFO) << "Got event " << #name << "(" << printer.GetResult() << ")"; \
573 } \
574
575 #define GENERATE_LOG_FUNCTION_NO_JNI(name, event, args, argnames) \
576 static void JNICALL log ## name args { \
577 LogPrinter printer(event); \
578 printer.PrintRestNoJNI argnames; \
579 LOG(INFO) << "Got event " << #name << "(" << printer.GetResult() << ")"; \
580 } \
581
FOR_ALL_SUPPORTED_EVENTS_DIFFERENT(GENERATE_LOG_FUNCTION_JNI,GENERATE_LOG_FUNCTION_NO_JNI)582 FOR_ALL_SUPPORTED_EVENTS_DIFFERENT(GENERATE_LOG_FUNCTION_JNI, GENERATE_LOG_FUNCTION_NO_JNI)
583 #undef GENERATE_LOG_FUNCTION
584
585 static jvmtiEventCallbacks kLogCallbacks {
586 #define CREATE_LOG_EVENT_CALLBACK(name, num, args, argnames) \
587 .name = log ## name,
588 FOR_ALL_SUPPORTED_EVENTS(CREATE_LOG_EVENT_CALLBACK)
589 #undef CREATE_LOG_EVENT_CALLBACK
590 };
591
EventToName(jvmtiEvent desired_event)592 static std::string EventToName(jvmtiEvent desired_event) {
593 #define CHECK_NAME(name, event, args, argnames) \
594 if (desired_event == (event)) { \
595 return #name; \
596 }
597 FOR_ALL_SUPPORTED_EVENTS(CHECK_NAME);
598 LOG(FATAL) << "Unknown event " << desired_event;
599 __builtin_unreachable();
600 #undef CHECK_NAME
601 }
NameToEvent(const std::string & desired_name)602 static jvmtiEvent NameToEvent(const std::string& desired_name) {
603 #define CHECK_NAME(name, event, args, argnames) \
604 if (desired_name == #name) { \
605 return event; \
606 }
607 FOR_ALL_SUPPORTED_EVENTS(CHECK_NAME);
608 LOG(FATAL) << "Unknown event " << desired_name;
609 __builtin_unreachable();
610 #undef CHECK_NAME
611 }
612
613 #undef FOR_ALL_SUPPORTED_EVENTS
614 #undef FOR_ALL_SUPPORTED_EVENTS_DIFFERENT
615
GetAllAvailableEvents(jvmtiEnv * jvmti)616 static std::vector<jvmtiEvent> GetAllAvailableEvents(jvmtiEnv* jvmti) {
617 std::vector<jvmtiEvent> out;
618 jvmtiCapabilities caps{};
619 jvmti->GetPotentialCapabilities(&caps);
620 uint8_t caps_bytes[sizeof(caps)];
621 memcpy(caps_bytes, &caps, sizeof(caps));
622 for (jvmtiEvent e : kAllEvents) {
623 jvmtiCapabilities req{};
624 AddCapsForEvent(e, &req);
625 uint8_t req_bytes[sizeof(req)];
626 memcpy(req_bytes, &req, sizeof(req));
627 bool good = true;
628 for (size_t i = 0; i < sizeof(caps); i++) {
629 if ((req_bytes[i] & caps_bytes[i]) != req_bytes[i]) {
630 good = false;
631 break;
632 }
633 }
634 if (good) {
635 out.push_back(e);
636 } else {
637 LOG(WARNING) << "Unable to get capabilities for event " << EventToName(e);
638 }
639 }
640 return out;
641 }
642
GetRequestedEventList(jvmtiEnv * jvmti,const std::string & args)643 static std::vector<jvmtiEvent> GetRequestedEventList(jvmtiEnv* jvmti, const std::string& args) {
644 std::vector<jvmtiEvent> res;
645 std::stringstream args_stream(args);
646 std::string item;
647 while (std::getline(args_stream, item, ',')) {
648 if (item == "") {
649 continue;
650 } else if (item == "all") {
651 return GetAllAvailableEvents(jvmti);
652 }
653 res.push_back(NameToEvent(item));
654 }
655 return res;
656 }
657
SetupJvmtiEnv(JavaVM * vm,jvmtiEnv ** jvmti)658 static jint SetupJvmtiEnv(JavaVM* vm, jvmtiEnv** jvmti) {
659 jint res = 0;
660 res = vm->GetEnv(reinterpret_cast<void**>(jvmti), JVMTI_VERSION_1_1);
661
662 if (res != JNI_OK || *jvmti == nullptr) {
663 LOG(ERROR) << "Unable to access JVMTI, error code " << res;
664 return vm->GetEnv(reinterpret_cast<void**>(jvmti), kArtTiVersion);
665 }
666 return res;
667 }
668
669 } // namespace
670
AgentStart(JavaVM * vm,char * options,void * reserved ATTRIBUTE_UNUSED)671 static jint AgentStart(JavaVM* vm,
672 char* options,
673 void* reserved ATTRIBUTE_UNUSED) {
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