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 }