Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  suspend_event_helper.cc

  Sprache: C
 

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "suspend_event_helper.h"

#include <inttypes.h>

#include <cstdio>
#include <memory>
#include <string>
#include <vector>

#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "common_helper.h"
#include "jni.h"
#include "jvmti.h"
#include "scoped_local_ref.h"
#include "scoped_utf_chars.h"

// Test infrastructure
#include "jni_binder.h"
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "test_env.h"
#include "ti_macros.h"

namespace art {
namespace common_suspend_event {

struct TestData {
  jlocation target_loc;
  jmethodID target_method;
  jclass target_klass;
  jfieldID target_field;
  jrawMonitorID notify_monitor;
  jint frame_pop_offset;
  jmethodID frame_pop_setup_method;
  jmethodID method_exit_callback;
  std::vector<std::string> interesting_classes;
  bool suspend_on_method_entry_exit;
  bool hit_location;

  TestData(jvmtiEnv* jvmti,
           JNIEnv* env,
           jlocation loc,
           jobject meth,
           jclass klass,
           jobject field,
           jobject setup_meth,
           jint pop_offset,
           jobject method_callback,
           const std::vector<std::string>&& interesting)
      : target_loc(loc),
        target_method(meth != nullptr ? env->FromReflectedMethod(meth) : nullptr),
        target_klass(reinterpret_cast<jclass>(env->NewGlobalRef(klass))),
        target_field(field != nullptr ? env->FromReflectedField(field) : nullptr),
        frame_pop_offset(pop_offset),
        frame_pop_setup_method(setup_meth != nullptr ? env->FromReflectedMethod(setup_meth)
                                                     : nullptr),
        method_exit_callback(method_callback != nullptr ? env->FromReflectedMethod(method_callback)
                                                        : nullptr),
        interesting_classes(interesting),
        suspend_on_method_entry_exit(true),
        hit_location(false) {
    JvmtiErrorToException(
        env, jvmti, jvmti->CreateRawMonitor("SuspendStopMonitor", ¬ify_monitor));
  }

  void PerformSuspend(jvmtiEnv* jvmti, JNIEnv* env) {
    // Wake up the waiting thread.
    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorEnter(notify_monitor));
    hit_location = true;
    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorNotifyAll(notify_monitor));
    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorExit(notify_monitor));
    // Suspend ourself
    jvmti->SuspendThread(nullptr);
  }
};

void PerformSuspension(jvmtiEnv* jvmti, JNIEnv* env) {
  TestData* data;
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti->GetThreadLocalStorage(/* thread */ nullptr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  data->PerformSuspend(jvmti, env);
}

void JNICALL
cbSingleStep(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID meth, jlocation loc) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (meth != data->target_method || loc != data->target_loc) {
    return;
  }
  data->PerformSuspend(jvmti, env);
}

void JNICALL cbExceptionCatch(jvmtiEnv* jvmti,
                              JNIEnv* env,
                              jthread thr,
                              jmethodID method,
                              [[maybe_unused]] jlocation location,
                              [[maybe_unused]] jobject exception) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (method != data->target_method) {
    return;
  }
  data->PerformSuspend(jvmti, env);
}

void JNICALL cbException(jvmtiEnv* jvmti,
                         JNIEnv* env,
                         jthread thr,
                         jmethodID method,
                         [[maybe_unused]] jlocation location,
                         [[maybe_unused]] jobject exception,
                         [[maybe_unused]] jmethodID catch_method,
                         [[maybe_unused]] jlocation catch_location) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (method != data->target_method) {
    return;
  }
  data->PerformSuspend(jvmti, env);
}

void JNICALL cbMethodEntry(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID method) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (method != data->target_method) {
    return;
  }
  data->PerformSuspend(jvmti, env);
}

void JNICALL cbMethodExit(jvmtiEnv* jvmti,
                          JNIEnv* env,
                          jthread thr,
                          jmethodID method,
                          [[maybe_unused]] jboolean was_popped_by_exception,
                          [[maybe_unused]] jvalue return_value) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (method != data->target_method) {
    return;
  }
  data->PerformSuspend(jvmti, env);
}

void suspendOnceCallback(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID method) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  if (data == nullptr) {
    return;
  }
  if (method != data->target_method) {
    return;
  }
  env->CallStaticVoidMethod(
      data->target_klass, data->method_exit_callback, GetJavaMethod(jvmti, env, method));
  if (!data->hit_location && data->suspend_on_method_entry_exit) {
    data->PerformSuspend(jvmti, env);
  }
}

