1 /* 2 * Copyright (c) 2004, 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 static JNIEnv *jni = NULL; 33 static jvmtiEnv *jvmti = NULL; 34 static jvmtiEventCallbacks callbacks; 35 static jvmtiCapabilities caps; 36 static jlong timeout = 0; 37 38 /* ============================================================================= */ 39 40 static volatile long objectCount = 0, objectCountMax = 0; 41 static int userData = 0, callbackAborted = 0; 42 static int numberOfDeallocatedFromCallbacksDescriptors = 0; 43 44 typedef struct ObjectDescStruct { 45 jlong tag; 46 jlong size; 47 struct ObjectDescStruct *next; 48 } ObjectDesc; 49 50 static ObjectDesc *objectDescList, *objectDescListStart, *objectDescBuf; 51 static ObjectDesc* *objectDescArr; 52 static short* deallocatedFlagsArr; 53 54 /* ============================================================================= */ 55 56 void JNICALL 57 ObjectFree(jvmtiEnv *jvmti_env, jlong tag) { 58 /* decrement number of expected objects */ 59 objectCount--; 60 } 61 62 /* ============================================================================= */ 63 64 65 /** jvmtiHeapRootCallback for first iteration. */ 66 jvmtiIterationControl JNICALL 67 heapRootCallbackForFirstObjectsIteration(jvmtiHeapRootKind root_kind, 68 jlong class_tag, 69 jlong size, 70 jlong* tag_ptr, 71 void* user_data) { 72 73 if (*tag_ptr != 0) return JVMTI_ITERATION_CONTINUE; 74 75 /* Set tag */ 76 *tag_ptr = (jlong)++objectCount; 77 78 if (!NSK_JVMTI_VERIFY(jvmti->Allocate((sizeof(ObjectDesc)), (unsigned char**)&objectDescBuf))) { 79 nsk_jvmti_setFailStatus(); 80 callbackAborted = 1; 81 NSK_COMPLAIN0("heapRootCallbackForFirstObjectsIteration: Allocation failed. Iteration aborted.\n"); 82 return JVMTI_ITERATION_ABORT; 83 } 84 85 (*objectDescList).tag = *tag_ptr; 86 (*objectDescList).size = size; 87 (*objectDescList).next = objectDescBuf; 88 89 /* step to next list element */ 90 objectDescList = (*objectDescList).next; 91 92 return JVMTI_ITERATION_CONTINUE; 93 } 94 95 /** jvmtiHeapRootCallback for second iteration. */ 96 jvmtiIterationControl JNICALL 97 heapRootCallbackForSecondObjectsIteration(jvmtiHeapRootKind root_kind, 98 jlong class_tag, 99 jlong size, 100 jlong* tag_ptr, 101 void* user_data) { 102 103 long ind = (long)((*tag_ptr) - 1); 104 105 if (*tag_ptr == 0) return JVMTI_ITERATION_CONTINUE; 106 107 /* 108 ObjectDesc *objectDesc = objectDescArr[ind]; 109 jlong tag = (*objectDesc).tag; 110 */ 111 if (ind < 0 || ind > objectCountMax) { 112 NSK_COMPLAIN1("heapRootCallbackForSecondObjectsIteration: invalid object tag value: %d\n", (long)*tag_ptr); 113 nsk_jvmti_setFailStatus(); 114 callbackAborted = 1; 115 return JVMTI_ITERATION_ABORT; 116 } 117 /* 118 NSK_DISPLAY3("heapRootCallbackForSecondObjectsIteration: *tag_ptr %6d , tag %6d , objectCount %6d\n", 119 (long)*tag_ptr, (long)tag, objectCount); 120 */ 121 /* Deallocate memory of list element*/ 122 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)objectDescArr[ind]))) { 123 nsk_jvmti_setFailStatus(); 124 callbackAborted = 1; 125 NSK_COMPLAIN0("heapRootCallbackForSecondObjectsIteration: Deallocation failed. Iteration aborted.\n"); 126 return JVMTI_ITERATION_ABORT; 127 } 128 129 numberOfDeallocatedFromCallbacksDescriptors++; 130 deallocatedFlagsArr[ind] = 1; 131 132 /* unset tag */ 133 *tag_ptr = 0; 134 objectCount--; 135 136 return JVMTI_ITERATION_CONTINUE; 137 } 138 139 /** jvmtiStackReferenceCallback for first iteration. */ 140 jvmtiIterationControl JNICALL 141 stackReferenceCallbackForFirstObjectsIteration(jvmtiHeapRootKind root_kind, 142 jlong class_tag, 143 jlong size, 144 jlong* tag_ptr, 145 jlong thread_tag, 146 jint depth, 147 jmethodID method, 148 jint slot, 149 void* user_data) { 150 151 if (*tag_ptr != 0) return JVMTI_ITERATION_CONTINUE; 152 153 /* Set tag */ 154 *tag_ptr = (jlong)++objectCount; 155 156 if (!NSK_JVMTI_VERIFY(jvmti->Allocate((sizeof(ObjectDesc)), (unsigned char**)&objectDescBuf))) { 157 nsk_jvmti_setFailStatus(); 158 callbackAborted = 1; 159 NSK_COMPLAIN0("stackReferenceCallbackForFirstObjectsIteration: Allocation failed. Iteration aborted.\n"); 160 return JVMTI_ITERATION_ABORT; 161 } 162 163 (*objectDescList).tag = *tag_ptr; 164 (*objectDescList).size = size; 165 (*objectDescList).next = objectDescBuf; 166 167 /* step to next list element */ 168 objectDescList = (*objectDescList).next; 169 170 return JVMTI_ITERATION_CONTINUE; 171 } 172 173 /** jvmtiStackReferenceCallback for second iteration. */ 174 jvmtiIterationControl JNICALL 175 stackReferenceCallbackForSecondObjectsIteration(jvmtiHeapRootKind root_kind, 176 jlong class_tag, 177 jlong size, 178 jlong* tag_ptr, 179 jlong thread_tag, 180 jint depth, 181 jmethodID method, 182 jint slot, 183 void* user_data) { 184 185 long ind = (long)((*tag_ptr) - 1); 186 187 if (*tag_ptr == 0) return JVMTI_ITERATION_CONTINUE; 188 189 /* 190 ObjectDesc *objectDesc = objectDescArr[ind]; 191 jlong tag = (*objectDesc).tag; 192 */ 193 if (ind < 0 || ind > objectCountMax) { 194 NSK_COMPLAIN1("stackReferenceCallbackForSecondObjectsIteration: invalid object tag value: %d\n", (long)*tag_ptr); 195 nsk_jvmti_setFailStatus(); 196 callbackAborted = 1; 197 return JVMTI_ITERATION_ABORT; 198 } 199 /* 200 NSK_DISPLAY3("stackReferenceCallbackForSecondObjectsIteration: *tag_ptr %6d , tag %6d , objectCount %6d\n", 201 (long)*tag_ptr, (long)tag, objectCount); 202 */ 203 /* Deallocate memory of list element*/ 204 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)objectDescArr[ind]))) { 205 nsk_jvmti_setFailStatus(); 206 callbackAborted = 1; 207 NSK_COMPLAIN0("stackReferenceCallbackForSecondObjectsIteration: Deallocation failed. Iteration aborted.\n"); 208 return JVMTI_ITERATION_ABORT; 209 } 210 211 numberOfDeallocatedFromCallbacksDescriptors++; 212 deallocatedFlagsArr[ind] = 1; 213 214 /* unset tag */ 215 *tag_ptr = 0; 216 objectCount--; 217 218 return JVMTI_ITERATION_CONTINUE; 219 } 220 221 /** jvmtiObjectReferenceCallback for first iteration. */ 222 jvmtiIterationControl JNICALL 223 objectReferenceCallbackForFirstObjectsIteration(jvmtiObjectReferenceKind reference_kind, 224 jlong class_tag, 225 jlong size, 226 jlong* tag_ptr, 227 jlong referrer_tag, 228 jint referrer_index, 229 void* user_data) { 230 231 if (*tag_ptr != 0) return JVMTI_ITERATION_CONTINUE; 232 233 /* Set tag */ 234 *tag_ptr = (jlong)++objectCount; 235 236 if (!NSK_JVMTI_VERIFY(jvmti->Allocate((sizeof(ObjectDesc)), (unsigned char**)&objectDescBuf))) { 237 nsk_jvmti_setFailStatus(); 238 callbackAborted = 1; 239 NSK_COMPLAIN0("objectReferenceCallbackForFirstObjectsIteration: Allocation failed. Iteration aborted.\n"); 240 return JVMTI_ITERATION_ABORT; 241 } 242 243 (*objectDescList).tag = *tag_ptr; 244 (*objectDescList).size = size; 245 (*objectDescList).next = objectDescBuf; 246 247 /* step to next list element */ 248 objectDescList = (*objectDescList).next; 249 250 return JVMTI_ITERATION_CONTINUE; 251 } 252 253 /** jvmtiObjectReferenceCallback for second iteration. */ 254 jvmtiIterationControl JNICALL 255 objectReferenceCallbackForSecondObjectsIteration(jvmtiObjectReferenceKind reference_kind, 256 jlong class_tag, 257 jlong size, 258 jlong* tag_ptr, 259 jlong referrer_tag, 260 jint referrer_index, 261 void* user_data) { 262 263 long ind = (long)((*tag_ptr) - 1); 264 265 if (*tag_ptr == 0) return JVMTI_ITERATION_CONTINUE; 266 267 /* 268 ObjectDesc *objectDesc = objectDescArr[ind]; 269 jlong tag = (*objectDesc).tag; 270 */ 271 if (ind < 0 || ind > objectCountMax) { 272 NSK_COMPLAIN1("objectReferenceCallbackForSecondObjectsIteration: invalid object tag value: %d\n", (long)*tag_ptr); 273 nsk_jvmti_setFailStatus(); 274 callbackAborted = 1; 275 return JVMTI_ITERATION_ABORT; 276 } 277 /* 278 NSK_DISPLAY3("objectReferenceCallbackForSecondObjectsIteration: *tag_ptr %6d , tag %6d , objectCount %6d\n", 279 (long)*tag_ptr, (long)tag, objectCount); 280 */ 281 /* Deallocate memory of list element*/ 282 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)objectDescArr[ind]))) { 283 nsk_jvmti_setFailStatus(); 284 callbackAborted = 1; 285 NSK_COMPLAIN0("objectReferenceCallbackForSecondObjectsIteration: Deallocation failed. Iteration aborted.\n"); 286 return JVMTI_ITERATION_ABORT; 287 } 288 289 numberOfDeallocatedFromCallbacksDescriptors++; 290 deallocatedFlagsArr[ind] = 1; 291 292 /* unset tag */ 293 *tag_ptr = 0; 294 objectCount--; 295 296 return JVMTI_ITERATION_CONTINUE; 297 } 298 299 /* ============================================================================= */ 300 301 /** Agent algorithm. */ 302 static void JNICALL 303 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { 304 305 long ind; 306 307 NSK_DISPLAY0("Wait for debugee start\n"); 308 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) 309 return; 310 311 { 312 do { 313 /* Allocate memory for first element of objectList */ 314 if (!NSK_JVMTI_VERIFY(jvmti->Allocate((sizeof(ObjectDesc)), 315 (unsigned char**)&objectDescBuf))) { 316 nsk_jvmti_setFailStatus(); 317 break; 318 } 319 objectDescList = objectDescBuf; 320 objectDescListStart = objectDescList; 321 322 NSK_DISPLAY0("Calling IterateOverReachableObjects with allocating object descriptors\n"); 323 { 324 if (!NSK_JVMTI_VERIFY(jvmti->IterateOverReachableObjects( 325 heapRootCallbackForFirstObjectsIteration, 326 stackReferenceCallbackForFirstObjectsIteration, 327 objectReferenceCallbackForFirstObjectsIteration, 328 &userData))) { 329 nsk_jvmti_setFailStatus(); 330 break; 331 } 332 } 333 if (callbackAborted) break; 334 335 if (objectCount == 0) { 336 NSK_COMPLAIN0("First IterateOverReachableObjects call had not visited any object\n"); 337 nsk_jvmti_setFailStatus(); 338 break; 339 } else { 340 NSK_DISPLAY1("Number of objects the first IterateOverReachableObjects visited: %d\n", objectCount); 341 } 342 343 if (callbackAborted) break; 344 345 objectCountMax = objectCount; 346 347 /* Deallocate last unnecessary descriptor */ 348 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)objectDescList))) { 349 NSK_COMPLAIN0("Unable to deallocate last unnecessary descriptor. \n"); 350 nsk_jvmti_setFailStatus(); 351 break; 352 } 353 354 /* Allocate memory for array to save pointers to ObjectDescList elements */ 355 if (!NSK_JVMTI_VERIFY(jvmti->Allocate((objectCount * sizeof(ObjectDesc*)), 356 (unsigned char**)&objectDescArr))) { 357 nsk_jvmti_setFailStatus(); 358 break; 359 } 360 361 /* Allocate memory for flags array and fill with false values */ 362 if (!NSK_JVMTI_VERIFY(jvmti->Allocate((objectCountMax * sizeof(short)), 363 (unsigned char**)&deallocatedFlagsArr))) { 364 nsk_jvmti_setFailStatus(); 365 break; 366 } 367 368 for (ind = 0; ind < objectCountMax; ind++) { 369 deallocatedFlagsArr[ind] = 0; 370 } 371 372 objectDescList = objectDescListStart; 373 { 374 /* Save all pointers to ObjectDescList elements in objectDescArr */ 375 for (ind = 0; ind < objectCount; ind++) { 376 objectDescArr[ind] = objectDescList; 377 objectDescList = (*objectDescList).next; 378 } 379 } 380 381 NSK_DISPLAY0("Calling IterateOverReachableObjects with deallocating object descriptors\n"); 382 { 383 if (!NSK_JVMTI_VERIFY(jvmti->IterateOverReachableObjects( 384 heapRootCallbackForSecondObjectsIteration, 385 stackReferenceCallbackForSecondObjectsIteration, 386 objectReferenceCallbackForSecondObjectsIteration, 387 &userData))) { 388 nsk_jvmti_setFailStatus(); 389 break; 390 } 391 } 392 393 if (numberOfDeallocatedFromCallbacksDescriptors == 0) { 394 NSK_COMPLAIN1("Deallocate func. hasn't been called from IterateOverReachableObjects'callbacks. " 395 "numberOfDeallocatedFromCallbacksDescriptors = %d\n", numberOfDeallocatedFromCallbacksDescriptors); 396 nsk_jvmti_setFailStatus(); 397 } 398 399 for (ind = 0; ind < objectCountMax; ind++) { 400 if (!deallocatedFlagsArr[ind]) { 401 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)objectDescArr[ind]))) { 402 NSK_COMPLAIN1("Unable to deallocate descriptor. Index = %d \n", ind); 403 nsk_jvmti_setFailStatus(); 404 return; 405 } 406 } 407 } 408 409 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)objectDescArr))) { 410 nsk_jvmti_setFailStatus(); 411 } 412 413 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)deallocatedFlagsArr))) { 414 nsk_jvmti_setFailStatus(); 415 } 416 417 } while (0); 418 } 419 420 NSK_DISPLAY0("Let debugee to finish\n"); 421 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) 422 return; 423 } 424 425 /* ============================================================================= */ 426 427 /* ============================================================================= */ 428 429 /** Agent library initialization. */ 430 #ifdef STATIC_BUILD 431 JNIEXPORT jint JNICALL Agent_OnLoad_iterreachobj002(JavaVM *jvm, char *options, void *reserved) { 432 return Agent_Initialize(jvm, options, reserved); 433 } 434 JNIEXPORT jint JNICALL Agent_OnAttach_iterreachobj002(JavaVM *jvm, char *options, void *reserved) { 435 return Agent_Initialize(jvm, options, reserved); 436 } 437 JNIEXPORT jint JNI_OnLoad_iterreachobj002(JavaVM *jvm, char *options, void *reserved) { 438 return JNI_VERSION_1_8; 439 } 440 #endif 441 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 442 443 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 444 return JNI_ERR; 445 446 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 447 448 if (!NSK_VERIFY((jvmti = 449 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 450 return JNI_ERR; 451 452 memset(&caps, 0, sizeof(caps)); 453 caps.can_tag_objects = 1; 454 caps.can_generate_object_free_events = 1; 455 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) { 456 return JNI_ERR; 457 } 458 459 if (!NSK_JVMTI_VERIFY(jvmti->GetCapabilities(&caps))) 460 return JNI_ERR; 461 462 if (!caps.can_tag_objects) 463 NSK_DISPLAY0("Warning: tagging objects is not available\n"); 464 if (!caps.can_generate_object_free_events) 465 NSK_DISPLAY0("Warning: generation of object free events is not available\n"); 466 467 /* set event callback */ 468 NSK_DISPLAY0("setting event callbacks ...\n"); 469 (void) memset(&callbacks, 0, sizeof(callbacks)); 470 471 callbacks.ObjectFree = &ObjectFree; 472 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)))) 473 return JNI_ERR; 474 475 NSK_DISPLAY0("setting event callbacks done.\n"); 476 477 NSK_DISPLAY0("enabling JVMTI events ...\n"); 478 if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, 479 JVMTI_EVENT_OBJECT_FREE, 480 NULL))) 481 return JNI_ERR; 482 NSK_DISPLAY0("enabling the events done.\n"); 483 484 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 485 return JNI_ERR; 486 487 return JNI_OK; 488 } 489 490 /* ============================================================================= */ 491 492 }