text: /*
   * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  
  #include <stdio.h>
  #include <string.h>
  #include "jni_tools.h"
  #include "agent_common.h"
  #include "jvmti_tools.h"
  
  extern "C" {
  
  #define CAPABILITY can_access_local_variables
  #define CAPABILITY_STR "can_access_local_variables"
  
  /* The test checks capability can_access_local_variables
   * and correspondent function:
   *     GetLocalVariableTable
   *     GetLocalObject
   *     GetLocalInt
   *     GetLocalLong
   *     GetLocalFloat
   *     GetLocalDouble
   *     SetLocalObject
   *     SetLocalInt
   *     SetLocalLong
   *     SetLocalFloat
   *     SetLocalDouble
   *
   * Testcases:
   *   1. Check if GetPotentialCapabilities returns the capability
   *   2. Add the capability during Onload phase
   *   3. Check if GetCapabilities returns the capability
   *   4. Relinquish the capability during Onload phase
   *   5. Check if GetCapabilities does not return the capability
   *   6. Add back the capability and check with GetCapabilities
   *   7. Check that only correspondent function work and functions of
   *      other capabilities return JVMTI_ERROR_MUST_POSSESS_CAPABILITY
   *   8. Check if VM exits well with the capability has not been relinquished
   */
  
  /* ========================================================================== */
  
  /* scaffold objects */
  static JNIEnv* jni = NULL;
  static jvmtiEnv *jvmti = NULL;
  static jlong timeout = 0;
  
  /* test objects */
  static jthread thread = NULL;
  static jclass klass = NULL;
  static jmethodID method = NULL;
  static jfieldID field = NULL;
  
  /* ========================================================================== */
  
  static int prepare() {
      const char* THREAD_NAME = "Debuggee Thread";
      jvmtiThreadInfo info;
      jthread *threads = NULL;
      jint threads_count = 0;
      int i;
  
      NSK_DISPLAY0("Prepare: find tested thread\n");
  
      /* get all live threads */
      if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&threads_count, &threads)))
          return NSK_FALSE;
  
      if (!NSK_VERIFY(threads_count > 0 && threads != NULL))
          return NSK_FALSE;
  
      /* find tested thread */
      for (i = 0; i < threads_count; i++) {
          if (!NSK_VERIFY(threads[i] != NULL))
              return NSK_FALSE;
  
          /* get thread information */
          if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(threads[i], &info)))
              return NSK_FALSE;
  
          NSK_DISPLAY3("    thread #%d (%s): %p\n", i, info.name, threads[i]);
  
          /* find by name */
          if (info.name != NULL && (strcmp(info.name, THREAD_NAME) == 0)) {
              thread = threads[i];
          }
      }
  
      /* deallocate threads list */
      if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)threads)))
          return NSK_FALSE;
  
      /* get tested thread class */
      if (!NSK_JNI_VERIFY(jni, (klass = jni->GetObjectClass(thread)) != NULL))
          return NSK_FALSE;
  
      /* get tested thread method 'run' */
      if (!NSK_JNI_VERIFY(jni, (method = jni->GetMethodID(klass, "run", "()V")) != NULL))
          return NSK_FALSE;
  
      /* get tested thread field 'waitingMonitor' */
      if (!NSK_JNI_VERIFY(jni, (field =
              jni->GetFieldID(klass, "waitingMonitor", "Ljava/lang/Object;")) != NULL))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* ========================================================================== */
  
  /* Check "can_suspend" functions
   */
  static int checkSuspend() {
      jvmtiError err;
  
      NSK_DISPLAY0("Checking negative: SuspendThread\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY, jvmti->SuspendThread(thread)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: ResumeThread\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY, jvmti->ResumeThread(thread)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: SuspendThreadList\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->SuspendThreadList(1, &thread, &err)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: ResumeThreadList\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->ResumeThreadList(1, &thread, &err)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_signal_thread" functions
   */
  static int checkSignalThread() {
      const char* THREAD_DEATH_CLASS_NAME = "java/lang/ThreadDeath";
      const char* THREAD_DEATH_CTOR_NAME = "<init>";
      const char* THREAD_DEATH_CTOR_SIGNATURE = "()V";
      jclass cls = NULL;
      jmethodID ctor = NULL;
      jobject exception = NULL;
  
      if (!NSK_JNI_VERIFY(jni, (cls = jni->FindClass(THREAD_DEATH_CLASS_NAME)) != NULL))
          return NSK_FALSE;
  
      if (!NSK_JNI_VERIFY(jni, (ctor =
              jni->GetMethodID(cls, THREAD_DEATH_CTOR_NAME, THREAD_DEATH_CTOR_SIGNATURE)) != NULL))
          return NSK_FALSE;
  
      if (!NSK_JNI_VERIFY(jni, (exception = jni->NewObject(cls, ctor)) != NULL))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: StopThread\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->StopThread(thread, exception)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: InterruptThread\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY, jvmti->InterruptThread(thread)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_get_owned_monitor_info" function
   */
  static int checkGetOwnedMonitorInfo() {
      jint count;
      jobject *monitors = NULL;
  
      NSK_DISPLAY0("Checking negative: GetOwnedMonitorInfo\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetOwnedMonitorInfo(thread, &count, &monitors)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_get_current_contended_monitor" function
   */
  static int checkGetCurrentContendedMonitor() {
      jobject monitor = NULL;
  
      NSK_DISPLAY0("Checking negative: GetCurrentContendedMonitor\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetCurrentContendedMonitor(thread, &monitor)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_pop_frame" function
   */
  static int checkPopFrame() {
      NSK_DISPLAY0("Checking negative: PopFrame\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY, jvmti->PopFrame(thread)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_tag_objects" functions
   */
  
  static jvmtiIterationControl JNICALL
  HeapObject(jlong class_tag, jlong size, jlong *tag_ptr, void *user_data) {
      return JVMTI_ITERATION_ABORT;
  }
  
  static jvmtiIterationControl JNICALL
  HeapRoot(jvmtiHeapRootKind root_kind, jlong class_tag, jlong size,
          jlong *tag_ptr, void *user_data) {
      return JVMTI_ITERATION_ABORT;
  }
  
  static jvmtiIterationControl JNICALL
  StackReference(jvmtiHeapRootKind root_kind, jlong class_tag, jlong size,
          jlong *tag_ptr, jlong thread_tag, jint depth, jmethodID method,
          jint slot, void *user_data) {
      return JVMTI_ITERATION_ABORT;
  }
  
  static jvmtiIterationControl JNICALL
  ObjectReference(jvmtiObjectReferenceKind reference_kind, jlong class_tag,
          jlong size, jlong *tag_ptr, jlong referrer_tag,
          jint referrer_index, void *user_data) {
      return JVMTI_ITERATION_ABORT;
  }
  
  static int checkHeapFunctions() {
      const jlong TAG_VALUE = (123456789L);
      jlong tag;
      jint count;
      jobject *res_objects = NULL;
      jlong *res_tags = NULL;
      jint dummy_user_data = 0;
  
      NSK_DISPLAY0("Checking negative: SetTag\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->SetTag(thread, TAG_VALUE)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: GetTag\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY, jvmti->GetTag(thread, &tag)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: GetObjectsWithTags\n");
      tag = TAG_VALUE;
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetObjectsWithTags(1, &tag, &count, &res_objects, &res_tags)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: IterateOverHeap\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->IterateOverHeap(JVMTI_HEAP_OBJECT_TAGGED, HeapObject, &dummy_user_data)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: IterateOverInstancesOfClass\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->IterateOverInstancesOfClass(klass,
                                                 JVMTI_HEAP_OBJECT_UNTAGGED,
                                                 HeapObject,
                                                 &dummy_user_data)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: IterateOverObjectsReachableFromObject\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->IterateOverObjectsReachableFromObject(thread,
                                                           ObjectReference,
                                                           &dummy_user_data)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: IterateOverReachableObjects\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->IterateOverReachableObjects(HeapRoot,
                                                 StackReference,
                                                 ObjectReference,
                                                 &dummy_user_data)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_access_local_variables" functions
   */
  static int checkLocalVariableFunctions() {
      jint count;
      jvmtiLocalVariableEntry *local_variable_table = NULL;
      jobject object_value;
      jint int_value;
      jlong long_value;
      jfloat float_value;
      jdouble double_value;
      int i;
  
  /* DEBUG -- while thread should be suspended
      jvmtiCapabilities caps;
  */
  
      NSK_DISPLAY0("Checking positive: GetLocalVariableTable\n");
      if (!NSK_JVMTI_VERIFY(jvmti->GetLocalVariableTable(method, &count, &local_variable_table)))
          return NSK_FALSE;
  
  /* DEBUG -- while thread should be suspended
      memset(&caps, 0, sizeof(caps));
      caps.can_suspend = 1;
      if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
          return JNI_ERR;
      if (!NSK_JVMTI_VERIFY(jvmti->SuspendThread(thread)))
          return NSK_FALSE;
  */
  
      for (i = 0; i < count; i++) {
          if (strcmp(local_variable_table[i].name, "o") == 0) {
              NSK_DISPLAY0("Checking positive: GetLocalObject\n");
              if (!NSK_JVMTI_VERIFY(
                      jvmti->GetLocalObject(thread, 1, local_variable_table[i].slot, &object_value)))
                  return NSK_FALSE;
  
              NSK_DISPLAY0("Checking positive: SetLocalObject\n");
              if (!NSK_JVMTI_VERIFY(
                      jvmti->SetLocalObject(thread, 1, local_variable_table[i].slot, object_value)))
                  return NSK_FALSE;
          } else if (strcmp(local_variable_table[i].name, "i") == 0) {
              NSK_DISPLAY0("Checking positive: GetLocalInt\n");
              if (!NSK_JVMTI_VERIFY(
                      jvmti->GetLocalInt(thread, 1, local_variable_table[i].slot, &int_value)))
                  return NSK_FALSE;
  
              NSK_DISPLAY0("Checking positive: SetLocalInt\n");
              if (!NSK_JVMTI_VERIFY(
                      jvmti->SetLocalInt(thread, 1, local_variable_table[i].slot, int_value)))
                  return NSK_FALSE;
          } else if (strcmp(local_variable_table[i].name, "l") == 0) {
              NSK_DISPLAY0("Checking positive: GetLocalLong\n");
              if (!NSK_JVMTI_VERIFY(
                      jvmti->GetLocalLong(thread, 1, local_variable_table[i].slot, &long_value)))
                  return NSK_FALSE;
  
              NSK_DISPLAY0("Checking positive: SetLocalLong\n");
              if (!NSK_JVMTI_VERIFY(
                      jvmti->SetLocalLong(thread, 1, local_variable_table[i].slot, long_value)))
                  return NSK_FALSE;
          } else if (strcmp(local_variable_table[i].name, "f") == 0) {
              NSK_DISPLAY0("Checking positive: GetLocalFloat\n");
              if (!NSK_JVMTI_VERIFY(
                      jvmti->GetLocalFloat(thread, 1, local_variable_table[i].slot, &float_value)))
                  return NSK_FALSE;
  
              NSK_DISPLAY0("Checking positive: SetLocalFloat\n");
              if (!NSK_JVMTI_VERIFY(
                      jvmti->SetLocalFloat(thread, 1, local_variable_table[i].slot, float_value)))
                  return NSK_FALSE;
          } else if (strcmp(local_variable_table[i].name, "d") == 0) {
              NSK_DISPLAY0("Checking positive: GetLocalDouble\n");
              if (!NSK_JVMTI_VERIFY(
                      jvmti->GetLocalDouble(thread, 1, local_variable_table[i].slot, &double_value)))
                  return NSK_FALSE;
  
              NSK_DISPLAY0("Checking positive: SetLocalDouble\n");
              if (!NSK_JVMTI_VERIFY(
                      jvmti->SetLocalDouble(thread, 1, local_variable_table[i].slot, double_value)))
                  return NSK_FALSE;
          }
      }
  
  /* DEBUG -- while thread should be suspended
      if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(thread)))
          return NSK_FALSE;
      if (!NSK_JVMTI_VERIFY(jvmti->RelinquishCapabilities(&caps)))
          return JNI_ERR;
  */
  
      if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)local_variable_table)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_get_source_info" functions
   */
  static int checkSourceInfoFunctions() {
      char *name;
      jint count;
      jvmtiLineNumberEntry *line_number_table = NULL;
  
      NSK_DISPLAY0("Checking negative: GetSourceFileName\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetSourceFileName(klass, &name)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: GetSourceDebugExtension\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetSourceDebugExtension(klass, &name)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: GetLineNumberTable\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetLineNumberTable(method, &count, &line_number_table)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_redefine_classes" functions
   */
  static int checkRedefineClasses() {
      jvmtiClassDefinition class_def;
  
      NSK_DISPLAY0("Checking negative: RedefineClasses\n");
      class_def.klass = klass;
      class_def.class_byte_count = 0;
      class_def.class_bytes = NULL;
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->RedefineClasses(1, &class_def)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_get_monitor_info" function
   */
  static int checkGetObjectMonitorUsage() {
      jvmtiMonitorUsage monitor_info;
  
      NSK_DISPLAY0("Checking negative: GetObjectMonitorUsage\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetObjectMonitorUsage(thread, &monitor_info)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_get_synthetic_attribute" functions
   */
  static int checkIsSyntheticFunctions() {
      jboolean is_synthetic;
  
      NSK_DISPLAY0("Checking negative: IsFieldSynthetic\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->IsFieldSynthetic(klass, field, &is_synthetic)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: IsMethodSynthetic\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->IsMethodSynthetic(method, &is_synthetic)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_get_bytecodes" function
   */
  static int checkGetBytecodes() {
      jint count;
      unsigned char *bytecodes;
  
      NSK_DISPLAY0("Checking negative: GetBytecodes\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetBytecodes(method, &count, &bytecodes)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_get_current_thread_cpu_time" function
   */
  static int checkGetCurrentThreadCpuTime() {
      jvmtiTimerInfo info;
      jlong nanos;
  
      NSK_DISPLAY0("Checking negative: GetCurrentThreadCpuTimerInfo\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetCurrentThreadCpuTimerInfo(&info)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: GetCurrentThreadCpuTime\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetCurrentThreadCpuTime(&nanos)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* Check "can_get_thread_cpu_time" function
   */
  static int checkGetThreadCpuTime() {
      jvmtiTimerInfo info;
      jlong nanos;
  
      NSK_DISPLAY0("Checking negative: GetThreadCpuTimerInfo\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetThreadCpuTimerInfo(&info)))
          return NSK_FALSE;
  
      NSK_DISPLAY0("Checking negative: GetThreadCpuTime\n");
      if (!NSK_JVMTI_VERIFY_CODE(JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
              jvmti->GetThreadCpuTime(thread, &nanos)))
          return NSK_FALSE;
  
      return NSK_TRUE;
  }
  
  /* ========================================================================== */
  
  /* agent algorithm */
  static void JNICALL
  agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
      jni = agentJNI;
  
      /* wait for initial sync */
      if (!nsk_jvmti_waitForSync(timeout))
          return;
  
      if (!prepare()) {
          nsk_jvmti_setFailStatus();
          return;
      }
  
      /* testcase #7: check that only correspondent function work */
      NSK_DISPLAY0("Testcase #7: check that only correspondent function work but not others\n");
      if (!checkSuspend())
          nsk_jvmti_setFailStatus();
      if (!checkSignalThread())
          nsk_jvmti_setFailStatus();
      if (!checkGetOwnedMonitorInfo())
          nsk_jvmti_setFailStatus();
      if (!checkGetCurrentContendedMonitor())
          nsk_jvmti_setFailStatus();
      if (!checkPopFrame())
          nsk_jvmti_setFailStatus();
      if (!checkHeapFunctions())
          nsk_jvmti_setFailStatus();
      if (!checkLocalVariableFunctions())
          nsk_jvmti_setFailStatus();
      if (!checkSourceInfoFunctions())
          nsk_jvmti_setFailStatus();
      if (!checkRedefineClasses())
          nsk_jvmti_setFailStatus();
      if (!checkGetObjectMonitorUsage())
          nsk_jvmti_setFailStatus();
      if (!checkIsSyntheticFunctions())
          nsk_jvmti_setFailStatus();
      if (!checkGetBytecodes())
          nsk_jvmti_setFailStatus();
      if (!checkGetCurrentThreadCpuTime())
          nsk_jvmti_setFailStatus();
      if (!checkGetThreadCpuTime())
          nsk_jvmti_setFailStatus();
  
      /* testcase #8: exits with the capability has not been relinquished */
      NSK_DISPLAY0("Testcase #8: check if VM exits well with the capability has not been relinquished\n");
  
      /* resume debugee after last sync */
      if (!nsk_jvmti_resumeSync())
          return;
  }
  
  /* ========================================================================== */
  
  /* agent library initialization */
  #ifdef STATIC_BUILD
  JNIEXPORT jint JNICALL Agent_OnLoad_cm01t011(JavaVM *jvm, char *options, void *reserved) {
      return Agent_Initialize(jvm, options, reserved);
  }
  JNIEXPORT jint JNICALL Agent_OnAttach_cm01t011(JavaVM *jvm, char *options, void *reserved) {
      return Agent_Initialize(jvm, options, reserved);
  }
  JNIEXPORT jint JNI_OnLoad_cm01t011(JavaVM *jvm, char *options, void *reserved) {
      return JNI_VERSION_1_8;
  }
  #endif
  jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
      jvmtiCapabilities caps;
  
      /* init framework and parse options */
      if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
          return JNI_ERR;
  
      timeout = nsk_jvmti_getWaitTime() * 60000;
      NSK_DISPLAY1("Timeout: %d msc\n", (int)timeout);
  
      /* create JVMTI environment */
      if (!NSK_VERIFY((jvmti =
              nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
          return JNI_ERR;
  
      /* register agent proc and arg */
      if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
          return JNI_ERR;
  
      /* testcase #1: check GetPotentialCapabilities */
      NSK_DISPLAY0("Testcase #1: check if GetPotentialCapabilities returns the capability\n");
      if (!NSK_JVMTI_VERIFY(jvmti->GetPotentialCapabilities(&caps)))
          return JNI_ERR;
      if (!caps.CAPABILITY) {
          NSK_COMPLAIN1("GetPotentialCapabilities does not return \"%s\" capability\n",
              CAPABILITY_STR);
          return JNI_ERR;
      }
  
      /* testcase #2: add the capability during Onload phase */
      NSK_DISPLAY0("Testcase #2: add the capability during Onload phase\n");
      memset(&caps, 0, sizeof(caps));
      caps.CAPABILITY = 1;
      if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
          return JNI_ERR;
  
      /* testcase #3: check if GetCapabilities returns the capability */
      NSK_DISPLAY0("Testcase #3: check if GetCapabilities returns the capability\n");
      memset(&caps, 0, sizeof(caps));
      if (!NSK_JVMTI_VERIFY(jvmti->GetCapabilities(&caps)))
          return JNI_ERR;
      if (!caps.CAPABILITY) {
          NSK_COMPLAIN1("GetCapabilities does not return \"%s\" capability\n",
              CAPABILITY_STR);
          return JNI_ERR;
      }
  
      /* testcase #4: relinquish the capability during Onload phase */
      NSK_DISPLAY0("Testcase #4: relinquish the capability during Onload phase\n");
      memset(&caps, 0, sizeof(caps));
      caps.CAPABILITY = 1;
      if (!NSK_JVMTI_VERIFY(jvmti->RelinquishCapabilities(&caps)))
          return JNI_ERR;
  
      /* testcase #5: check if GetCapabilities does not return the capability */
      NSK_DISPLAY0("Testcase #5: check if GetCapabilities does not return the capability\n");
      memset(&caps, 0, sizeof(caps));
      if (!NSK_JVMTI_VERIFY(jvmti->GetCapabilities(&caps)))
          return JNI_ERR;
      if (caps.CAPABILITY) {
          NSK_COMPLAIN1("GetCapabilities returns relinquished \"%s\" capability\n",
              CAPABILITY_STR);
          return JNI_ERR;
      }
  
      /* testcase #6: add back the capability and check with GetCapabilities */
      NSK_DISPLAY0("Testcase #6: add back the capability and check with GetCapabilities\n");
      memset(&caps, 0, sizeof(caps));
      caps.CAPABILITY = 1;
      if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
          return JNI_ERR;
      memset(&caps, 0, sizeof(caps));
      if (!NSK_JVMTI_VERIFY(jvmti->GetCapabilities(&caps)))
          return JNI_ERR;
      if (!caps.CAPABILITY) {
          NSK_COMPLAIN1("GetCapabilities does not return \"%s\" capability\n",
              CAPABILITY_STR);
          return JNI_ERR;
      }
  
      return JNI_OK;
  }
  
  /* ========================================================================== */
  
  }
  