void JNICALL cbMethodEntrySuspendOnce(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID method) {
  suspendOnceCallback(jvmti, env, thr, method);
}

void JNICALL cbMethodExitSuspendOnce(jvmtiEnv* jvmti,
                                     JNIEnv* env,
                                     jthread thr,
                                     jmethodID method,
                                     [[maybe_unused]] jboolean was_popped_by_exception,
                                     [[maybe_unused]] jvalue return_value) {
  suspendOnceCallback(jvmti, env, thr, method);
}

void JNICALL cbFieldModification(jvmtiEnv* jvmti,
                                 JNIEnv* env,
                                 jthread thr,
                                 [[maybe_unused]] jmethodID method,
                                 [[maybe_unused]] jlocation location,
                                 [[maybe_unused]] jclass field_klass,
                                 [[maybe_unused]] jobject object,
                                 jfieldID field,
                                 [[maybe_unused]] char signature_type,
                                 [[maybe_unused]] jvalue new_value) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (field != data->target_field) {
    // TODO What to do here.
    LOG(FATAL) << "Strange, shouldn't get here!";
  }
  data->PerformSuspend(jvmti, env);
}

void JNICALL cbFieldAccess(jvmtiEnv* jvmti,
                           JNIEnv* env,
                           jthread thr,
                           [[maybe_unused]] jmethodID method,
                           [[maybe_unused]] jlocation location,
                           jclass field_klass,
                           [[maybe_unused]] jobject object,
                           jfieldID field) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (field != data->target_field || !env->IsSameObject(field_klass, data->target_klass)) {
    // TODO What to do here.
    LOG(FATAL) << "Strange, shouldn't get here!";
  }
  data->PerformSuspend(jvmti, env);
}

void JNICALL
cbBreakpointHit(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID method, jlocation loc) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (data->frame_pop_setup_method == method) {
    CHECK(loc == 0) << "We should have stopped at location 0";
    if (JvmtiErrorToException(env, jvmti, jvmti->NotifyFramePop(thr, data->frame_pop_offset))) {
      return;
    }
    return;
  }
  if (method != data->target_method || loc != data->target_loc) {
    // TODO What to do here.
    LOG(FATAL) << "Strange, shouldn't get here!";
  }
  data->PerformSuspend(jvmti, env);
}

void JNICALL cbFramePop(jvmtiEnv* jvmti,
                        JNIEnv* env,
                        jthread thr,
                        [[maybe_unused]] jmethodID method,
                        [[maybe_unused]] jboolean was_popped_by_exception) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  data->PerformSuspend(jvmti, env);
}

void JNICALL cbClassLoadOrPrepare(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jclass klass) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  char* name;
  if (JvmtiErrorToException(env, jvmti, jvmti->GetClassSignature(klass, &name, nullptr))) {
    return;
  }
  std::string name_str(name);
  if (JvmtiErrorToException(
          env, jvmti, jvmti->Deallocate(reinterpret_cast<unsigned char*>(name)))) {
    return;
  }
  if (std::find(data->interesting_classes.cbegin(), data->interesting_classes.cend(), name_str) !=
      data->interesting_classes.cend()) {
    data->PerformSuspend(jvmti, env);
  }
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupTest(JNIEnv* env,
                                                                   [[maybe_unused]] jclass klass) {
  jvmtiCapabilities caps;
  memset(&caps, 0sizeof(caps));
  // Most of these will already be there but might as well be complete.
  caps.can_pop_frame = 1;
  caps.can_force_early_return = 1;
  caps.can_generate_single_step_events = 1;
  caps.can_generate_breakpoint_events = 1;
  caps.can_suspend = 1;
  caps.can_generate_method_entry_events = 1;
  caps.can_generate_method_exit_events = 1;
  caps.can_generate_monitor_events = 1;
  caps.can_generate_exception_events = 1;
  caps.can_generate_frame_pop_events = 1;
  caps.can_generate_field_access_events = 1;
  caps.can_generate_field_modification_events = 1;
  caps.can_redefine_classes = 1;
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
    return;
  }
  jvmtiEventCallbacks cb;
  memset(&cb, 0sizeof(cb));
  // TODO Add the rest of these.
  cb.Breakpoint = cbBreakpointHit;
  cb.SingleStep = cbSingleStep;
  cb.FieldAccess = cbFieldAccess;
  cb.FieldModification = cbFieldModification;
  cb.MethodEntry = cbMethodEntry;
  cb.MethodExit = cbMethodExit;
  cb.Exception = cbException;
  cb.ExceptionCatch = cbExceptionCatch;
  cb.FramePop = cbFramePop;
  cb.ClassLoad = cbClassLoadOrPrepare;
  cb.ClassPrepare = cbClassLoadOrPrepare;
  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)));
}

