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