Home | History | Annotate | Download | only in openjdkjvmti
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
     18 #define ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
     19 
     20 #include <array>
     21 
     22 #include "events.h"
     23 #include "jni_internal.h"
     24 #include "nativehelper/ScopedLocalRef.h"
     25 #include "ti_breakpoint.h"
     26 
     27 #include "art_jvmti.h"
     28 
     29 namespace openjdkjvmti {
     30 
     31 static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
     32   if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
     33     if (env->capabilities.can_retransform_classes) {
     34       return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
     35     } else {
     36       return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
     37     }
     38   } else {
     39     return static_cast<ArtJvmtiEvent>(e);
     40   }
     41 }
     42 
     43 namespace impl {
     44 
     45 // Infrastructure to achieve type safety for event dispatch.
     46 
     47 #define FORALL_EVENT_TYPES(fn)                                                       \
     48   fn(VMInit,                  ArtJvmtiEvent::kVmInit)                                \
     49   fn(VMDeath,                 ArtJvmtiEvent::kVmDeath)                               \
     50   fn(ThreadStart,             ArtJvmtiEvent::kThreadStart)                           \
     51   fn(ThreadEnd,               ArtJvmtiEvent::kThreadEnd)                             \
     52   fn(ClassFileLoadHook,       ArtJvmtiEvent::kClassFileLoadHookRetransformable)      \
     53   fn(ClassFileLoadHook,       ArtJvmtiEvent::kClassFileLoadHookNonRetransformable)   \
     54   fn(ClassLoad,               ArtJvmtiEvent::kClassLoad)                             \
     55   fn(ClassPrepare,            ArtJvmtiEvent::kClassPrepare)                          \
     56   fn(VMStart,                 ArtJvmtiEvent::kVmStart)                               \
     57   fn(Exception,               ArtJvmtiEvent::kException)                             \
     58   fn(ExceptionCatch,          ArtJvmtiEvent::kExceptionCatch)                        \
     59   fn(SingleStep,              ArtJvmtiEvent::kSingleStep)                            \
     60   fn(FramePop,                ArtJvmtiEvent::kFramePop)                              \
     61   fn(Breakpoint,              ArtJvmtiEvent::kBreakpoint)                            \
     62   fn(FieldAccess,             ArtJvmtiEvent::kFieldAccess)                           \
     63   fn(FieldModification,       ArtJvmtiEvent::kFieldModification)                     \
     64   fn(MethodEntry,             ArtJvmtiEvent::kMethodEntry)                           \
     65   fn(MethodExit,              ArtJvmtiEvent::kMethodExit)                            \
     66   fn(NativeMethodBind,        ArtJvmtiEvent::kNativeMethodBind)                      \
     67   fn(CompiledMethodLoad,      ArtJvmtiEvent::kCompiledMethodLoad)                    \
     68   fn(CompiledMethodUnload,    ArtJvmtiEvent::kCompiledMethodUnload)                  \
     69   fn(DynamicCodeGenerated,    ArtJvmtiEvent::kDynamicCodeGenerated)                  \
     70   fn(DataDumpRequest,         ArtJvmtiEvent::kDataDumpRequest)                       \
     71   fn(MonitorWait,             ArtJvmtiEvent::kMonitorWait)                           \
     72   fn(MonitorWaited,           ArtJvmtiEvent::kMonitorWaited)                         \
     73   fn(MonitorContendedEnter,   ArtJvmtiEvent::kMonitorContendedEnter)                 \
     74   fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered)               \
     75   fn(ResourceExhausted,       ArtJvmtiEvent::kResourceExhausted)                     \
     76   fn(GarbageCollectionStart,  ArtJvmtiEvent::kGarbageCollectionStart)                \
     77   fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish)               \
     78   fn(ObjectFree,              ArtJvmtiEvent::kObjectFree)                            \
     79   fn(VMObjectAlloc,           ArtJvmtiEvent::kVmObjectAlloc)
     80 
     81 template <ArtJvmtiEvent kEvent>
     82 struct EventFnType {
     83 };
     84 
     85 #define EVENT_FN_TYPE(name, enum_name)               \
     86 template <>                                          \
     87 struct EventFnType<enum_name> {                      \
     88   using type = decltype(jvmtiEventCallbacks().name); \
     89 };
     90 
     91 FORALL_EVENT_TYPES(EVENT_FN_TYPE)
     92 
     93 #undef EVENT_FN_TYPE
     94 
     95 template <ArtJvmtiEvent kEvent>
     96 ALWAYS_INLINE inline typename EventFnType<kEvent>::type GetCallback(ArtJvmTiEnv* env);
     97 
     98 #define GET_CALLBACK(name, enum_name)                                     \
     99 template <>                                                               \
    100 ALWAYS_INLINE inline EventFnType<enum_name>::type GetCallback<enum_name>( \
    101     ArtJvmTiEnv* env) {                                                   \
    102   if (env->event_callbacks == nullptr) {                                  \
    103     return nullptr;                                                       \
    104   }                                                                       \
    105   return env->event_callbacks->name;                                      \
    106 }
    107 
    108 FORALL_EVENT_TYPES(GET_CALLBACK)
    109 
    110 #undef GET_CALLBACK
    111 
    112 #undef FORALL_EVENT_TYPES
    113 
    114 }  // namespace impl
    115 
    116 // C++ does not allow partial template function specialization. The dispatch for our separated
    117 // ClassFileLoadHook event types is the same, so use this helper for code deduplication.
    118 // TODO Locking of some type!
    119 template <ArtJvmtiEvent kEvent>
    120 inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
    121                                                          JNIEnv* jnienv,
    122                                                          jclass class_being_redefined,
    123                                                          jobject loader,
    124                                                          const char* name,
    125                                                          jobject protection_domain,
    126                                                          jint class_data_len,
    127                                                          const unsigned char* class_data,
    128                                                          jint* new_class_data_len,
    129                                                          unsigned char** new_class_data) const {
    130   static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
    131                 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
    132   DCHECK(*new_class_data == nullptr);
    133   jint current_len = class_data_len;
    134   unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
    135   ArtJvmTiEnv* last_env = nullptr;
    136   for (ArtJvmTiEnv* env : envs) {
    137     if (env == nullptr) {
    138       continue;
    139     }
    140     if (ShouldDispatch<kEvent>(env, thread)) {
    141       ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
    142       jnienv->ExceptionClear();
    143       jint new_len = 0;
    144       unsigned char* new_data = nullptr;
    145       auto callback = impl::GetCallback<kEvent>(env);
    146       callback(env,
    147                jnienv,
    148                class_being_redefined,
    149                loader,
    150                name,
    151                protection_domain,
    152                current_len,
    153                current_class_data,
    154                &new_len,
    155                &new_data);
    156       if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
    157         jnienv->Throw(thr.get());
    158       }
    159       if (new_data != nullptr && new_data != current_class_data) {
    160         // Destroy the data the last transformer made. We skip this if the previous state was the
    161         // initial one since we don't know here which jvmtiEnv allocated it.
    162         // NB Currently this doesn't matter since all allocations just go to malloc but in the
    163         // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
    164         if (last_env != nullptr) {
    165           last_env->Deallocate(current_class_data);
    166         }
    167         last_env = env;
    168         current_class_data = new_data;
    169         current_len = new_len;
    170       }
    171     }
    172   }
    173   if (last_env != nullptr) {
    174     *new_class_data_len = current_len;
    175     *new_class_data = current_class_data;
    176   }
    177 }
    178 
    179 // Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
    180 // exactly the argument types of the corresponding Jvmti kEvent function pointer.
    181 
    182 template <ArtJvmtiEvent kEvent, typename ...Args>
    183 inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
    184   for (ArtJvmTiEnv* env : envs) {
    185     if (env != nullptr) {
    186       DispatchEvent<kEvent, Args...>(env, thread, args...);
    187     }
    188   }
    189 }
    190 
    191 // Events with JNIEnvs need to stash pending exceptions since they can cause new ones to be thrown.
    192 // In accordance with the JVMTI specification we allow exceptions originating from events to
    193 // overwrite the current exception, including exceptions originating from earlier events.
    194 // TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list of the
    195 // newest exception.
    196 template <ArtJvmtiEvent kEvent, typename ...Args>
    197 inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const {
    198   for (ArtJvmTiEnv* env : envs) {
    199     if (env != nullptr) {
    200       ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
    201       jnienv->ExceptionClear();
    202       DispatchEvent<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...);
    203       if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
    204         jnienv->Throw(thr.get());
    205       }
    206     }
    207   }
    208 }
    209 
    210 template <ArtJvmtiEvent kEvent, typename ...Args>
    211 inline void EventHandler::DispatchEvent(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
    212   using FnType = void(jvmtiEnv*, Args...);
    213   if (ShouldDispatch<kEvent>(env, thread)) {
    214     FnType* callback = impl::GetCallback<kEvent>(env);
    215     if (callback != nullptr) {
    216       (*callback)(env, args...);
    217     }
    218   }
    219 }
    220 
    221 // Need to give custom specializations for Breakpoint since it needs to filter out which particular
    222 // methods/dex_pcs agents get notified on.
    223 template <>
    224 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kBreakpoint>(art::Thread* thread,
    225                                                                     JNIEnv* jnienv,
    226                                                                     jthread jni_thread,
    227                                                                     jmethodID jmethod,
    228                                                                     jlocation location) const {
    229   art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
    230   for (ArtJvmTiEnv* env : envs) {
    231     // Search for a breakpoint on this particular method and location.
    232     if (env != nullptr &&
    233         ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
    234         env->breakpoints.find({method, location}) != env->breakpoints.end()) {
    235       // We temporarily clear any pending exceptions so the event can call back into java code.
    236       ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
    237       jnienv->ExceptionClear();
    238       auto callback = impl::GetCallback<ArtJvmtiEvent::kBreakpoint>(env);
    239       (*callback)(env, jnienv, jni_thread, jmethod, location);
    240       if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
    241         jnienv->Throw(thr.get());
    242       }
    243     }
    244   }
    245 }
    246 
    247 // Need to give custom specializations for FieldAccess and FieldModification since they need to
    248 // filter out which particular fields agents want to get notified on.
    249 // TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This
    250 // could make the system more performant.
    251 template <>
    252 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kFieldModification>(art::Thread* thread,
    253                                                                            JNIEnv* jnienv,
    254                                                                            jthread jni_thread,
    255                                                                            jmethodID method,
    256                                                                            jlocation location,
    257                                                                            jclass field_klass,
    258                                                                            jobject object,
    259                                                                            jfieldID field,
    260                                                                            char type_char,
    261                                                                            jvalue val) const {
    262   for (ArtJvmTiEnv* env : envs) {
    263     if (env != nullptr &&
    264         ShouldDispatch<ArtJvmtiEvent::kFieldModification>(env, thread) &&
    265         env->modify_watched_fields.find(
    266             art::jni::DecodeArtField(field)) != env->modify_watched_fields.end()) {
    267       ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
    268       jnienv->ExceptionClear();
    269       auto callback = impl::GetCallback<ArtJvmtiEvent::kFieldModification>(env);
    270       (*callback)(env,
    271                   jnienv,
    272                   jni_thread,
    273                   method,
    274                   location,
    275                   field_klass,
    276                   object,
    277                   field,
    278                   type_char,
    279                   val);
    280       if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
    281         jnienv->Throw(thr.get());
    282       }
    283     }
    284   }
    285 }
    286 
    287 template <>
    288 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kFieldAccess>(art::Thread* thread,
    289                                                                      JNIEnv* jnienv,
    290                                                                      jthread jni_thread,
    291                                                                      jmethodID method,
    292                                                                      jlocation location,
    293                                                                      jclass field_klass,
    294                                                                      jobject object,
    295                                                                      jfieldID field) const {
    296   for (ArtJvmTiEnv* env : envs) {
    297     if (env != nullptr &&
    298         ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
    299         env->access_watched_fields.find(
    300             art::jni::DecodeArtField(field)) != env->access_watched_fields.end()) {
    301       ScopedLocalRef<jthrowable> thr(jnienv, jnienv->ExceptionOccurred());
    302       jnienv->ExceptionClear();
    303       auto callback = impl::GetCallback<ArtJvmtiEvent::kFieldAccess>(env);
    304       (*callback)(env, jnienv, jni_thread, method, location, field_klass, object, field);
    305       if (thr.get() != nullptr && !jnienv->ExceptionCheck()) {
    306         jnienv->Throw(thr.get());
    307       }
    308     }
    309   }
    310 }
    311 
    312 // Need to give a custom specialization for NativeMethodBind since it has to deal with an out
    313 // variable.
    314 template <>
    315 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
    316                                                                           JNIEnv* jnienv,
    317                                                                           jthread jni_thread,
    318                                                                           jmethodID method,
    319                                                                           void* cur_method,
    320                                                                           void** new_method) const {
    321   *new_method = cur_method;
    322   for (ArtJvmTiEnv* env : envs) {
    323     if (env != nullptr && ShouldDispatch<ArtJvmtiEvent::kNativeMethodBind>(env, thread)) {
    324       auto callback = impl::GetCallback<ArtJvmtiEvent::kNativeMethodBind>(env);
    325       (*callback)(env, jnienv, jni_thread, method, cur_method, new_method);
    326       if (*new_method != nullptr) {
    327         cur_method = *new_method;
    328       }
    329     }
    330   }
    331 }
    332 
    333 // C++ does not allow partial template function specialization. The dispatch for our separated
    334 // ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
    335 // The following two DispatchEvent specializations dispatch to it.
    336 template <>
    337 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
    338     art::Thread* thread,
    339     JNIEnv* jnienv,
    340     jclass class_being_redefined,
    341     jobject loader,
    342     const char* name,
    343     jobject protection_domain,
    344     jint class_data_len,
    345     const unsigned char* class_data,
    346     jint* new_class_data_len,
    347     unsigned char** new_class_data) const {
    348   return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
    349       thread,
    350       jnienv,
    351       class_being_redefined,
    352       loader,
    353       name,
    354       protection_domain,
    355       class_data_len,
    356       class_data,
    357       new_class_data_len,
    358       new_class_data);
    359 }
    360 template <>
    361 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
    362     art::Thread* thread,
    363     JNIEnv* jnienv,
    364     jclass class_being_redefined,
    365     jobject loader,
    366     const char* name,
    367     jobject protection_domain,
    368     jint class_data_len,
    369     const unsigned char* class_data,
    370     jint* new_class_data_len,
    371     unsigned char** new_class_data) const {
    372   return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
    373       thread,
    374       jnienv,
    375       class_being_redefined,
    376       loader,
    377       name,
    378       protection_domain,
    379       class_data_len,
    380       class_data,
    381       new_class_data_len,
    382       new_class_data);
    383 }
    384 
    385 template <ArtJvmtiEvent kEvent>
    386 inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
    387                                          art::Thread* thread) {
    388   bool dispatch = env->event_masks.global_event_mask.Test(kEvent);
    389 
    390   if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
    391     EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
    392     dispatch = mask != nullptr && mask->Test(kEvent);
    393   }
    394   return dispatch;
    395 }
    396 
    397 inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
    398   bool union_value = false;
    399   for (const ArtJvmTiEnv* stored_env : envs) {
    400     if (stored_env == nullptr) {
    401       continue;
    402     }
    403     union_value |= stored_env->event_masks.global_event_mask.Test(event);
    404     union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
    405     if (union_value) {
    406       break;
    407     }
    408   }
    409   global_mask.Set(event, union_value);
    410 }
    411 
    412 inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
    413                                            const jvmtiCapabilities& caps,
    414                                            bool added) {
    415   ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
    416                               : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
    417   return caps.can_retransform_classes == 1 &&
    418       IsEventEnabledAnywhere(event) &&
    419       env->event_masks.IsEnabledAnywhere(event);
    420 }
    421 
    422 inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
    423                                                     const jvmtiCapabilities& caps,
    424                                                     bool added) {
    425   if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
    426     env->event_masks.HandleChangedCapabilities(caps, added);
    427     if (caps.can_retransform_classes == 1) {
    428       RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
    429       RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
    430     }
    431   }
    432 }
    433 
    434 }  // namespace openjdkjvmti
    435 
    436 #endif  // ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
    437