extern "C" JNIEXPORT void JNICALL
Java_art_SuspendEvents_setupMethodExitTest(JNIEnv* env, [[maybe_unused]] jclass klass) {
  jvmtiCapabilities caps;
  memset(&caps, 0sizeof(caps));
  // Most of these will already be there but might as well be complete.
  caps.can_pop_frame = 1;
  caps.can_force_early_return = 1;
  caps.can_generate_single_step_events = 1;
  caps.can_generate_breakpoint_events = 1;
  caps.can_suspend = 1;
  caps.can_generate_method_entry_events = 1;
  caps.can_generate_method_exit_events = 1;
  caps.can_generate_monitor_events = 1;
  caps.can_generate_exception_events = 1;
  caps.can_generate_frame_pop_events = 1;
  caps.can_generate_field_access_events = 1;
  caps.can_generate_field_modification_events = 1;
  caps.can_redefine_classes = 1;
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
    return;
  }
  jvmtiEventCallbacks cb;
  memset(&cb, 0sizeof(cb));
  cb.MethodEntry = cbMethodEntrySuspendOnce;
  cb.MethodExit = cbMethodExitSuspendOnce;
  cb.Exception = cbException;
  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)));
}

static bool DeleteTestData(JNIEnv* env, jthread thr, TestData* data) {
  env->DeleteGlobalRef(data->target_klass);
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
    return false;
  }
  return JvmtiErrorToException(
      env, jvmti_env, jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data)));
}

static TestData* SetupTestData(JNIEnv* env,
                               jobject meth,
                               jlocation loc,
                               jclass target_klass,
                               jobject field,
                               jobject setup_meth,
                               jint pop_offset,
                               jobject method_exit_callback,
                               const std::vector<std::string>&& interesting_names) {
  void* data_ptr;
  TestData* data;
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->Allocate(sizeof(TestData), reinterpret_cast<uint8_t**>(&data_ptr)))) {
    return nullptr;
  }
  data = new (data_ptr) TestData(jvmti_env,
                                 env,
                                 loc,
                                 meth,
                                 target_klass,
                                 field,
                                 setup_meth,
                                 pop_offset,
                                 method_exit_callback,
                                 std::move(interesting_names));
  if (env->ExceptionCheck()) {
    env->DeleteGlobalRef(data->target_klass);
    jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data));
    return nullptr;
  }
  return data;
}

static TestData* SetupTestData(JNIEnv* env,
                               jobject meth,
                               jlocation loc,
                               jclass target_klass,
                               jobject field,
                               jobject setup_meth,
                               jint pop_offset) {
  std::vector<std::string> empty;
  return SetupTestData(
      env, meth, loc, target_klass, field, setup_meth, pop_offset, nullptr, std::move(empty));
}

