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 30 extern "C" { 31 32 /* ============================================================================= */ 33 34 static jlong timeout = 0; 35 36 #define INFO_NONE 0x00 37 #define INFO_ALL 0xFF 38 #define INFO_OBJREF 0x01 39 #define INFO_STACKREF 0x02 40 #define INFO_HEAPROOT 0x04 41 #define INFO_HEAPOBJ 0x08 42 43 static unsigned int info = INFO_ALL; 44 45 #define DEBUGEE_CLASS_NAME "nsk/jvmti/unit/FollowReferences/followref003" 46 #define ROOT_OBJECT_CLASS_NAME "nsk/jvmti/unit/FollowReferences/followref003RootTestedClass" 47 #define ROOT_OBJECT_CLASS_SIG "L" ROOT_OBJECT_CLASS_NAME ";" 48 #define CHAIN_OBJECT_CLASS_NAME "nsk/jvmti/unit/FollowReferences/followref003TestedClass" 49 #define CHAIN_OBJECT_CLASS_SIG "L" CHAIN_OBJECT_CLASS_NAME ";" 50 51 #define OBJECT_FIELD_NAME "object" 52 #define REACHABLE_CHAIN_FIELD_NAME "reachableChain" 53 #define UNREACHABLE_CHAIN_FIELD_NAME "unreachableChain" 54 #define TAIL_FIELD_NAME "tail" 55 56 57 #define DEFAULT_CHAIN_LENGTH 3 58 #define MAXDEPTH 50 59 #define MAXSLOT 16 60 61 typedef struct ObjectDescStruct { 62 jlong tag; 63 jlong class_tag; 64 jlong exp_class_tag; 65 jint exp_found; 66 jint found; 67 } ObjectDesc; 68 69 static int chainLength = 0; 70 static int objectsCount = 0; 71 static int fakeUserData = 0; 72 static int userDataError = 0; 73 74 static ObjectDesc* objectDescList = NULL; 75 76 #define TARG_THREAD_TAG 11 77 #define FIRST_THREAD_TAG (TARG_THREAD_TAG + 1) 78 79 #define TARG_FRAME_DEPTH 1 80 81 static jlong rootClassTag = 9; 82 static jlong chainClassTag = 99; 83 static jlong thrObjectTag = FIRST_THREAD_TAG; 84 static jlong rootObjectTag = 55; 85 static jlong chainObjectTag = 100; 86 87 88 /* Java method frame slots interesting to check */ 89 #define ARGV_STRING_ARR_SLOT 1 90 #define FIRST_PRIM_ARR_SLOT 3 91 #define LAST_PRIM_ARR_SLOT 10 92 #define DUMMY_STRING_ARR_SLOT 11 93 94 95 static jvmtiHeapCallbacks heapCallbacks; 96 97 static const char* ref_kind_str[28] = { 98 "unknown_0", 99 "REFERENCE_CLASS", 100 "REFERENCE_FIELD", 101 "REFERENCE_ARRAY_ELEMENT", 102 "REFERENCE_CLASS_LOADER", 103 "REFERENCE_SIGNERS", 104 "REFERENCE_PROTECTION_DOMAIN", 105 "REFERENCE_INTERFACE", 106 "REFERENCE_STATIC_FIELD", 107 "REFERENCE_CONSTANT_POOL", 108 "unknown_10", "unknown_11", "unknown_12", 109 "unknown_13", "unknown_14", "unknown_15", "unknown_16", 110 "unknown_17", "unknown_18", "unknown_19", "unknown_20", 111 "REFERENCE_JNI_GLOBAL", 112 "REFERENCE_SYSTEM_CLASS", 113 "REFERENCE_MONITOR", 114 "REFERENCE_STACK_LOCAL", 115 "REFERENCE_JNI_LOCAL", 116 "REFERENCE_THREAD", 117 "REFERENCE_OTHER" 118 }; 119 120 121 #define DEREF(ptr) (((ptr) == NULL ? 0 : *(ptr))) 122 123 124 /* ============================================================================= */ 125 126 /** Obtain chain of tested objects and tag them recursively. */ 127 static int getChainObjects(jvmtiEnv* jvmti, JNIEnv* jni, jobject firstObject, 128 jfieldID firstField, const char firstFieldName[], 129 jfieldID nextField, const char nextFieldName[], 130 int count, ObjectDesc objectDescList[], 131 jlong tag, int reachable) { 132 jobject obj = NULL; 133 jlong objTag = (reachable ? tag : -tag); 134 135 if (count <= 0) 136 return NSK_TRUE; 137 138 count--; 139 tag++; 140 141 if (!NSK_JNI_VERIFY(jni, (obj = jni->GetObjectField(firstObject, firstField)) != NULL)) { 142 nsk_jvmti_setFailStatus(); 143 return NSK_FALSE; 144 } 145 146 objectDescList[count].tag = objTag; 147 148 if (!NSK_JVMTI_VERIFY(jvmti->SetTag(obj, objTag))) { 149 nsk_jvmti_setFailStatus(); 150 } 151 printf(" tag=%-5ld object=0x%p\n", (long)objTag, (void*)obj); 152 fflush(0); 153 if (!getChainObjects(jvmti, jni, obj, nextField, nextFieldName, 154 nextField, nextFieldName, 155 count, objectDescList, tag, reachable)) { 156 return NSK_FALSE; 157 } 158 159 NSK_TRACE(jni->DeleteLocalRef(obj)); 160 return NSK_TRUE; 161 } 162 163 /** Obtain all tested objects from debugee class and tag them recursively. */ 164 static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, 165 int *objectsCount, ObjectDesc* *objectDescList, 166 jobject* rootObject) { 167 jclass debugeeClass = NULL; 168 jclass rootObjectClass = NULL; 169 jclass chainObjectClass = NULL; 170 171 jfieldID objectField = NULL; 172 jfieldID reachableChainField = NULL; 173 jfieldID unreachableChainField = NULL; 174 jfieldID tailField = NULL; 175 176 *objectsCount = 1 + 2 * chainLength; 177 178 printf("Allocate memory for objects list: %d objects\n", *objectsCount); 179 fflush(0); 180 if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)), 181 (unsigned char**)objectDescList))) { 182 nsk_jvmti_setFailStatus(); 183 return NSK_FALSE; 184 } 185 printf(" ... allocated array: 0x%p\n", (void*)objectDescList); 186 fflush(0); 187 188 { 189 int k; 190 for (k = 0; k < *objectsCount; k++) { 191 (*objectDescList)[k].tag = 0; 192 (*objectDescList)[k].exp_class_tag = chainClassTag; 193 (*objectDescList)[k].exp_found = 0; 194 (*objectDescList)[k].found = 0; 195 } 196 } 197 (*objectDescList)[0].exp_class_tag = rootClassTag; 198 199 printf("Find debugee class: %s\n", DEBUGEE_CLASS_NAME); 200 fflush(0); 201 if (!NSK_JNI_VERIFY(jni, (debugeeClass = jni->FindClass(DEBUGEE_CLASS_NAME)) != NULL)) { 202 nsk_jvmti_setFailStatus(); 203 return NSK_FALSE; 204 } 205 printf(" ... found class: 0x%p\n", (void*)debugeeClass); 206 207 printf("Find root object class: %s\n", ROOT_OBJECT_CLASS_NAME); 208 fflush(0); 209 if (!NSK_JNI_VERIFY(jni, (rootObjectClass = jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != NULL)) { 210 nsk_jvmti_setFailStatus(); 211 return NSK_FALSE; 212 } 213 printf(" ... found class: 0x%p\n", (void*)rootObjectClass); 214 215 if (!NSK_JVMTI_VERIFY(jvmti->SetTag(rootObjectClass, rootClassTag))) { 216 nsk_jvmti_setFailStatus(); 217 } 218 printf(" tag=%-5ld rootClass=0x%p\n", 219 (long)rootClassTag, (void*)rootObjectClass); 220 221 printf("Find chain object class: %s\n", CHAIN_OBJECT_CLASS_NAME); 222 fflush(0); 223 if (!NSK_JNI_VERIFY(jni, (chainObjectClass = 224 jni->FindClass(CHAIN_OBJECT_CLASS_NAME)) != NULL)) { 225 nsk_jvmti_setFailStatus(); 226 return NSK_FALSE; 227 } 228 printf(" ... found class: 0x%p\n", 229 (void*)chainObjectClass); 230 231 if (!NSK_JVMTI_VERIFY(jvmti->SetTag(chainObjectClass, chainClassTag))) { 232 nsk_jvmti_setFailStatus(); 233 } 234 printf(" tag=%-5ld chainClass=0x%p\n", 235 (long)chainClassTag, (void*)chainObjectClass); 236 237 printf("Find static field in debugee class: %s\n", OBJECT_FIELD_NAME); 238 fflush(0); 239 if (!NSK_JNI_VERIFY(jni, (objectField = 240 jni->GetStaticFieldID(debugeeClass, OBJECT_FIELD_NAME, ROOT_OBJECT_CLASS_SIG)) != NULL)) { 241 nsk_jvmti_setFailStatus(); 242 return NSK_FALSE; 243 } 244 printf(" ... got fieldID: 0x%p\n", (void*)objectField); 245 246 printf("Find instance field in root object class: %s\n", REACHABLE_CHAIN_FIELD_NAME); 247 fflush(0); 248 if (!NSK_JNI_VERIFY(jni, (reachableChainField = 249 jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) { 250 nsk_jvmti_setFailStatus(); 251 return NSK_FALSE; 252 } 253 printf(" ... got fieldID: 0x%p\n", (void*)reachableChainField); 254 255 printf("Find instance field in root object class: %s\n", UNREACHABLE_CHAIN_FIELD_NAME); 256 fflush(0); 257 if (!NSK_JNI_VERIFY(jni, (unreachableChainField = 258 jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) { 259 nsk_jvmti_setFailStatus(); 260 return NSK_FALSE; 261 } 262 printf(" ... got fieldID: 0x%p\n", (void*)unreachableChainField); 263 264 printf("Find instance field in chain object class: %s\n", TAIL_FIELD_NAME); 265 fflush(0); 266 if (!NSK_JNI_VERIFY(jni, (tailField = 267 jni->GetFieldID(chainObjectClass, TAIL_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) { 268 nsk_jvmti_setFailStatus(); 269 return NSK_FALSE; 270 } 271 printf(" ... got fieldID: 0x%p\n", (void*)tailField); 272 273 printf("Get root object from static field: %s\n", OBJECT_FIELD_NAME); 274 fflush(0); 275 if (!NSK_JNI_VERIFY(jni, (*rootObject = 276 jni->GetStaticObjectField(debugeeClass, objectField)) != NULL)) { 277 nsk_jvmti_setFailStatus(); 278 return NSK_FALSE; 279 } 280 printf(" ... got object: 0x%p\n", (void*)*rootObject); 281 fflush(0); 282 283 if (!NSK_JNI_VERIFY(jni, (*rootObject = jni->NewGlobalRef(*rootObject)) != NULL)) { 284 nsk_jvmti_setFailStatus(); 285 return NSK_FALSE; 286 } 287 printf(" ... global ref: 0x%p\n", (void*)*rootObject); 288 289 printf("Obtain and tag chain objects:\n"); 290 291 printf(" root tested object\n"); 292 fflush(0); 293 if (!NSK_JVMTI_VERIFY(jvmti->SetTag(*rootObject, rootObjectTag))) { 294 nsk_jvmti_setFailStatus(); 295 } 296 printf(" tag=%-5ld object=0x%p\n", 297 (long)rootObjectTag, (void*)*rootObject); 298 299 /* Root object must be reported 1 time */ 300 (*objectDescList)[0].exp_found = 1; 301 (*objectDescList)[0].tag = rootObjectTag; 302 303 printf(" reachable objects chain: %d objects\n", chainLength); 304 fflush(0); 305 if (!getChainObjects(jvmti, jni, *rootObject, 306 reachableChainField, REACHABLE_CHAIN_FIELD_NAME, 307 tailField, TAIL_FIELD_NAME, 308 chainLength, (*objectDescList) + 1, 309 chainObjectTag, NSK_TRUE)) { 310 nsk_jvmti_setFailStatus(); 311 return NSK_FALSE; 312 } 313 314 /* First unreachable object must be reported once 315 * as JVMTI_HEAP_REFERENCE_STACK_LOCAL */ 316 (*objectDescList)[2 * chainLength].exp_found = 1; 317 318 printf(" unreachable objects chain: %d objects\n", chainLength); 319 if (!getChainObjects(jvmti, jni, *rootObject, 320 unreachableChainField, UNREACHABLE_CHAIN_FIELD_NAME, 321 tailField, TAIL_FIELD_NAME, 322 chainLength, (*objectDescList) + 1 + chainLength, 323 chainObjectTag, NSK_FALSE)) { 324 nsk_jvmti_setFailStatus(); 325 return NSK_FALSE; 326 } 327 328 return NSK_TRUE; 329 } 330 331 /** Check if tagged objects were iterated. */ 332 static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, 333 int chainLength, ObjectDesc objectDescList[]) { 334 int success = NSK_TRUE; 335 int i, idx; 336 337 printf("Following tagged objects were iterated:\n"); 338 339 printf("Root tested object:\n"); 340 printf(" tag: %ld\n" 341 " expected to iterate: %d times\n" 342 " iterated: %d times\n", 343 (long) objectDescList[0].tag, 344 objectDescList[0].exp_found, 345 objectDescList[0].found); 346 if (objectDescList[0].found != objectDescList[0].exp_found) { 347 NSK_COMPLAIN1("Root tested object unexpectedly iterated %d times\n", 348 objectDescList[0].found); 349 nsk_jvmti_setFailStatus(); 350 } 351 352 printf("\nReachable objects:\n"); 353 fflush(0); 354 for (i = 0; i < chainLength; i++) { 355 idx = i + 1; 356 printf("Reachable object:\n" 357 " tag: %-3ld\n" 358 " expected to iterate: %d times\n" 359 " iterated: %d times\n", 360 (long) objectDescList[idx].tag, 361 objectDescList[idx].exp_found, 362 objectDescList[idx].found); 363 if (objectDescList[i + 1].found <= 0 && objectDescList[i + 1].exp_found > 0) { 364 NSK_COMPLAIN0("Reachable object was not iterated\n"); 365 nsk_jvmti_setFailStatus(); 366 } 367 if (objectDescList[idx].found != objectDescList[idx].exp_found) { 368 NSK_COMPLAIN0("Reachable object was iterated unexpected number of times\n"); 369 nsk_jvmti_setFailStatus(); 370 } 371 } 372 373 printf("\nUnreachable objects:\n"); 374 for (i = 0; i < chainLength; i++) { 375 idx = i + 1 + chainLength; 376 377 printf("Unreachable object:\n" 378 " tag: %ld\n" 379 " expected to iterate: %d times\n" 380 " iterated: %d times\n", 381 (long) objectDescList[idx].tag, 382 objectDescList[idx].exp_found, 383 objectDescList[idx].found); 384 if (objectDescList[idx].found > 0 && objectDescList[idx].exp_found == 0) { 385 NSK_COMPLAIN0("Unreachable object was iterated\n"); 386 nsk_jvmti_setFailStatus(); 387 } 388 fflush(0); 389 } 390 391 return NSK_TRUE; 392 } 393 394 /** Release references to the tested objects and free allocated memory. */ 395 static int releaseTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, 396 ObjectDesc* objectDescList, jobject rootObject) { 397 if (rootObject != NULL) { 398 printf("Release object reference to root tested object: 0x%p\n", rootObject); 399 NSK_TRACE(jni->DeleteGlobalRef(rootObject)); 400 } 401 402 if (objectDescList != NULL) { 403 printf("Deallocate objects list: 0x%p\n", (void*)objectDescList); 404 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)objectDescList))) { 405 nsk_jvmti_setFailStatus(); 406 } 407 } 408 409 fflush(0); 410 return NSK_TRUE; 411 } 412 413 /* ============================================================================= */ 414 415 /* Some diagnostics happen in the first FollowReferences call only */ 416 static int first_followref = 1; 417 418 typedef struct ThreadDescStruct { 419 jlong tag; 420 jlong id; 421 } ThreadDesc; 422 423 #define MAX_THREADS 1024 424 static ThreadDesc thrDesc [MAX_THREADS] = {}; 425 426 static jlong registerThread(jlong thr_id, jlong thr_tag) { 427 if (thr_id <= 0 || thr_id >= MAX_THREADS) { 428 NSK_COMPLAIN1("Unexpected thread ID: %ld\n", thr_id); 429 nsk_jvmti_setFailStatus(); 430 return 0; 431 } 432 if (thrDesc[thr_id].id == 0) { 433 /* need to set the first occurence info */ 434 thrDesc[thr_id].id = thr_id; 435 thrDesc[thr_id].tag = thr_tag; 436 } else if (thr_tag != thrDesc[thr_id].tag) { 437 NSK_COMPLAIN3("Thread tag doesn't match the first occurence: thr_id= %ld\n" 438 "\t first thr_tag=%#lx, curr thr_tag=%#lx\n", 439 thr_id, thrDesc[thr_id].tag, thr_tag); 440 nsk_jvmti_setFailStatus(); 441 return 0; 442 } 443 return thr_id; 444 } /* registerThread */ 445 446 typedef struct FrameDescStruct { 447 jlong thr_id; 448 jint depth; 449 jmethodID method; 450 } FrameDesc; 451 452 #define MAX_FRAMES 256 453 static FrameDesc frameDesc[MAX_FRAMES] = {}; 454 static int curr_frame_id = 0; /* Index 0 should not be used */ 455 456 /* returns frame slot number in the table of frames */ 457 static int registerFrame(jlong thr_id, jint depth, jmethodID method, 458 jvmtiHeapReferenceKind ref_kind) 459 { 460 int idx; 461 int failed = 0; 462 463 FrameDesc *fr; 464 if (depth < 0 || depth > MAXDEPTH) { 465 NSK_COMPLAIN1("Incorrect frame depth: %ld\n", depth); 466 failed = 1; 467 } 468 /* JNI_LOCAL references from native methods may not have a jmethodID. 469 * (Do we have to clarify this in the JVMTI spec?) 470 * Do not consider the test as failing in such a case. 471 */ 472 if (method == NULL && ref_kind != JVMTI_HEAP_REFERENCE_JNI_LOCAL) { 473 NSK_COMPLAIN0("methodID must not be NULL\n"); 474 failed = 1; 475 } 476 if (failed) { 477 nsk_jvmti_setFailStatus(); 478 return 0; 479 } 480 481 /* Check if this frame was registered */ 482 for (idx = 1; idx <= curr_frame_id; idx++) { 483 fr = &frameDesc[idx]; 484 if (fr->thr_id == thr_id && fr->depth == depth && fr->method == method) { 485 return idx; 486 } 487 } 488 if (++curr_frame_id >= MAX_FRAMES) { 489 NSK_COMPLAIN1("Internal: Insufficient frames table size: %ld\n", MAX_FRAMES); 490 return 0; 491 } 492 fr = &frameDesc[curr_frame_id]; 493 fr->thr_id = thr_id; 494 fr->depth = depth; 495 fr->method = method; 496 497 return curr_frame_id; 498 } /* registerFrame */ 499 500 501 typedef struct LocalDescStruct { 502 jint frame_id; 503 jlocation location; 504 jint slot; 505 jlong tag; 506 } LocalDesc; 507 508 #define MAX_LOCALS 100 509 static LocalDesc locDesc [MAX_LOCALS] = {}; 510 static int curr_local_idx = 0; /* Index 0 should not be used */ 511 512 /* returns frame slot number in the table of frames */ 513 static int registerLocal(jint frame_id, jlocation location, jint slot, jlong tag) { 514 int idx; 515 LocalDesc *loc; 516 int failed = 0; 517 518 if (slot < 0 || slot > MAXSLOT) { 519 NSK_COMPLAIN1("Incorrect stack local slot#: %ld\n", slot); 520 failed = 1; 521 } 522 if ((jlong) location == -1L) { 523 NSK_COMPLAIN0("Location must not be -1\n"); 524 failed = 1; 525 } 526 527 if (failed) { 528 nsk_jvmti_setFailStatus(); 529 return 0; 530 } 531 532 /* Check if this local was registered */ 533 for (idx = 1; idx <= curr_local_idx; idx++) { 534 loc = &locDesc[idx]; 535 if (loc->frame_id == frame_id && 536 loc->slot == slot) { 537 if (first_followref) { 538 /* Do this check on the first FollowReferences call only */ 539 FrameDesc *fr = &frameDesc[frame_id]; 540 printf("Second report of the local: " 541 "loc_idx=%d, frame_id=%d, slot=%d\n", 542 idx, frame_id, slot); 543 printf("\t thr_id=%" LL "d, depth=%d, meth=0x%p\n", 544 fr->thr_id, fr->depth, fr->method); 545 failed = 1; 546 } 547 if (loc->tag != tag) { 548 NSK_COMPLAIN2("Tag mismatch: expected %#lx, passed: %#lx\n", 549 loc->tag, tag); 550 failed = 1; 551 } 552 if (loc->location != location) { 553 NSK_COMPLAIN2("Location mismatch: expected %ld, passed: %ld\n", 554 (long) loc->location, (long) location); 555 failed = 1; 556 } 557 if (failed) { 558 nsk_jvmti_setFailStatus(); 559 return 0; 560 } 561 return idx; 562 } 563 } 564 if (++curr_local_idx >= MAX_LOCALS) { 565 printf("Internal: Insufficient locals table size: %d\n", MAX_FRAMES); 566 return 0; 567 } 568 loc = &locDesc[curr_local_idx]; 569 loc->frame_id = frame_id; 570 loc->location = location; 571 loc->slot = slot; 572 loc->tag = tag; 573 574 return curr_local_idx; 575 } /* registerLocal */ 576 577 578 /** heapReferenceCallback for heap iterator. */ 579 jint JNICALL heapReferenceCallback( 580 jvmtiHeapReferenceKind ref_kind, 581 const jvmtiHeapReferenceInfo* reference_info, 582 jlong class_tag, 583 jlong referrer_class_tag, 584 jlong size, 585 jlong* tag_ptr, 586 jlong* referrer_tag_ptr, 587 jint length, 588 void* user_data) 589 { 590 jint depth = -1; 591 jint slot = -1; 592 jint index = -1; 593 jmethodID method = (jmethodID) NULL; 594 jlocation location = (jlocation)(-1); 595 jlong tag = DEREF(tag_ptr); 596 jlong ref_tag = DEREF(referrer_tag_ptr); 597 jlong thr_tag = -1; 598 jlong thr_id = -1; 599 jlong thr_idx = -1; 600 int res = -1; 601 int meth_idx = -1; 602 603 switch (ref_kind) { 604 case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: 605 index = reference_info->constant_pool.index; 606 break; 607 case JVMTI_HEAP_REFERENCE_FIELD: 608 case JVMTI_HEAP_REFERENCE_STATIC_FIELD: 609 index = reference_info->field.index; 610 break; 611 case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: 612 index = reference_info->array.index; 613 break; 614 case JVMTI_HEAP_REFERENCE_STACK_LOCAL: 615 thr_tag = reference_info->stack_local.thread_tag; 616 thr_id = reference_info->stack_local.thread_id; 617 depth = reference_info->stack_local.depth; 618 method = reference_info->stack_local.method; 619 location = reference_info->stack_local.location; 620 slot = reference_info->stack_local.slot; 621 index = slot | depth << 16; 622 break; 623 case JVMTI_HEAP_REFERENCE_JNI_LOCAL: 624 thr_tag = reference_info->jni_local.thread_tag; 625 thr_id = reference_info->jni_local.thread_id; 626 depth = reference_info->jni_local.depth; 627 method = reference_info->jni_local.method; 628 index = depth; 629 break; 630 default: 631 // TODO: check that realy should be done w/ other jvmtiHeapReferenceKind 632 break; 633 } 634 635 if (ref_kind == JVMTI_HEAP_REFERENCE_OTHER || 636 ref_kind == JVMTI_HEAP_REFERENCE_JNI_GLOBAL || 637 ref_kind == JVMTI_HEAP_REFERENCE_SYSTEM_CLASS) { 638 return 0; /* Skip it as there is a plan to test it differently */ 639 } 640 641 if (ref_kind == JVMTI_HEAP_REFERENCE_THREAD) { 642 /* Target thread has been tagged already */ 643 if (tag == 0) { 644 tag = *tag_ptr = thrObjectTag++; 645 /* Just want to report new tag for thread object */ 646 printf(" heapReferenceCallback: ref=%s, tag=%-3ld, size=%-3ld\n", 647 ref_kind_str[ref_kind], 648 (long) *tag_ptr, 649 (long) size); 650 } 651 652 fflush(0); 653 return 0; 654 } 655 656 printf(" heapReferenceCallback: ref=%s, class_tag=%-3ld, tag=%-3ld," 657 " size=%-3ld, len=%-2d\n" 658 "\t\t ref_tag=%-" LL "d, thr_tag=%-3ld, thr_id=%" LL "d, " 659 "meth=0x%p, loc=%ld, idx=%#x\n", 660 ref_kind_str[ref_kind], 661 (long) class_tag, 662 (long) tag, 663 (long) size, 664 (int ) length, 665 ref_tag, 666 (long) thr_tag, 667 thr_id, 668 method, 669 (long) location, 670 (int ) index); 671 fflush(0); 672 673 if (tag_ptr == NULL) { 674 NSK_COMPLAIN1("NULL tag_ptr is passed to heapReferenceCallback:" 675 " tag_ptr=0x%p\n", (void*)tag_ptr); 676 nsk_jvmti_setFailStatus(); 677 } 678 679 if (tag_ptr != NULL && tag != 0) { 680 int found = 0; 681 int i; 682 683 for (i = 0; i < objectsCount; i++) { 684 if (*tag_ptr == objectDescList[i].tag) { 685 found++; 686 objectDescList[i].found++; 687 688 if (*tag_ptr < 0 && *tag_ptr != -chainObjectTag && 689 ref_kind != JVMTI_HEAP_REFERENCE_STACK_LOCAL) 690 { 691 NSK_COMPLAIN0("Unreachable tagged object is " 692 "passed to heapReferenceCallback\n"); 693 nsk_jvmti_setFailStatus(); 694 break; 695 } 696 break; 697 } 698 } 699 700 if (ref_kind != JVMTI_HEAP_REFERENCE_CLASS && 701 ref_kind != JVMTI_HEAP_REFERENCE_JNI_LOCAL && found <= 0 && 702 tag < FIRST_THREAD_TAG && tag > (thrObjectTag - 1)) 703 { 704 NSK_COMPLAIN0("Unknown tagged object is passed " 705 "to heapReferenceCallback\n"); 706 nsk_jvmti_setFailStatus(); 707 } 708 } 709 710 if (user_data != &fakeUserData && !userDataError) { 711 NSK_COMPLAIN2("Unexpected user_data is passed " 712 "to heapReferenceCallback:\n" 713 " expected: 0x%p\n" 714 " actual: 0x%p\n", 715 user_data, 716 &fakeUserData); 717 nsk_jvmti_setFailStatus(); 718 userDataError++; 719 } 720 721 switch (ref_kind) { 722 case JVMTI_HEAP_REFERENCE_CLASS: { 723 int i; 724 if (tag == 0) { 725 return 0; 726 } 727 if (tag != rootClassTag && tag != chainClassTag) { 728 NSK_COMPLAIN0("Unknown tagged class is passed " 729 "to heapReferenceCallback\n"); 730 nsk_jvmti_setFailStatus(); 731 break; 732 } 733 for (i = 0; i < objectsCount; i++) { 734 if (ref_tag == objectDescList[i].tag) { 735 if (objectDescList[i].exp_class_tag != tag) { 736 NSK_COMPLAIN2("Wrong tag in heapReferenceCallback" 737 "/JVMTI_HEAP_REFERENCE_CLASS:\n" 738 "Expected: %-3ld\n" 739 "Passed: %-3ld\n", 740 objectDescList[i].exp_class_tag, 741 tag); 742 nsk_jvmti_setFailStatus(); 743 } 744 break; 745 } 746 } 747 break; 748 } 749 750 case JVMTI_HEAP_REFERENCE_STATIC_FIELD: 751 if (tag != rootObjectTag || class_tag != rootClassTag) { 752 NSK_COMPLAIN1("This reference kind was not expected: %s\n", 753 ref_kind_str[ref_kind]); 754 fflush(0); 755 nsk_jvmti_setFailStatus(); 756 } 757 break; 758 759 case JVMTI_HEAP_REFERENCE_STACK_LOCAL: 760 // Skip local references from non-main (e.g. compiler) threads. 761 if (thr_tag == TARG_THREAD_TAG) { 762 thr_idx = registerThread(thr_id, thr_tag); 763 meth_idx = registerFrame(thr_id, depth, method, ref_kind); 764 if (meth_idx > 0) { 765 jint loc_idx = registerLocal(meth_idx, location, slot, tag); 766 } 767 } 768 /* This part is kind of hack. It has some expectations about stack layout */ 769 if (thr_tag == TARG_THREAD_TAG && 770 reference_info->stack_local.depth == TARG_FRAME_DEPTH) { 771 if (length != -1) { 772 jint exp_len = length; 773 774 if (reference_info->stack_local.slot == ARGV_STRING_ARR_SLOT) { 775 exp_len = 0; 776 } 777 else if (reference_info->stack_local.slot >= FIRST_PRIM_ARR_SLOT && 778 reference_info->stack_local.slot <= LAST_PRIM_ARR_SLOT) { 779 exp_len = 2; 780 } 781 else if (reference_info->stack_local.slot == DUMMY_STRING_ARR_SLOT) { 782 exp_len = 3; 783 } 784 if (length != exp_len) { 785 NSK_COMPLAIN2("Wrong length of the local array:" 786 " expected: %-d, found: %-d\n\n", exp_len, length); 787 } 788 } else { /* length == -1 */ 789 if ((reference_info->stack_local.slot >= FIRST_PRIM_ARR_SLOT && 790 reference_info->stack_local.slot <= DUMMY_STRING_ARR_SLOT) || 791 reference_info->stack_local.slot == ARGV_STRING_ARR_SLOT) { 792 NSK_COMPLAIN0("Length of array must not be -1\n"); 793 } 794 } 795 if (length == 0 796 && reference_info->stack_local.slot != ARGV_STRING_ARR_SLOT 797 && reference_info->stack_local.slot < FIRST_PRIM_ARR_SLOT 798 && reference_info->stack_local.slot > DUMMY_STRING_ARR_SLOT) { 799 NSK_COMPLAIN1("Wrong length of the local variable:" 800 " expected: -1, found: %-d\n\n", length); 801 nsk_jvmti_setFailStatus(); 802 } 803 } 804 break; 805 case JVMTI_HEAP_REFERENCE_JNI_LOCAL: 806 // Skip JNI local references from non-main (e.g. compiler) threads. 807 if (thr_tag == TARG_THREAD_TAG) { 808 thr_idx = registerThread(thr_id, thr_tag); 809 meth_idx = registerFrame(thr_id, depth, method, ref_kind); 810 } 811 break; 812 813 case JVMTI_REFERENCE_ARRAY_ELEMENT: 814 case JVMTI_HEAP_REFERENCE_JNI_GLOBAL: 815 case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS: 816 case JVMTI_HEAP_REFERENCE_MONITOR: 817 case JVMTI_HEAP_REFERENCE_OTHER: 818 /* These reference kinds are expected */ 819 break; 820 821 default: { 822 NSK_COMPLAIN1("This reference kind was not expected: %s\n\n", 823 ref_kind_str[ref_kind]); 824 fflush(0); 825 nsk_jvmti_setFailStatus(); 826 break; 827 } 828 } 829 return 0; 830 } 831 832 jint JNICALL primitiveFieldCallback 833 (jvmtiHeapReferenceKind ref_kind, 834 const jvmtiHeapReferenceInfo* reference_info, 835 jlong class_tag, 836 jlong* tag_ptr, 837 jvalue value, 838 jvmtiPrimitiveType value_type, 839 void* user_data) 840 { 841 printf(" primitiveFieldCallback: ref=%s, class_tag=%-3ld, tag=%-3ld, type=%c\n", 842 ref_kind_str[ref_kind], 843 (long) class_tag, 844 (long) DEREF(tag_ptr), 845 (int ) value_type); 846 fflush(0); 847 return 0; 848 } 849 850 jint JNICALL arrayPrimitiveValueCallback 851 (jlong class_tag, jlong size, jlong* tag_ptr, jint element_count, 852 jvmtiPrimitiveType element_type, const void* elements, void* user_data) 853 { 854 printf(" arrayPrimitiveValueCallback: class_tag=%-3ld, tag=%-3ld, len=%d, type=%c\n", 855 (long) class_tag, 856 (long) DEREF(tag_ptr), 857 (int ) element_count, 858 (int ) element_type); 859 fflush(0); 860 return 0; 861 } 862 863 jint JNICALL stringPrimitiveValueCallback 864 (jlong class_tag, jlong size, jlong* tag_ptr, const jchar* value, 865 jint value_length, void* user_data) 866 { 867 printf("stringPrimitiveValueCallback: class_tag=%-3ld, tag=%-3ld, len=%d\n", 868 (long) class_tag, 869 (long) DEREF(tag_ptr), 870 (int ) value_length); 871 fflush(0); 872 return 0; 873 } 874 875 876 /* ============================================================================= */ 877 static jthread getTargetThread(jvmtiEnv *jvmti) { 878 static const char *target_thread_name = "main"; 879 jint i; 880 jint thread_count = -1; 881 jthread *threads = NULL; 882 883 jvmti->GetAllThreads(&thread_count, &threads); 884 885 for (i = 0; i < thread_count; i++) { 886 jvmtiThreadInfo thread_info; 887 jvmti->GetThreadInfo(threads[i], &thread_info); 888 889 if (strcmp(thread_info.name, target_thread_name) == 0) { 890 return threads[i]; 891 } 892 } 893 894 return NULL; 895 } 896 897 static jvmtiError setTagForTargetThread(jvmtiEnv *jvmti, jlong tag) { 898 jthread target_thread = getTargetThread(jvmti); 899 return jvmti->SetTag(target_thread, tag); 900 } 901 902 /** Agent algorithm. */ 903 static void JNICALL 904 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { 905 jobject rootObject = NULL; 906 907 printf("Wait for tested objects created\n"); 908 fflush(0); 909 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) { 910 return; 911 } 912 913 printf(">>> Obtain and tag tested objects from debugee class\n"); 914 fflush(0); 915 { 916 if (!NSK_VERIFY(getTestedObjects(jvmti, jni, chainLength, &objectsCount, 917 &objectDescList, &rootObject))) { 918 return; 919 } 920 } 921 922 printf(">>> Let debugee to clean links to unreachable objects\n"); 923 fflush(0); 924 { 925 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { 926 return; 927 } 928 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) { 929 return; 930 } 931 } 932 933 if (!NSK_JVMTI_VERIFY(setTagForTargetThread(jvmti, TARG_THREAD_TAG))) { 934 nsk_jvmti_setFailStatus(); 935 return; 936 } 937 938 printf("\n\n>>> Start 1-st iteration starting from the heap root\n"); 939 fflush(0); 940 { 941 if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences((jint) 0, /* heap_filter */ 942 (jclass) NULL, /* class */ 943 (jobject) NULL, /* initial_object */ 944 &heapCallbacks, 945 (const void *) &fakeUserData))) { 946 nsk_jvmti_setFailStatus(); 947 return; 948 } 949 } 950 951 printf(">>> Check if reachable objects were iterated\n"); 952 fflush(0); 953 { 954 if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { 955 nsk_jvmti_setFailStatus(); 956 } 957 } 958 959 { /* Reinstall the expectations */ 960 int k; 961 for (k = 0; k < objectsCount; k++) { 962 (objectDescList)[k].exp_found = 0; 963 (objectDescList)[k].found = 0; 964 } 965 /* Heap root object must be reported 2 times */ 966 objectDescList[0].exp_found = 2; 967 968 /* First unreachable object must be reported once 969 * as JVMTI_HEAP_REFERENCE_STACK_LOCAL */ 970 objectDescList[2 * chainLength].exp_found = 1; 971 } 972 973 printf("\n\n>>> Start 2-nd iteration starting from the heap root\n"); 974 fflush(0); 975 first_followref = 0; 976 { 977 jint heap_filter = JVMTI_HEAP_FILTER_UNTAGGED 978 | JVMTI_HEAP_FILTER_CLASS_UNTAGGED; 979 if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences(heap_filter, 980 (jclass) NULL, /* class */ 981 (jobject) NULL, /* initial_object */ 982 &heapCallbacks, 983 (const void *) &fakeUserData))) { 984 nsk_jvmti_setFailStatus(); 985 return; 986 } 987 } 988 989 printf(">>> Check that both reachable and unreachable " 990 "objects were not iterated\n"); 991 fflush(0); 992 { 993 if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { 994 nsk_jvmti_setFailStatus(); 995 } 996 } 997 998 999 printf(">>> Clean used data\n"); 1000 fflush(0); 1001 { 1002 if (!NSK_VERIFY(releaseTestedObjects(jvmti, jni, chainLength, 1003 objectDescList, rootObject))) { 1004 return; 1005 } 1006 } 1007 1008 printf("Let debugee to finish\n"); 1009 fflush(0); 1010 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) 1011 return; 1012 } 1013 1014 /* ============================================================================= */ 1015 1016 /** Agent library initialization. */ 1017 #ifdef STATIC_BUILD 1018 JNIEXPORT jint JNICALL Agent_OnLoad_followref003(JavaVM *jvm, char *options, void *reserved) { 1019 return Agent_Initialize(jvm, options, reserved); 1020 } 1021 JNIEXPORT jint JNICALL Agent_OnAttach_followref003(JavaVM *jvm, char *options, void *reserved) { 1022 return Agent_Initialize(jvm, options, reserved); 1023 } 1024 JNIEXPORT jint JNI_OnLoad_followref003(JavaVM *jvm, char *options, void *reserved) { 1025 return JNI_VERSION_1_8; 1026 } 1027 #endif 1028 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 1029 jvmtiEnv* jvmti = NULL; 1030 1031 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 1032 return JNI_ERR; 1033 1034 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 1035 1036 { 1037 const char* infoOpt = nsk_jvmti_findOptionValue("info"); 1038 if (infoOpt != NULL) { 1039 if (strcmp(infoOpt, "none") == 0) 1040 info = INFO_NONE; 1041 else if (strcmp(infoOpt, "all") == 0) 1042 info = INFO_ALL; 1043 else if (strcmp(infoOpt, "objref") == 0) 1044 info = INFO_OBJREF; 1045 else if (strcmp(infoOpt, "stackref") == 0) 1046 info = INFO_STACKREF; 1047 else if (strcmp(infoOpt, "heaproot") == 0) 1048 info = INFO_HEAPROOT; 1049 else if (strcmp(infoOpt, "heapobj") == 0) 1050 info = INFO_HEAPOBJ; 1051 else { 1052 printf("Unknown option value: info=%s\n", infoOpt); 1053 fflush(0); 1054 return JNI_ERR; 1055 } 1056 } 1057 } 1058 1059 chainLength = nsk_jvmti_findOptionIntValue("objects", DEFAULT_CHAIN_LENGTH); 1060 if (!NSK_VERIFY(chainLength > 0)) 1061 return JNI_ERR; 1062 1063 if (!NSK_VERIFY((jvmti = 1064 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 1065 return JNI_ERR; 1066 1067 { 1068 jvmtiCapabilities caps; 1069 1070 memset(&caps, 0, sizeof(caps)); 1071 caps.can_tag_objects = 1; 1072 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) { 1073 return JNI_ERR; 1074 } 1075 } 1076 1077 /* Setting Heap Callbacks */ 1078 heapCallbacks.heap_iteration_callback = NULL; 1079 heapCallbacks.heap_reference_callback = heapReferenceCallback; 1080 heapCallbacks.primitive_field_callback = primitiveFieldCallback; 1081 heapCallbacks.array_primitive_value_callback = arrayPrimitiveValueCallback; 1082 heapCallbacks.string_primitive_value_callback = stringPrimitiveValueCallback; 1083 1084 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 1085 return JNI_ERR; 1086 1087 return JNI_OK; 1088 } 1089 1090 /* ============================================================================= */ 1091 1092 }