1 /*
   2  * Copyright (c) 2013, 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 #include <wchar.h>
  24 #include <string.h>
  25 #include <stdlib.h>
  26 
  27 #include "jvmti.h"
  28 #include "jni_tools.h"
  29 #include "jvmti_tools.h"
  30 #include "agent_common.h"
  31 
  32 extern "C" {
  33 
  34 #define TEST_OBJECT_TAG 0x8000
  35 #define EXPECTED_NON_PRIMITIVES_COUNT 1
  36 #define EXPECTED_PRIMITIVE_VALUE 0xC1A55F1E1DLL
  37 
  38 static int timeout = 0;
  39 
  40 static int field_found = 0;
  41 static int object_unloaded = 0;
  42 static int non_primitive_reported = 0;
  43 
  44 
  45 #define className "nsk/jvmti/IterateThroughHeap/concrete_klass_filter/ConcreteKlassFilter"
  46 #define fieldName "testObject"
  47 #define fieldSig "Ljava/lang/Object;"
  48 #define testClassName "nsk/jvmti/IterateThroughHeap/concrete_klass_filter/TestClass"
  49 
  50 
  51 jint JNICALL field_callback(jvmtiHeapReferenceKind kind,
  52                             const jvmtiHeapReferenceInfo* info,
  53                             jlong object_class_tag,
  54                             jlong* object_tag_ptr,
  55                             jvalue value,
  56                             jvmtiPrimitiveType value_type,
  57                             void* user_data) {
  58   //only field of our test object are expected
  59   if(*object_tag_ptr != TEST_OBJECT_TAG) {
  60     NSK_COMPLAIN2("jvmtiPrimitiveFieldCallback was invoked for primitive "
  61                   "field with unexpected class tag 0x%lX and object tag 0x%lX.\n",
  62                   object_class_tag, *object_tag_ptr);
  63     nsk_jvmti_setFailStatus();
  64     return 0;
  65   }
  66   //expected field is long
  67   if(value_type != JVMTI_PRIMITIVE_TYPE_LONG) {
  68     NSK_COMPLAIN0("jvmtiPrimitiveFieldCallback was invoked for non-long field.\n");
  69     nsk_jvmti_setFailStatus();
  70     return 0;
  71   }
  72   //check value
  73   if(value.j != EXPECTED_PRIMITIVE_VALUE) {
  74     NSK_COMPLAIN0("Unexpected value was passed to jvmtiPrimitiveFieldCallback.\n");
  75     NSK_COMPLAIN1("Expected value: 0x%lX.\n", EXPECTED_PRIMITIVE_VALUE);
  76     NSK_COMPLAIN1("Passed value: 0x%lX.\n", value.j);
  77     nsk_jvmti_setFailStatus();
  78   } else {
  79     field_found++;
  80   }
  81   return 0;
  82 }
  83 
  84 jint JNICALL string_callback(jlong class_tag,
  85                              jlong size,
  86                              jlong* tag_ptr,
  87                              const jchar* value,
  88                              jint value_length,
  89                              void* user_data) {
  90   //strings are not expected
  91   NSK_COMPLAIN2("jvmtiStringPrimitiveValueCallback was invoked for object "
  92                 "with class tag 0x%lX and object tag 0x%lX.\n",class_tag,*tag_ptr);
  93   nsk_jvmti_setFailStatus();
  94   return 0;
  95 }
  96 
  97 jint JNICALL array_callback(jlong class_tag,
  98                             jlong size,
  99                             jlong* tag_ptr,
 100                             jint element_count,
 101                             jvmtiPrimitiveType element_type,
 102                             const void* elements,
 103                             void* user_data) {
 104   //arrays are not expected
 105   NSK_COMPLAIN2("jvmtiArrayPrimitiveValueCallback was invoked for object "
 106                 "with class tag 0x%lX and object tag 0x%lX.\n",class_tag,*tag_ptr);
 107   nsk_jvmti_setFailStatus();
 108   return 0;
 109 }
 110 
 111 jint JNICALL heap_callback(jlong class_tag,
 112                            jlong size,
 113                            jlong* tag_ptr,
 114                            jint length,
 115                            void* user_data) {
 116   //test object have to be reported by this callback
 117   if(*tag_ptr != TEST_OBJECT_TAG) {
 118     NSK_COMPLAIN2("Object with unexpected class tag 0x%lX and object tag 0x%lX "
 119                   "was passed to jvmtiHeapIterationCallback.\n", class_tag, *tag_ptr);
 120     nsk_jvmti_setFailStatus();
 121     return 0;
 122   }
 123 
 124   non_primitive_reported++;
 125 
 126   if(non_primitive_reported>EXPECTED_NON_PRIMITIVES_COUNT) {
 127     NSK_COMPLAIN1("Test object was reported more than %d times.\n",
 128                   EXPECTED_NON_PRIMITIVES_COUNT);
 129     nsk_jvmti_setFailStatus();
 130   }
 131 
 132   return 0;
 133 }
 134 
 135 JNIEXPORT void JNICALL
 136 object_free_callback(jvmtiEnv* jvmti, jlong tag) {
 137   if(tag != TEST_OBJECT_TAG) {
 138     NSK_COMPLAIN1("object free callback was invoked for an object with "
 139                   "unexpected tag 0x%lX.\n",tag);
 140     nsk_jvmti_setFailStatus();
 141   } else {
 142     object_unloaded = 1;
 143   }
 144 }
 145 
 146 /**
 147  * Tag test object and it's class.
 148  */
 149 int tag_objects(jvmtiEnv *jvmti, JNIEnv *jni) {
 150   jclass debugee;
 151   jfieldID testObjectField;
 152   jobject testObject;
 153   jclass testObjectClass;
 154 
 155   if(!NSK_VERIFY(NULL != (debugee = jni->FindClass(className))))
 156     return JNI_ERR;
 157 
 158   if(!NSK_VERIFY(NULL != (testObjectField = jni->GetStaticFieldID(debugee, fieldName, fieldSig))))
 159     return JNI_ERR;
 160 
 161   if(!NSK_VERIFY(NULL != (testObject = (jni->GetStaticObjectField(debugee, testObjectField)))))
 162     return JNI_ERR;
 163 
 164   if(!NSK_VERIFY(NULL != (testObjectClass = (jni->GetObjectClass(testObject)))))
 165     return JNI_ERR;
 166 
 167   // tag class and it's instance to pass this tag into primitive field callback
 168   if(!NSK_JVMTI_VERIFY(jvmti->SetTag(testObject, TEST_OBJECT_TAG)))
 169     return JNI_ERR;
 170   if(!NSK_JVMTI_VERIFY(jvmti->SetTag(testObjectClass, TEST_OBJECT_TAG)))
 171     return JNI_ERR;
 172 
 173   jni->DeleteLocalRef(testObjectClass);
 174   jni->DeleteLocalRef(testObject);
 175 
 176   return JNI_OK;
 177 }
 178 
 179 void verify_objects() {
 180   //if test object was not unloaded then it's field expected to be found once.
 181   if(object_unloaded) return;
 182   if(field_found == 0) {
 183     NSK_COMPLAIN0("TestClass instance field was not found.\n");
 184     nsk_jvmti_setFailStatus();
 185   } if (field_found > 1) {
 186     NSK_COMPLAIN1("TestClass instance field was reported more than once: %d times.\n",
 187                   field_found);
 188     nsk_jvmti_setFailStatus();
 189   }
 190   field_found = 0;
 191   non_primitive_reported = 0;
 192 }
 193 
 194 static void JNICALL
 195 agent(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
 196   jvmtiEvent event = JVMTI_EVENT_OBJECT_FREE;
 197   jvmtiHeapCallbacks primitive_callbacks;
 198   jclass klass;
 199 
 200   if(!NSK_VERIFY(NULL != (klass = jni->FindClass(testClassName)))) {
 201     NSK_COMPLAIN1("Can't find class %s.\n",testClassName);
 202     nsk_jvmti_setFailStatus();
 203     return;
 204   }
 205 
 206   NSK_DISPLAY0("Waiting debugee.\n");
 207   if(!NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_ENABLE, 1, &event, NULL))) {
 208     return;
 209   }
 210   if(!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) {
 211     return;
 212   }
 213 
 214   NSK_DISPLAY0("Tagging fields.\n");
 215   if(!NSK_VERIFY(JNI_OK==tag_objects(jvmti, jni))) {
 216     return;
 217   }
 218 
 219   memset(&primitive_callbacks, 0, sizeof(jvmtiHeapCallbacks));
 220   primitive_callbacks.primitive_field_callback = &field_callback;
 221   primitive_callbacks.array_primitive_value_callback = &array_callback;
 222   primitive_callbacks.string_primitive_value_callback = &string_callback;
 223   primitive_callbacks.heap_iteration_callback = &heap_callback;
 224 
 225   NSK_DISPLAY0("Iterating over reachable objects.\n");
 226   if(!NSK_JVMTI_VERIFY(jvmti->IterateThroughHeap(0, klass, &primitive_callbacks, NULL))) {
 227     nsk_jvmti_setFailStatus();
 228     return;
 229   }
 230 
 231   NSK_DISPLAY0("Verifying that all filds were found.\n");
 232   verify_objects();
 233 
 234   if(!NSK_VERIFY(nsk_jvmti_resumeSync())) {
 235     return;
 236   }
 237 
 238   if(!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) {
 239     return;
 240   }
 241 
 242   NSK_DISPLAY0("Iterating over unreachable objects.\n");
 243   if(!NSK_JVMTI_VERIFY(jvmti->IterateThroughHeap(0, klass, &primitive_callbacks, NULL))) {
 244     nsk_jvmti_setFailStatus();
 245     return;
 246   }
 247 
 248   NSK_DISPLAY0("Verifying that all filds were found.\n");
 249   verify_objects();
 250 
 251   if(!NSK_VERIFY(nsk_jvmti_resumeSync()))
 252     return;
 253 }
 254 
 255 #ifdef STATIC_BUILD
 256 JNIEXPORT jint JNICALL Agent_OnLoad_ConcreteKlassFilter(JavaVM *jvm, char *options, void *reserved) {
 257     return Agent_Initialize(jvm, options, reserved);
 258 }
 259 JNIEXPORT jint JNICALL Agent_OnAttach_ConcreteKlassFilter(JavaVM *jvm, char *options, void *reserved) {
 260     return Agent_Initialize(jvm, options, reserved);
 261 }
 262 JNIEXPORT jint JNI_OnLoad_ConcreteKlassFilter(JavaVM *jvm, char *options, void *reserved) {
 263     return JNI_VERSION_1_8;
 264 }
 265 #endif
 266 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 267   jvmtiEnv *jvmti;
 268   jvmtiCapabilities caps;
 269   jvmtiEventCallbacks event_callbacks;
 270 
 271   if(!NSK_VERIFY((jvmti = nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) {
 272     return JNI_ERR;
 273   }
 274 
 275   nsk_jvmti_parseOptions(options);
 276 
 277   timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
 278 
 279   memset(&caps, 0, sizeof(caps));
 280   caps.can_tag_objects = 1;
 281   caps.can_generate_object_free_events = 1;
 282 
 283   if(!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) {
 284     return JNI_ERR;
 285   }
 286 
 287   memset(&event_callbacks, 0, sizeof(jvmtiEventCallbacks));
 288   event_callbacks.ObjectFree = &object_free_callback;
 289   if(!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&event_callbacks, sizeof(jvmtiEventCallbacks)))) {
 290     return JNI_ERR;
 291   }
 292 
 293   if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agent, NULL))) {
 294     return JNI_ERR;
 295   }
 296 
 297   return JNI_OK;
 298 }
 299 
 300 }