extern "C" JNIEXPORT void JNICALL
Java_art_SuspendEvents_setupSuspendClassEvent(JNIEnv* env,
                                              [[maybe_unused]] jclass klass,
                                              jint event_num,
                                              jobjectArray interesting_names,
                                              jthread thr) {
  CHECK(event_num == JVMTI_EVENT_CLASS_LOAD || event_num == JVMTI_EVENT_CLASS_PREPARE);
  std::vector<std::string> names;
  jint cnt = env->GetArrayLength(interesting_names);
  for (jint i = 0; i < cnt; i++) {
    env->PushLocalFrame(1);
    jstring name_obj = reinterpret_cast<jstring>(env->GetObjectArrayElement(interesting_names, i));
    const char* name_chr = env->GetStringUTFChars(name_obj, nullptr);
    names.push_back(std::string(name_chr));
    env->ReleaseStringUTFChars(name_obj, name_chr);
    env->PopLocalFrame(nullptr);
  }
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data == nullptr) << "Data was not cleared!";
  data = SetupTestData(env,
                       nullptr,
                       0,
                       nullptr,
                       nullptr,
                       nullptr,
                       0,
                       /*method_exit_callback*/ nullptr,
                       std::move(names));
  if (data == nullptr) {
    return;
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
    return;
  }
  JvmtiErrorToException(
      env,
      jvmti_env,
      jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, static_cast<jvmtiEvent>(event_num), thr));
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendClassEvent(
    JNIEnv* env, [[maybe_unused]] jclass klass, jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_LOAD, thr))) {
    return;
  }
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_PREPARE, thr))) {
    return;
  }
  DeleteTestData(env, thr, data);
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendSingleStepAt(
    JNIEnv* env, [[maybe_unused]] jclass klass, jobject meth, jlocation loc, jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data == nullptr) << "Data was not cleared!";
  data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0);
  if (data == nullptr) {
    return;
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
    return;
  }
  JvmtiErrorToException(
      env,
      jvmti_env,
      jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, thr));
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendSingleStepFor(
    JNIEnv* env, [[maybe_unused]] jclass klass, jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, thr))) {
    return;
  }
  DeleteTestData(env, thr, data);
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendPopFrameEvent(
    JNIEnv* env, [[maybe_unused]] jclass klass, jint offset, jobject breakpoint_func, jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data == nullptr) << "Data was not cleared!";
  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, breakpoint_func, offset);
  CHECK(data != nullptr);
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
    return;
  }
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_FRAME_POP, thr))) {
    return;
  }
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
    return;
  }
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->SetBreakpoint(data->frame_pop_setup_method, 0))) {
    return;
  }
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendPopFrameEvent(
    JNIEnv* env, [[maybe_unused]] jclass klass , jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_FRAME_POP, thr))) {
    return;
  }
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
    return;
  }
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->ClearBreakpoint(data->frame_pop_setup_method, 0))) {
    return;
  }
  DeleteTestData(env, thr, data);
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendBreakpointFor(
    JNIEnv* env, [[maybe_unused]] jclass klass , jobject meth, jlocation loc, jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data == nullptr) << "Data was not cleared!";
  data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0);
  if (data == nullptr) {
    return;
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
    return;
  }
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
    return;
  }
  JvmtiErrorToException(
      env, jvmti_env, jvmti_env->SetBreakpoint(data->target_method, data->target_loc));
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendBreakpointFor(
    JNIEnv* env, [[maybe_unused]] jclass klass , jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
    return;
  }
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->ClearBreakpoint(data->target_method, data->target_loc))) {
    return;
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
    return;
  }
  DeleteTestData(env, thr, data);
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendExceptionEvent(
    JNIEnv* env, [[maybe_unused]] jclass klass , jobject method, jboolean is_catch, jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data == nullptr) << "Data was not cleared!";
  data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0);
  if (data == nullptr) {
    return;
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
    return;
  }
  JvmtiErrorToException(
      env,
      jvmti_env,
      jvmti_env->SetEventNotificationMode(
          JVMTI_ENABLE, is_catch ? JVMTI_EVENT_EXCEPTION_CATCH : JVMTI_EVENT_EXCEPTION, thr));
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_enableMethodExitEvents(
    JNIEnv* env, [[maybe_unused]] jclass klass , jclass target_class, jobject method, jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
      env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  if (data != nullptr) {
    data->suspend_on_method_entry_exit = false;

    if (data->target_klass == nullptr) {
      data->target_klass = reinterpret_cast<jclass>(env->NewGlobalRef(target_class));
    } else if (!env->IsSameObject(data->target_klass, target_class)) {
      LOG(ERROR) << "No support for setting events for different target classes";
    }

    data->method_exit_callback = env->FromReflectedMethod(method);
  }
  JvmtiErrorToException(
      env,
      jvmti_env,
      jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, thr));
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendExceptionEvent(
    JNIEnv* env, [[maybe_unused]] jclass klass , jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION_CATCH, thr))) {
    return;
  }
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION, thr))) {
    return;
  }
  DeleteTestData(env, thr, data);
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_disableExceptionEvents(
    JNIEnv* env, [[maybe_unused]] jclass klass , jthread thr) {
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION_CATCH, thr))) {
    return;
  }
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION, thr))) {
    return;
  }
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendMethodEvent(
    JNIEnv* env, [[maybe_unused]] jclass klass , jobject method, jboolean enter, jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data == nullptr) << "Data was not cleared!";
  data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0);
  if (data == nullptr) {
    return;
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
    return;
  }
  JvmtiErrorToException(
      env,
      jvmti_env,
      jvmti_env->SetEventNotificationMode(
          JVMTI_ENABLE, enter ? JVMTI_EVENT_METHOD_ENTRY : JVMTI_EVENT_METHOD_EXIT, thr));
}

