1 /*
   2  * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 #include <string.h>
  25 #include <jvmti.h>
  26 #include "agent_common.h"
  27 #include "jni_tools.h"
  28 #include "jvmti_tools.h"
  29 #include "jvmti_FollowRefObjects.h"
  30 
  31 extern "C" {
  32 
  33 /* ============================================================================= */
  34 
  35 static jlong g_timeout = 0;
  36 
  37 #define JAVA_LANG_STRING_CLASS_NAME "java/lang/String"
  38 #define JAVA_IO_SERIALIZABLE_CLASS_NAME "java/io/Serializable"
  39 #define JAVA_UTIL_CALENDAR_CLASS_NAME "java/util/Calendar"
  40 
  41 static jobject g_jniGlobalRef = 0;
  42 static jweak g_jniWeakGlobalRef = 0;
  43 
  44 static jvmtiHeapCallbacks g_heapCallbacks;
  45 
  46 /* ============================================================================= */
  47 
  48 jint JNICALL heapReferenceCallback(
  49      jvmtiHeapReferenceKind        reference_kind,
  50      const jvmtiHeapReferenceInfo* reference_info,
  51      jlong                         class_tag,
  52      jlong                         referrer_class_tag,
  53      jlong                         size,
  54      jlong*                        tag_ptr,
  55      jlong*                        referrer_tag_ptr,
  56      jint                          length,
  57      void*                         user_data)
  58 {
  59     CHECK_USER_DATA(user_data);
  60 
  61     printHeapRefCallbackInfo(reference_kind, reference_info, class_tag, referrer_class_tag, size, tag_ptr, referrer_tag_ptr, length);
  62 
  63     markTagVisited(DEREF(tag_ptr));
  64     markRefToVerify(DEREF(referrer_tag_ptr), DEREF(tag_ptr), reference_kind);
  65 
  66     return JVMTI_VISIT_OBJECTS;
  67 
  68 } /* heapReferenceCallback */
  69 
  70 
  71 jint JNICALL primitiveFieldCallback(
  72      jvmtiHeapReferenceKind        reference_kind,
  73      const jvmtiHeapReferenceInfo* reference_info,
  74      jlong                         class_tag,
  75      jlong*                        tag_ptr,
  76      jvalue                        value,
  77      jvmtiPrimitiveType            value_type,
  78      void*                         user_data)
  79 {
  80     CHECK_USER_DATA(user_data);
  81 
  82     printf(" primitiveFieldCallback: ref=%s,"
  83                " class_tag=%-3ld, tag=%-3ld, type=%c\n",
  84                g_refKindStr[reference_kind],
  85                (long) class_tag,
  86                (long) DEREF(tag_ptr),
  87                (int ) value_type);
  88 
  89     fflush(0);
  90 
  91     markTagVisited(DEREF(tag_ptr));
  92 
  93     return JVMTI_VISIT_OBJECTS;
  94 
  95 } /* primitiveFieldCallback */
  96 
  97 
  98 jint JNICALL arrayPrimitiveValueCallback(
  99      jlong              class_tag,
 100      jlong              size,
 101      jlong*             tag_ptr,
 102      jint               element_count,
 103      jvmtiPrimitiveType element_type,
 104      const void*        elements,
 105      void*              user_data)
 106 {
 107     CHECK_USER_DATA(user_data);
 108 
 109     printf("    arrayPrimitiveValueCallback: class_tag=%-3ld, tag=%-3ld, len=%d, type=%c\n",
 110            (long) class_tag,
 111            (long) DEREF(tag_ptr),
 112            (int ) element_count,
 113            (int ) element_type);
 114     fflush(0);
 115 
 116     markTagVisited(DEREF(tag_ptr));
 117 
 118     return JVMTI_VISIT_OBJECTS;
 119 
 120 } /* arrayPrimitiveValueCallback */
 121 
 122 
 123 jint JNICALL stringPrimitiveValueCallback(
 124      jlong        class_tag,
 125      jlong        size,
 126      jlong*       tag_ptr,
 127      const jchar* value,
 128      jint         value_length,
 129      void*        user_data)
 130 {
 131     printf("stringPrimitiveValueCallback: class_tag=%-3ld, tag=%-3ld, len=%d\n",
 132            (long) class_tag,
 133            (long) DEREF(tag_ptr),
 134            (int ) value_length);
 135     fflush(0);
 136 
 137     markTagVisited(DEREF(tag_ptr));
 138 
 139     return JVMTI_VISIT_OBJECTS;
 140 
 141 } /* stringPrimitiveValueCallback */
 142 
 143 /* ============================================================================= */
 144 
 145 static void createGlobalRefs(JNIEnv * jni)
 146 {
 147     jclass klass;
 148 
 149     if  ( ! NSK_JNI_VERIFY(jni, (klass = jni->FindClass(JAVA_LANG_STRING_CLASS_NAME)) != NULL) ) {
 150         nsk_jvmti_setFailStatus();
 151         return;
 152     }
 153 
 154     if ( ! NSK_JNI_VERIFY(jni, (g_jniGlobalRef = jni->NewGlobalRef(klass)) != NULL) ) {
 155         nsk_jvmti_setFailStatus();
 156     }
 157 
 158     if ( ! NSK_JNI_VERIFY(jni, (g_jniWeakGlobalRef = jni->NewWeakGlobalRef(klass)) != NULL) ) {
 159         nsk_jvmti_setFailStatus();
 160     }
 161 
 162 } /* createGlobalRefs */
 163 
 164 /** Agent algorithm. */
 165 
 166 static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg)
 167 {
 168     jvmtiError retCode;
 169 
 170     printf(">>> Sync with Java code\n");
 171     fflush(0);
 172 
 173     if (!NSK_VERIFY(nsk_jvmti_waitForSync(g_timeout))) {
 174         return;
 175     }
 176 
 177     printf(">>> Create JNI global references\n");
 178     fflush(0);
 179 
 180     createGlobalRefs(jni);
 181 
 182     retCode = jvmti->FollowReferences((jint) 0,                 /* heap filter */
 183                                       NULL,                     /* class */
 184                                       NULL,                     /* inital object */
 185                                       &g_heapCallbacks,
 186                                       (const void *) &g_fakeUserData);
 187 
 188     if ( ! NSK_VERIFY(retCode == JVMTI_ERROR_NONE) ) {
 189         nsk_jvmti_setFailStatus();
 190     }
 191 
 192     checkThatAllTagsVisited();
 193 
 194     printf(">>> Let debugee to finish\n");
 195     fflush(0);
 196 
 197     if (!NSK_VERIFY(nsk_jvmti_resumeSync())) {
 198         return;
 199     }
 200 
 201 } /* agentProc */
 202 
 203 
 204 /* ============================================================================= */
 205 
 206 /** Agent library initialization. */
 207 
 208 #ifdef STATIC_BUILD
 209 JNIEXPORT jint JNICALL Agent_OnLoad_followref004(JavaVM *jvm, char *options, void *reserved) {
 210     return Agent_Initialize(jvm, options, reserved);
 211 }
 212 JNIEXPORT jint JNICALL Agent_OnAttach_followref004(JavaVM *jvm, char *options, void *reserved) {
 213     return Agent_Initialize(jvm, options, reserved);
 214 }
 215 JNIEXPORT jint JNI_OnLoad_followref004(JavaVM *jvm, char *options, void *reserved) {
 216     return JNI_VERSION_1_8;
 217 }
 218 #endif
 219 jint  Agent_Initialize(JavaVM *jvm, char *options, void *reserved)
 220 {
 221     jvmtiEnv* jvmti = NULL;
 222 
 223     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) {
 224         return JNI_ERR;
 225     }
 226 
 227     g_timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
 228 
 229     if (!NSK_VERIFY((jvmti = nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) {
 230         return JNI_ERR;
 231     }
 232 
 233     /* Setting Heap Callbacks */
 234     memset(&g_heapCallbacks, 0, sizeof(g_heapCallbacks));
 235     g_heapCallbacks.heap_iteration_callback         = NULL;
 236     g_heapCallbacks.heap_reference_callback         = heapReferenceCallback;
 237     g_heapCallbacks.primitive_field_callback        = primitiveFieldCallback;
 238     g_heapCallbacks.array_primitive_value_callback  = arrayPrimitiveValueCallback;
 239     g_heapCallbacks.string_primitive_value_callback = stringPrimitiveValueCallback;
 240 
 241     jvmti_FollowRefObject_init();
 242 
 243     {
 244         jvmtiCapabilities caps;
 245 
 246         memset(&caps, 0, sizeof(caps));
 247         caps.can_tag_objects = 1;
 248         if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) {
 249             return JNI_ERR;
 250         }
 251     }
 252 
 253     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) {
 254         return JNI_ERR;
 255     }
 256 
 257     return JNI_OK;
 258 
 259 } /* Agent_OnLoad */
 260 
 261 
 262 /* ============================================================================= */
 263 
 264 }