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 <stdint.h>
  26 #include "jvmti.h"
  27 #include "agent_common.h"
  28 #include "jni_tools.h"
  29 #include "jvmti_tools.h"
  30 
  31 extern "C" {
  32 
  33 /* ============================================================================= */
  34 
  35 static jlong timeout = 0;
  36 
  37 #define DEBUGEE_CLASS_NAME      "nsk/jvmti/unit/FollowReferences/followref001"
  38 #define ROOT_OBJECT_CLASS_NAME  "nsk/jvmti/unit/FollowReferences/followref001RootTestedClass"
  39 #define ROOT_OBJECT_CLASS_SIG   "L" ROOT_OBJECT_CLASS_NAME ";"
  40 #define CHAIN_OBJECT_CLASS_NAME "nsk/jvmti/unit/FollowReferences/followref001TestedClass"
  41 #define CHAIN_OBJECT_CLASS_SIG  "L" CHAIN_OBJECT_CLASS_NAME ";"
  42 
  43 #define OBJECT_FIELD_NAME               "rootObject"
  44 #define REACHABLE_CHAIN_FIELD_NAME      "reachableChain"
  45 #define UNREACHABLE_CHAIN_FIELD_NAME    "unreachableChain"
  46 #define NEXT_FIELD_NAME                 "next"
  47 
  48 
  49 #define DEFAULT_CHAIN_LENGTH 3
  50 #define FULL_32_BIT_MASK     0xFFFFFFFF
  51 
  52 typedef struct ObjectDescStruct {
  53     jlong tag;           /* Tag of the object */
  54     jlong exp_class_tag; /* Expected tag of the object class */
  55     jlong class_tag;     /* Reported tag of the object class */
  56     jint  exp_found;     /* Expected number of iterations through the object */
  57     jint  found;         /* Reported number of iterations through the object */
  58 } ObjectDesc;
  59 
  60 static int chainLength   = 0;
  61 static int objectsCount  = 0;
  62 static int fakeUserData  = 0;
  63 static int userDataError = 0;
  64 
  65 static ObjectDesc* objectDescList = NULL;
  66 
  67 static const jlong ROOT_CLASS_TAG   = 9;
  68 static const jlong CHAIN_CLASS_TAG  = 99;
  69 static const jlong ROOT_OBJECT_TAG  = 10;
  70 static const jlong CHAIN_OBJECT_TAG = 100;
  71 
  72 static jvmtiHeapCallbacks heapCallbacks;
  73 
  74 /* This array has to be up-to-date with the jvmtiHeapReferenceKind enum */
  75 static const char* ref_kind_str[28] = {
  76    "unknown_0",
  77    "JVMTI_HEAP_REFERENCE_CLASS",
  78    "JVMTI_HEAP_REFERENCE_FIELD",
  79    "JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT",
  80    "JVMTI_HEAP_REFERENCE_CLASS_LOADER",
  81    "JVMTI_HEAP_REFERENCE_SIGNERS",
  82    "JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN",
  83    "JVMTI_HEAP_REFERENCE_INTERFACE",
  84    "JVMTI_HEAP_REFERENCE_STATIC_FIELD",
  85    "JVMTI_HEAP_REFERENCE_CONSTANT_POOL",
  86    "JVMTI_HEAP_REFERENCE_SUPERCLASS",
  87    "unknown_11", "unknown_12", "unknown_13", "unknown_14", "unknown_15",
  88    "unknown_16", "unknown_17", "unknown_18", "unknown_19", "unknown_20",
  89    "JVMTI_HEAP_REFERENCE_JNI_GLOBAL",
  90    "JVMTI_HEAP_REFERENCE_SYSTEM_CLASS",
  91    "JVMTI_HEAP_REFERENCE_MONITOR",
  92    "JVMTI_HEAP_REFERENCE_STACK_LOCAL",
  93    "JVMTI_HEAP_REFERENCE_JNI_LOCAL",
  94    "JVMTI_HEAP_REFERENCE_THREAD",
  95    "JVMTI_HEAP_REFERENCE_OTHER"
  96 };
  97 
  98 #define DEREF(ptr) (((ptr) == NULL ? 0 : *(ptr)))
  99 
 100 
 101 /* ============================================================================= */
 102 
 103 static int get_reference_index(jvmtiHeapReferenceKind   reference_kind,
 104                                const jvmtiHeapReferenceInfo* reference_info)
 105 {
 106     int referrer_index = 0;
 107 
 108     switch (reference_kind) {
 109         case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
 110             referrer_index = reference_info->constant_pool.index;
 111             break;
 112         case JVMTI_HEAP_REFERENCE_FIELD:
 113         case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
 114             referrer_index = reference_info->field.index;
 115             break;
 116         case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
 117             referrer_index = reference_info->array.index;
 118             break;
 119         case JVMTI_HEAP_REFERENCE_STACK_LOCAL:
 120             referrer_index = reference_info->stack_local.slot;
 121             /* Fall through */
 122         case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
 123             referrer_index |= reference_info->stack_local.depth << 16;
 124             break;
 125         default:
 126             // TODO: check that realy should be done w/ other jvmtiHeapReferenceKind
 127             break;
 128     }
 129 
 130     return referrer_index;
 131 } /* get_reference_index */
 132 
 133 
 134 /** Initialize objectDescList. */
 135 static int initObjectDescList(jvmtiEnv*    jvmti,
 136                               int          chainLength,
 137                               int*         objectsCount,
 138                               ObjectDesc** objectDescList)
 139 {
 140     /* root object + reachable and unreachable object chains */
 141     *objectsCount = 1 + 2 * chainLength;
 142 
 143     printf("Allocate memory for objects list: %d objects\n", *objectsCount);
 144     fflush(0);
 145     if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)),
 146                                           (unsigned char**) objectDescList))) {
 147         nsk_jvmti_setFailStatus();
 148         return NSK_FALSE;
 149     }
 150     printf("  ... allocated array: 0x%p\n", (void*)objectDescList);
 151     fflush(0);
 152 
 153     {
 154         int k;
 155         for (k = 0; k < *objectsCount; k++) {
 156             (*objectDescList)[k].tag = 0;
 157             (*objectDescList)[k].exp_class_tag = CHAIN_CLASS_TAG;
 158             (*objectDescList)[k].exp_found = 0;
 159             (*objectDescList)[k].found = 0;
 160         }
 161     }
 162     (*objectDescList)[0].exp_class_tag = ROOT_CLASS_TAG;
 163     (*objectDescList)[0].tag           = ROOT_OBJECT_TAG;
 164 
 165     /* Object with tag=100 must be referenced 2 times */
 166     (*objectDescList)[chainLength].exp_found = 1;
 167 
 168 
 169      return NSK_TRUE;
 170 } /* initObjectDescList */
 171 
 172 
 173 /** Find and tag classes. */
 174 static int getAndTagClasses(jvmtiEnv*    jvmti,
 175                             JNIEnv*      jni,
 176                             jclass*      debugeeClass,
 177                             jclass*      rootObjectClass,
 178                             jclass*      chainObjectClass)
 179 {
 180 
 181     if (!NSK_JNI_VERIFY(jni, (*debugeeClass = jni->FindClass(DEBUGEE_CLASS_NAME)) != NULL)) {
 182         nsk_jvmti_setFailStatus();
 183         return NSK_FALSE;
 184     }
 185     printf("\nFound debugee class: 0x%p\n  %s\n",
 186            (void*) *debugeeClass, DEBUGEE_CLASS_NAME);
 187     fflush(0);
 188 
 189     if (!NSK_JNI_VERIFY(jni, (*rootObjectClass =
 190             jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != NULL)) {
 191         nsk_jvmti_setFailStatus();
 192         return NSK_FALSE;
 193     }
 194 
 195     if (!NSK_JVMTI_VERIFY(jvmti->SetTag(*rootObjectClass, ROOT_CLASS_TAG))) {
 196         nsk_jvmti_setFailStatus();
 197     }
 198 
 199     printf("\nFound root object class: 0x%p, tag=%ld\n  %s\n",
 200            (void*) *rootObjectClass,(long) ROOT_CLASS_TAG,
 201            ROOT_OBJECT_CLASS_NAME);
 202     fflush(0);
 203 
 204 
 205     if (!NSK_JNI_VERIFY(jni, (*chainObjectClass =
 206             jni->FindClass(CHAIN_OBJECT_CLASS_NAME)) != NULL)) {
 207         nsk_jvmti_setFailStatus();
 208         return NSK_FALSE;
 209     }
 210 
 211     if (!NSK_JVMTI_VERIFY(jvmti->SetTag(*chainObjectClass, CHAIN_CLASS_TAG))) {
 212         nsk_jvmti_setFailStatus();
 213     }
 214     printf("\nFound chain object class: 0x%p, tag=%ld\n  %s\n",
 215            (void*) *chainObjectClass, (long) CHAIN_CLASS_TAG,
 216            CHAIN_OBJECT_CLASS_NAME);
 217     fflush(0);
 218 
 219      return NSK_TRUE;
 220 } /* getAndTagClasses */
 221 
 222 
 223 /** Obtain chain of tested objects and tag them recursively. */
 224 static int getFieldsAndObjects(jvmtiEnv*  jvmti,
 225                              JNIEnv*     jni,
 226                              jclass      debugeeClass,
 227                              jclass      rootObjectClass,
 228                              jclass      chainObjectClass,
 229                              jobject*    rootObjectPtr,
 230                              jfieldID*   reachableChainField,
 231                              jfieldID*   unreachableChainField,
 232                              jfieldID*   nextField)
 233 {
 234     jfieldID rootObjectField = NULL;
 235 
 236     if (!NSK_JNI_VERIFY(jni, (rootObjectField =
 237             jni->GetStaticFieldID(debugeeClass, OBJECT_FIELD_NAME, ROOT_OBJECT_CLASS_SIG)) != NULL)) {
 238         nsk_jvmti_setFailStatus();
 239         return NSK_FALSE;
 240     }
 241     printf("\nFound fieldID: 0x%p - \'%s\' static field in debugee class\n",
 242            (void*) rootObjectField, OBJECT_FIELD_NAME);
 243     fflush(0);
 244 
 245     if (!NSK_JNI_VERIFY(jni, (*reachableChainField =
 246             jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
 247         nsk_jvmti_setFailStatus();
 248         return NSK_FALSE;
 249     }
 250     printf("\nFound fieldID: 0x%p - \'%s\' field in root object class\n",
 251            (void*) reachableChainField, REACHABLE_CHAIN_FIELD_NAME);
 252     fflush(0);
 253 
 254     if (!NSK_JNI_VERIFY(jni, (*unreachableChainField =
 255             jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
 256         nsk_jvmti_setFailStatus();
 257         return NSK_FALSE;
 258     }
 259 
 260     printf("\nFound fieldID: 0x%p - \'%s\' field in root object class\n",
 261            (void*) unreachableChainField, UNREACHABLE_CHAIN_FIELD_NAME);
 262     fflush(0);
 263 
 264     if (!NSK_JNI_VERIFY(jni, (*nextField =
 265             jni->GetFieldID(chainObjectClass, NEXT_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
 266         nsk_jvmti_setFailStatus();
 267         return NSK_FALSE;
 268     }
 269     printf("\nFound fieldID: 0x%p - \'%s\' field in chain object class\n",
 270            (void*) nextField, NEXT_FIELD_NAME);
 271     fflush(0);
 272 
 273     if (!NSK_JNI_VERIFY(jni, (*rootObjectPtr =
 274             jni->GetStaticObjectField(debugeeClass, rootObjectField)) != NULL)) {
 275         nsk_jvmti_setFailStatus();
 276         return NSK_FALSE;
 277     }
 278     printf("\nFound root object: 0x%p\n", (void*) *rootObjectPtr);
 279     fflush(0);
 280 
 281     if (!NSK_JNI_VERIFY(jni, (*rootObjectPtr = jni->NewGlobalRef(*rootObjectPtr)) != NULL)) {
 282         nsk_jvmti_setFailStatus();
 283         return NSK_FALSE;
 284     }
 285     printf("Created root object global ref: 0x%p\n", (void*)*rootObjectPtr);
 286     fflush(0);
 287 
 288      return NSK_TRUE;
 289 } /* getFieldsAndObjects */
 290 
 291 
 292 /** Obtain chain of tested objects and tag them recursively. */
 293 static int getAndTagChainObjects(
 294     jvmtiEnv*  jvmti,
 295     JNIEnv*    jni,
 296     jobject    currObj,
 297     jfieldID   refField,
 298     jfieldID   nextField,
 299     int        count,
 300     ObjectDesc objectDescList[],
 301     jlong      tag,
 302     int        reachable)
 303 {
 304     jobject nextObj = NULL;
 305     jlong objTag = (reachable ? tag : -tag);
 306 
 307     if (count <= 0) {
 308         return NSK_TRUE;
 309     }
 310 
 311     count--;
 312     tag++;
 313 
 314     if (!NSK_JNI_VERIFY(jni, (nextObj = jni->GetObjectField(currObj, refField)) != NULL)) {
 315         nsk_jvmti_setFailStatus();
 316         return NSK_FALSE;
 317     }
 318 
 319     objectDescList[count].tag = objTag;
 320     if (reachable) {
 321         objectDescList[count].exp_found++;
 322     }
 323 
 324     if (!NSK_JVMTI_VERIFY(jvmti->SetTag(nextObj, objTag))) {
 325         nsk_jvmti_setFailStatus();
 326     }
 327     printf("        tag=%-5ld object=0x%p\n", (long)objTag, (void*)nextObj);
 328     fflush(0);
 329 
 330     /* To continue traversing objects in the chain */
 331     if (!getAndTagChainObjects(jvmti,
 332                                jni,
 333                                nextObj,
 334                                nextField,
 335                                nextField,
 336                                count,
 337                                objectDescList,
 338                                tag,
 339                                reachable)
 340     ) {
 341         return NSK_FALSE;
 342     }
 343 
 344     NSK_TRACE(jni->DeleteLocalRef(nextObj));
 345 
 346     return NSK_TRUE;
 347 } /* getAndTagChainObjects */
 348 
 349 /** Obtain all tested objects from debugee class and tag them recursively. */
 350 static int getAndTagTestedObjects(
 351     jvmtiEnv*    jvmti,
 352     JNIEnv*      jni,
 353     int          chainLength,
 354     int*         objectsCount,
 355     ObjectDesc** objectDescList,
 356     jobject*     rootObjectPtr)
 357 {
 358     jclass   debugeeClass          = NULL;
 359     jclass   rootObjectClass       = NULL;
 360     jclass   chainObjectClass      = NULL;
 361 
 362     jfieldID reachableChainField   = NULL;
 363     jfieldID unreachableChainField = NULL;
 364     jfieldID nextField             = NULL;
 365 
 366     if (initObjectDescList(jvmti,
 367                            chainLength,
 368                            objectsCount,
 369                            objectDescList) == NSK_FALSE) {
 370         return NSK_FALSE;
 371     }
 372 
 373     if (getAndTagClasses(jvmti,
 374                          jni,
 375                          &debugeeClass,
 376                          &rootObjectClass,
 377                          &chainObjectClass) == NSK_FALSE) {
 378         return NSK_FALSE;
 379     }
 380 
 381     if (getFieldsAndObjects(jvmti,
 382                             jni,
 383                             debugeeClass,
 384                             rootObjectClass,
 385                             chainObjectClass,
 386                             rootObjectPtr,
 387                             &reachableChainField,
 388                             &unreachableChainField,
 389                             &nextField) == NSK_FALSE) {
 390         return NSK_FALSE;
 391     }
 392 
 393     printf("\nObtain and tag chain objects:\n");
 394     printf("    root tested object:\n");
 395 
 396     if (!NSK_JVMTI_VERIFY(jvmti->SetTag(*rootObjectPtr, ROOT_OBJECT_TAG))
 397     ) {
 398         nsk_jvmti_setFailStatus();
 399     }
 400     printf("        tag=%-5ld  object = 0x%p\n",
 401            (long) ROOT_OBJECT_TAG, (void*) *rootObjectPtr);
 402 
 403     printf("    reachable objects chain: %d objects\n", chainLength);
 404     fflush(0);
 405 
 406     if (!getAndTagChainObjects(jvmti,
 407                                jni,
 408                                *rootObjectPtr,
 409                                reachableChainField,
 410                                nextField,
 411                                chainLength,
 412                                (*objectDescList) + 1,
 413                                CHAIN_OBJECT_TAG,
 414                                NSK_TRUE)  /* reachable objects */
 415     ) {
 416         nsk_jvmti_setFailStatus();
 417         return NSK_FALSE;
 418     }
 419 
 420     printf("    unreachable objects chain: %d objects\n", chainLength);
 421     if (!getAndTagChainObjects(jvmti,
 422                                jni,
 423                                *rootObjectPtr,
 424                                unreachableChainField,
 425                                nextField,
 426                                chainLength,
 427                                (*objectDescList) + 1 + chainLength,
 428                                CHAIN_OBJECT_TAG,
 429                                NSK_FALSE) /* unreachable objects */
 430     ) {
 431         nsk_jvmti_setFailStatus();
 432         return NSK_FALSE;
 433     }
 434 
 435     return NSK_TRUE;
 436 } /* getAndTagTestedObjects */
 437 
 438 /** Check if tagged objects were iterated. */
 439 static int checkTestedObjects(jvmtiEnv*  jvmti,
 440                               JNIEnv*    jni,
 441                               int        chainLength,
 442                               ObjectDesc objectDescList[])
 443 {
 444     int success = NSK_TRUE;
 445     int i, idx;
 446 
 447     printf("Following tagged objects were iterated:\n");
 448 
 449     printf("Root tested object:\n");
 450     printf("   tag:                 %ld\n"
 451            "   expected to iterate: %d times\n"
 452            "   iterated:            %d times\n",
 453            (long) objectDescList[0].tag,
 454                   objectDescList[0].exp_found,
 455                   objectDescList[0].found);
 456     if (objectDescList[0].found != objectDescList[0].exp_found) {
 457         NSK_COMPLAIN1("Root tested object unexpectedly iterated %d times\n",
 458                       objectDescList[0].found);
 459         nsk_jvmti_setFailStatus();
 460     }
 461 
 462     printf("\nReachable objects:\n");
 463     fflush(0);
 464     for (i = 0; i < chainLength; i++) {
 465         idx = i + 1;
 466         printf("Reachable object:\n"
 467                "   tag:                 %-3ld\n"
 468                "   expected to iterate: %d times\n"
 469                "   iterated:            %d times\n",
 470                 (long) objectDescList[idx].tag,
 471                        objectDescList[idx].exp_found,
 472                        objectDescList[idx].found);
 473         if (objectDescList[i + 1].found <= 0) {
 474             NSK_COMPLAIN0("Reachable object was not iterated\n");
 475             nsk_jvmti_setFailStatus();
 476         }
 477         if (objectDescList[idx].found != objectDescList[idx].exp_found) {
 478             NSK_COMPLAIN0("Reachable object was iterated unexpected number of times\n");
 479             nsk_jvmti_setFailStatus();
 480         }
 481     }
 482 
 483     printf("\nUnreachable objects:\n");
 484     for (i = 0; i < chainLength; i++) {
 485         idx = i + 1 + chainLength;
 486 
 487         printf("Unreachable object:\n"
 488                "   tag:                 %ld\n"
 489                "   expected to iterate: %d times\n"
 490                "   iterated:            %d times\n",
 491                 (long) objectDescList[idx].tag,
 492                        objectDescList[idx].exp_found,
 493                        objectDescList[idx].found);
 494         if (objectDescList[idx].found > 0) {
 495             NSK_COMPLAIN0("Unreachable object was iterated\n");
 496             nsk_jvmti_setFailStatus();
 497         }
 498         fflush(0);
 499     }
 500 
 501     return NSK_TRUE;
 502 } /* checkTestedObjects */
 503 
 504 
 505 /** Release references to the tested objects and free allocated memory. */
 506 static int releaseTestedObjects(jvmtiEnv*   jvmti,
 507                                 JNIEnv*     jni,
 508                                 int         chainLength,
 509                                 ObjectDesc* objectDescList,
 510                                 jobject     rootObject)
 511 {
 512     if (rootObject != NULL) {
 513         printf("Release object reference to root tested object: 0x%p\n", rootObject);
 514         NSK_TRACE(jni->DeleteGlobalRef(rootObject));
 515     }
 516 
 517     if (objectDescList != NULL) {
 518         printf("Deallocate objects list: 0x%p\n", (void*)objectDescList);
 519         if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)objectDescList))) {
 520             nsk_jvmti_setFailStatus();
 521         }
 522     }
 523 
 524     fflush(0);
 525     return NSK_TRUE;
 526 } /* releaseTestedObjects */
 527 
 528 
 529 /* ============================================================================= */
 530 
 531 /** heapReferenceCallback for heap iterator. */
 532 jint JNICALL heapReferenceCallback(
 533      jvmtiHeapReferenceKind        reference_kind,
 534      const jvmtiHeapReferenceInfo* reference_info,
 535      jlong                         class_tag,
 536      jlong                         referrer_class_tag,
 537      jlong                         size,
 538      jlong*                        tag_ptr,
 539      jlong*                        referrer_tag_ptr,
 540      jint                          length,
 541      void*                         user_data)
 542 {
 543     jint referrer_index = 0;
 544     jlong tag;
 545     jlong ref_tag;
 546 
 547     printf(" heapReferenceCallback: %s\n", ref_kind_str[reference_kind]);
 548     printf("   reference_info: 0x%p, class_tag: 0x%" LL "d, referrer_class_tag: 0x%" LL "d\n",
 549                reference_info,       class_tag,           referrer_class_tag);
 550                           /* ss45998: class_tag=>referrence_class_tag */
 551     printf("   size: %" LL "d, tag_ptr: 0x%p, referrer_tag_ptr: 0x%p, length: %-d\n",
 552                size,         tag_ptr,       referrer_tag_ptr,       length);
 553     fflush(0);
 554 
 555     if (((uintptr_t) tag_ptr & FULL_32_BIT_MASK) == FULL_32_BIT_MASK) {
 556         NSK_COMPLAIN1("wrong tag_ptr passed to "
 557                       "heapReferenceCallback: %#lx\n", tag_ptr);
 558         nsk_jvmti_setFailStatus();
 559         tag = 0;
 560     } else {
 561         tag = DEREF(tag_ptr);
 562     }
 563 
 564     if (((uintptr_t) referrer_tag_ptr & FULL_32_BIT_MASK) == FULL_32_BIT_MASK) {
 565         NSK_COMPLAIN1("wrong referrer_tag_ptr passed to "
 566                       "heapReferenceCallback: %#lx\n", referrer_tag_ptr);
 567         nsk_jvmti_setFailStatus();
 568         ref_tag = 0;
 569     } else {
 570         ref_tag = DEREF(referrer_tag_ptr);
 571     }
 572 
 573     referrer_index = get_reference_index(reference_kind, reference_info);
 574 
 575     printf("   class_tag=%" LL "d, tag=%" LL "d, size=%" LL "d,"
 576            " ref_tag=%" LL "d, referrer_index=%d\n\n",
 577                class_tag, tag, size, ref_tag, referrer_index);
 578     fflush(0);
 579 
 580     if (length != -1) {
 581         NSK_COMPLAIN1("wrong length passed to heapReferenceCallback: "
 582                       "%d; must be: -1\n", length);
 583         nsk_jvmti_setFailStatus();
 584     }
 585 
 586     if (tag_ptr != NULL && *tag_ptr != 0) {
 587         int found = 0;
 588         int i;
 589 
 590         for (i = 0; i < objectsCount; i++) {
 591             if (*tag_ptr == objectDescList[i].tag) {
 592                 found++;
 593                 objectDescList[i].found++;
 594 
 595                 if (*tag_ptr < 0) {
 596                     NSK_COMPLAIN0("Unreachable tagged object is passed"
 597                                   " to heapReferenceCallback\n");
 598                     nsk_jvmti_setFailStatus();
 599                 }
 600                 break;
 601             }
 602         }
 603 
 604         if (reference_kind != JVMTI_HEAP_REFERENCE_CLASS && found <= 0) {
 605             NSK_COMPLAIN0("Unknown tagged object is passed"
 606                           " to heapReferenceCallback\n");
 607             nsk_jvmti_setFailStatus();
 608         }
 609     }
 610 
 611     if (user_data != &fakeUserData && !userDataError) {
 612        NSK_COMPLAIN2("Unexpected user_data is passed"
 613                      " to heapReferenceCallback:\n"
 614                       "   expected:       0x%p\n"
 615                       "   actual:         0x%p\n",
 616                       user_data,
 617                       &fakeUserData);
 618         nsk_jvmti_setFailStatus();
 619         userDataError++;
 620     }
 621 
 622     switch (reference_kind) {
 623         int i;
 624         case JVMTI_HEAP_REFERENCE_CLASS: {
 625             if (tag == 0) {
 626                 return 0;
 627             }
 628             if (tag != ROOT_CLASS_TAG && tag != CHAIN_CLASS_TAG) {
 629                 NSK_COMPLAIN0("Unknown tagged class is passed"
 630                               " to heapReferenceCallback\n");
 631                 nsk_jvmti_setFailStatus();
 632             }
 633             for (i = 0; i < objectsCount; i++) {
 634                if (ref_tag == objectDescList[i].tag) {
 635                    if (objectDescList[i].exp_class_tag != tag) {
 636                        NSK_COMPLAIN2("Wrong tag in heapReferenceCallback"
 637                                      "/JVMTI_HEAP_REFERENCE_CLASS:\n"
 638                                      "Expected: %-3ld\n"
 639                                      "Passed:   %-3ld\n",
 640                                       objectDescList[i].exp_class_tag,
 641                                       tag);
 642                        nsk_jvmti_setFailStatus();
 643                    }
 644                    break;
 645                }
 646             }
 647             return 0;
 648         }
 649         case JVMTI_HEAP_REFERENCE_JNI_GLOBAL:
 650         case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS:
 651         case JVMTI_HEAP_REFERENCE_MONITOR:
 652         case JVMTI_HEAP_REFERENCE_STACK_LOCAL:
 653         case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
 654         case JVMTI_HEAP_REFERENCE_THREAD:
 655         case JVMTI_HEAP_REFERENCE_OTHER: {
 656             NSK_COMPLAIN1("This reference kind was not expected: %s\n",
 657                            ref_kind_str[reference_kind]);
 658             fflush(0);
 659             nsk_jvmti_setFailStatus();
 660             return 0;
 661         }
 662         default:
 663             // TODO: check that realy should be done w/ other jvmtiHeapReferenceKind
 664             break;
 665     }
 666     return JVMTI_VISIT_OBJECTS;
 667 } /* heapReferenceCallback */
 668 
 669 
 670 jint JNICALL primitiveFieldCallback(
 671      jvmtiHeapReferenceKind        reference_kind,
 672      const jvmtiHeapReferenceInfo* reference_info,
 673      jlong                         class_tag,
 674      jlong*                        tag_ptr,
 675      jvalue                        value,
 676      jvmtiPrimitiveType            value_type,
 677      void*                         user_data)
 678 {
 679     printf(" primitiveFieldCallback: ref=%s,"
 680                " class_tag=%-3ld, tag=%-3ld, type=%c\n",
 681                ref_kind_str[reference_kind],
 682                (long) class_tag,
 683                (long) DEREF(tag_ptr),
 684                (int ) value_type);
 685     fflush(0);
 686     return 0;
 687 } /* primitiveFieldCallback */
 688 
 689 
 690 jint JNICALL arrayPrimitiveValueCallback(
 691      jlong              class_tag,
 692      jlong              size,
 693      jlong*             tag_ptr,
 694      jint               element_count,
 695      jvmtiPrimitiveType element_type,
 696      const void*        elements,
 697      void*              user_data)
 698 {
 699     printf(" arrayPrimitiveValueCallback: class_tag=%-3ld,"
 700            " tag=%-3ld, len=%d, type=%c\n",
 701            (long) class_tag,
 702            (long) DEREF(tag_ptr),
 703            (int ) element_count,
 704            (int ) element_type);
 705     fflush(0);
 706     return 0;
 707 } /* arrayPrimitiveValueCallback */
 708 
 709 
 710 jint JNICALL stringPrimitiveValueCallback(
 711      jlong        class_tag,
 712      jlong        size,
 713      jlong*       tag_ptr,
 714      const jchar* value,
 715      jint         value_length,
 716      void*        user_data)
 717 {
 718     printf("stringPrimitiveValueCallback: class_tag=%-3ld, tag=%-3ld, len=%d\n",
 719            (long) class_tag,
 720            (long) DEREF(tag_ptr),
 721            (int ) value_length);
 722     fflush(0);
 723     return 0;
 724 } /* stringPrimitiveValueCallback */
 725 
 726 
 727 
 728 /* ============================================================================= */
 729 
 730 /** Agent algorithm. */
 731 static void JNICALL
 732 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
 733     jobject rootObject = NULL;
 734 
 735     printf("Wait for tested objects created\n");
 736     fflush(0);
 737     if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) {
 738         return;
 739     }
 740 
 741 
 742     printf(">>> Obtain and tag tested objects from debugee class\n");
 743     fflush(0);
 744 
 745     if (!NSK_VERIFY(getAndTagTestedObjects(jvmti,
 746                                            jni,
 747                                            chainLength,
 748                                            &objectsCount,
 749                                            &objectDescList,
 750                                            &rootObject))
 751     ) {
 752         return;
 753     }
 754 
 755     printf(">>> Let debugee to clean links to unreachable objects\n");
 756     fflush(0);
 757 
 758     if (!NSK_VERIFY(nsk_jvmti_resumeSync())) {
 759         return;
 760     }
 761     if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) {
 762         return;
 763     }
 764 
 765     printf(">>> Start iteration from root tested object: 0x%p\n\n", rootObject);
 766     fflush(0);
 767 
 768     if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences((jint)   0,    /* heap_filter    */
 769                                                   (jclass) NULL, /* class          */
 770                                                   rootObject,    /* initial_object */
 771                                                   &heapCallbacks,
 772                                                   (const void *) &fakeUserData))) {
 773          nsk_jvmti_setFailStatus();
 774          return;
 775     }
 776 
 777     printf(">>> Check if reachable objects were iterated:\n");
 778     fflush(0);
 779 
 780     if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) {
 781         nsk_jvmti_setFailStatus();
 782     }
 783 
 784     printf(">>> Clean used data\n");
 785     fflush(0);
 786 
 787     if (!NSK_VERIFY(releaseTestedObjects(jvmti, jni, chainLength,
 788                                          objectDescList, rootObject))) {
 789         return;
 790     }
 791 
 792     printf(">>> Let debugee to finish\n");
 793     fflush(0);
 794     if (!NSK_VERIFY(nsk_jvmti_resumeSync())) {
 795         return;
 796     }
 797 } /* agentProc */
 798 
 799 
 800 /* ============================================================================= */
 801 
 802 /** Agent library initialization. */
 803 #ifdef STATIC_BUILD
 804 JNIEXPORT jint JNICALL Agent_OnLoad_followref001(JavaVM *jvm, char *options, void *reserved) {
 805     return Agent_Initialize(jvm, options, reserved);
 806 }
 807 JNIEXPORT jint JNICALL Agent_OnAttach_followref001(JavaVM *jvm, char *options, void *reserved) {
 808     return Agent_Initialize(jvm, options, reserved);
 809 }
 810 JNIEXPORT jint JNI_OnLoad_followref001(JavaVM *jvm, char *options, void *reserved) {
 811     return JNI_VERSION_1_8;
 812 }
 813 #endif
 814 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 815     jvmtiEnv* jvmti = NULL;
 816 
 817     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) {
 818         return JNI_ERR;
 819     }
 820     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
 821 
 822     chainLength = nsk_jvmti_findOptionIntValue("objects", DEFAULT_CHAIN_LENGTH);
 823     if (!NSK_VERIFY(chainLength > 0))
 824         return JNI_ERR;
 825 
 826     if (!NSK_VERIFY((jvmti = nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) {
 827         return JNI_ERR;
 828     }
 829 
 830     {
 831         jvmtiCapabilities caps;
 832 
 833         memset(&caps, 0, sizeof(caps));
 834         caps.can_tag_objects = 1;
 835         if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) {
 836             return JNI_ERR;
 837         }
 838     }
 839 
 840     /* Setting Heap Callbacks */
 841     heapCallbacks.heap_iteration_callback         = NULL;
 842     heapCallbacks.heap_reference_callback         = heapReferenceCallback;
 843     heapCallbacks.primitive_field_callback        = primitiveFieldCallback;
 844     heapCallbacks.array_primitive_value_callback  = arrayPrimitiveValueCallback;
 845     heapCallbacks.string_primitive_value_callback = stringPrimitiveValueCallback;
 846 
 847     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) {
 848         return JNI_ERR;
 849     }
 850 
 851     return JNI_OK;
 852 } /* Agent_OnLoad */
 853 
 854 
 855 /* ============================================================================= */
 856 
 857 }