extern "C" JNIEXPORT void JNICALL
Java_art_SuspendEvents_setupSuspendMethodEventWithCallback(JNIEnv* env,
                                                           [[maybe_unused]] jclass klass,
                                                           jobject method,
                                                           jboolean enter,
                                                           jthread thr,
                                                           jclass target_class,
                                                           jobject callback_method) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data == nullptr) << "Data was not cleared!";
  std::vector<std::string> empty;
  data = SetupTestData(
      env, method, 0, target_class, nullptr, nullptr, 0, callback_method, std::move(empty));
  if (data == nullptr) {
    return;
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
    return;
  }
  JvmtiErrorToException(
      env,
      jvmti_env,
      jvmti_env->SetEventNotificationMode(
          JVMTI_ENABLE, enter ? JVMTI_EVENT_METHOD_ENTRY : JVMTI_EVENT_METHOD_EXIT, thr));
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendMethodEvent(
    JNIEnv* env, [[maybe_unused]] jclass klass , jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_EXIT, thr))) {
    return;
  }
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_ENTRY, thr))) {
    return;
  }
  DeleteTestData(env, thr, data);
}

extern "C" JNIEXPORT void JNICALL
Java_art_SuspendEvents_setupFieldSuspendFor(JNIEnv* env,
                                            [[maybe_unused]] jclass klass,
                                            jclass target_klass,
                                            jobject field,
                                            jboolean access,
                                            jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data == nullptr) << "Data was not cleared!";
  data = SetupTestData(env, nullptr, 0, target_klass, field, nullptr, 0);
  if (data == nullptr) {
    return;
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
    return;
  }
  if (JvmtiErrorToException(env,
                            jvmti_env,
                            jvmti_env->SetEventNotificationMode(
                                JVMTI_ENABLE,
                                access ? JVMTI_EVENT_FIELD_ACCESS : JVMTI_EVENT_FIELD_MODIFICATION,
                                thr))) {
    return;
  }
  if (access) {
    JvmtiErrorToException(
        env, jvmti_env, jvmti_env->SetFieldAccessWatch(data->target_klass, data->target_field));
  } else {
    JvmtiErrorToException(
        env,
        jvmti_env,
        jvmti_env->SetFieldModificationWatch(data->target_klass, data->target_field));
  }
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearFieldSuspendFor(
    JNIEnv* env, [[maybe_unused]] jclass klass , jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_FIELD_ACCESS, thr))) {
    return;
  }
  if (JvmtiErrorToException(env,
                            jvmti_env,
                            jvmti_env->SetEventNotificationMode(
                                JVMTI_DISABLE, JVMTI_EVENT_FIELD_MODIFICATION, thr))) {
    return;
  }
  if (JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->ClearFieldModificationWatch(data->target_klass, data->target_field)) &&
      JvmtiErrorToException(
          env,
          jvmti_env,
          jvmti_env->ClearFieldAccessWatch(data->target_klass, data->target_field))) {
    return;
  } else {
    env->ExceptionClear();
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
    return;
  }
  DeleteTestData(env, thr, data);
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupWaitForNativeCall(
    JNIEnv* env, [[maybe_unused]] jclass klass , jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data == nullptr) << "Data was not cleared!";
  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0);
  if (data == nullptr) {
    return;
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
    return;
  }
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearWaitForNativeCall(
    JNIEnv* env, [[maybe_unused]] jclass klass , jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
    return;
  }
  DeleteTestData(env, thr, data);
}

extern "C" JNIEXPORT void JNICALL
Java_art_SuspendEvents_waitForSuspendHit(JNIEnv* env, [[maybe_unused]] jclass klass, jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  CHECK(data != nullptr);
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(data->notify_monitor))) {
    return;
  }
  while (!data->hit_location) {
    if (JvmtiErrorToException(
            env, jvmti_env, jvmti_env->RawMonitorWait(data->notify_monitor, -1))) {
      return;
    }
  }
  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(data->notify_monitor))) {
    return;
  }
  jint state = 0;
  while (!JvmtiErrorToException(env, jvmti_env, jvmti_env->GetThreadState(thr, &state)) &&
         (state & JVMTI_THREAD_STATE_SUSPENDED) == 0) {
  }
}

extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearTestData(
    JNIEnv* env, [[maybe_unused]] jclass klass , jthread thr) {
  TestData* data;
  if (JvmtiErrorToException(
          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
    return;
  }
  if (data != nullptr) {
    DeleteTestData(env, thr, data);
  }
}

}  // namespace common_suspend_event
}  // namespace art

Messung V0.5 in Prozent
C=91 H=92 G=91

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik