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