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 STATIC_FIELD 0x0008 35 36 /* 37 For this test tags have following format: 38 |63 48| 32| 16| 0| 39 |<not used> |tag type|obj idx|fld idx| 40 */ 41 42 #define FIELD_TAG 1 43 #define OBJECT_TAG 2 44 #define CLASS_TAG 4 45 46 #define ENCODE_TAG(type, obj, fld) (((jlong)type)<<32 | ((jlong)obj)<<16 | (jlong)fld) 47 #define DECODE_TYPE(tag) tag>>32 48 #define DECODE_OBJECT(tag) ((tag>>16)&0xFFFF) 49 #define DECODE_FIELD(tag) (tag&0xFFFF) 50 51 #define TEST_OBJECTS_COUNT 2 52 #define TAGGED_OBJECTS 1 53 54 static long timeout = 0; 55 static int filter_type = -1; 56 57 // by default at least one object will be reported regardless to filter type 58 static int expected_object_count = 1; 59 static int reported_objects = 0; 60 61 //expected values 62 #define INT_ARRAY_LENGTH 2 63 64 static jint TAGGED_STATIC_INT_VALUE = 0xC0DE01; 65 static jint TAGGED_INT_VALUE = 0xC0DE02; 66 static jint UNTAGGED_STATIC_INT_VALUE = 0xC0DE03; 67 static jint UNTAGGED_INT_VALUE = 0xC0DE04; 68 static jint TAGGED_INT_ARRAY_VALUE[] = {0xC0DE01, 69 0xC0DE01+1}; 70 static jint UNTAGGED_INT_ARRAY_VALUE[] = {0xC0DE03, 71 0xC0DE03+1}; 72 static const wchar_t *TAGGED_STRING_VALUE = L"I'm a tagged string"; 73 static const wchar_t *UNTAGGED_STRING_VALUE = L"I'm an untagged string"; 74 75 //kind of field 76 #define TYPE_FIELD 1 77 #define TYPE_ARRAY 2 78 #define TYPE_STRING 4 79 80 //field info 81 typedef struct { 82 char *name; 83 char *signature; 84 int found; 85 int collected; 86 int primitive; 87 int expected; 88 int type; 89 void *value; 90 int size; 91 } field_info_t; 92 93 //object info 94 typedef struct { 95 char *name; 96 jint fields_count; 97 field_info_t *fields; 98 int collected; 99 } object_info_t; 100 101 static object_info_t objects_info[TEST_OBJECTS_COUNT]; 102 103 #define className "nsk/jvmti/IterateThroughHeap/filter_tagged/HeapFilter" 104 #define fieldName "testObjects" 105 #define fieldSig "[Ljava/lang/Object;" 106 #define STRING_SIGNATURE "Ljava/lang/String;" 107 #define INT_ARRAY_SIGNATURE "[I" 108 109 // Check if the signature is signature of primitive type. 110 jboolean is_primitive_type(const char *signature) { 111 if (!strcmp(signature,"C") 112 || !strcmp(signature, "B") 113 || !strcmp(signature, "S") 114 || !strcmp(signature, "I") 115 || !strcmp(signature, "J") 116 || !strcmp(signature, "F") 117 || !strcmp(signature, "D") 118 || !strcmp(signature, "Z")) 119 return JNI_TRUE; 120 return JNI_FALSE; 121 } 122 123 //check tag values accoring to heap filter choosed for test 124 jboolean verify_tag(jlong class_tag, jlong object_tag) { 125 switch (filter_type) { 126 case JVMTI_HEAP_FILTER_TAGGED: 127 return object_tag == 0; 128 case JVMTI_HEAP_FILTER_UNTAGGED: 129 return object_tag != 0; 130 case JVMTI_HEAP_FILTER_CLASS_TAGGED: 131 return class_tag == 0; 132 case JVMTI_HEAP_FILTER_CLASS_UNTAGGED: 133 return class_tag != 0; 134 default: 135 return JNI_FALSE; 136 } 137 } 138 139 //check whether or not field expected to be reported 140 jboolean occurance_expected(int tagged, int is_static, int is_primitive) { 141 switch (filter_type) { 142 case JVMTI_HEAP_FILTER_TAGGED: 143 return !tagged; 144 case JVMTI_HEAP_FILTER_UNTAGGED: 145 return tagged; 146 case JVMTI_HEAP_FILTER_CLASS_TAGGED: 147 return (is_static && is_primitive) || !is_primitive || !tagged; 148 case JVMTI_HEAP_FILTER_CLASS_UNTAGGED: 149 return !is_static && is_primitive && tagged; 150 default: 151 return JNI_ERR; 152 } 153 } 154 155 jint JNICALL field_callback(jvmtiHeapReferenceKind kind, 156 const jvmtiHeapReferenceInfo* info, 157 jlong object_class_tag, 158 jlong* object_tag_ptr, 159 jvalue value, 160 jvmtiPrimitiveType value_type, 161 void* user_data) { 162 int object; 163 int field; 164 if (!NSK_VERIFY(verify_tag(object_class_tag, *object_tag_ptr))) { 165 nsk_jvmti_setFailStatus(); 166 } 167 168 //iterate over all fields found during tagging and compare reported value 169 //with their values. 170 if (value_type != JVMTI_PRIMITIVE_TYPE_INT) 171 return 0; 172 for (object = 0; object < TEST_OBJECTS_COUNT; object++) { 173 for (field = 0; field < objects_info[object].fields_count; field++) { 174 if (objects_info[object].fields[field].type == TYPE_FIELD && 175 *(jint*)(objects_info[object].fields[field].value) == value.i) { 176 objects_info[object].fields[field].found++; 177 } 178 } 179 } 180 return 0; 181 } 182 183 jint JNICALL string_callback(jlong class_tag, 184 jlong size, 185 jlong* tag_ptr, 186 const jchar* value, 187 jint value_length, 188 void* user_data) { 189 int object; 190 int field; 191 if (!NSK_VERIFY(verify_tag(class_tag, *tag_ptr))) { 192 nsk_jvmti_setFailStatus(); 193 } 194 for (object = 0; object < TEST_OBJECTS_COUNT; object++) { 195 for (field = 0; field < objects_info[object].fields_count; field++) { 196 if (objects_info[object].fields[field].type == TYPE_STRING && 197 value_length == objects_info[object].fields[field].size) { 198 int matched = 1; 199 int i; 200 wchar_t *str = (wchar_t*)objects_info[object].fields[field].value; 201 for (i = 0; i < value_length && matched; i++) { 202 matched = (str[i] == value[i]); 203 } 204 if (matched) 205 objects_info[object].fields[field].found++; 206 } 207 } 208 } 209 return 0; 210 } 211 212 213 jint JNICALL array_callback(jlong class_tag, 214 jlong size, 215 jlong* tag_ptr, 216 jint element_count, 217 jvmtiPrimitiveType element_type, 218 const void* elements, 219 void* user_data) { 220 int object; 221 int field; 222 if (!NSK_VERIFY(verify_tag(class_tag, *tag_ptr))) { 223 nsk_jvmti_setFailStatus(); 224 } 225 for (object = 0; object < TEST_OBJECTS_COUNT; object++) { 226 for (field = 0; field < objects_info[object].fields_count; field++) { 227 if (objects_info[object].fields[field].type == TYPE_ARRAY && 228 element_count == objects_info[object].fields[field].size) { 229 int matched = 1; 230 int i; 231 for (i = 0; i < element_count && matched; i++) { 232 matched = ((jint*)objects_info[object].fields[field].value)[i]== 233 ((jint*)elements)[i]; 234 } 235 if (matched) 236 objects_info[object].fields[field].found++; 237 } 238 } 239 } 240 return 0; 241 } 242 243 jint JNICALL heap_callback(jlong class_tag, 244 jlong size, 245 jlong* tag_ptr, 246 jint length, 247 void* user_data) { 248 if (!NSK_VERIFY(verify_tag(class_tag, *tag_ptr))) { 249 NSK_COMPLAIN0("Tag values invalid for selected heap filter were passed " 250 "to jvmtiHeapIterationCallback.\n"); 251 NSK_COMPLAIN2("\tClass tag: 0x%lX;\n\tObject tag: 0x%lX.\n", class_tag, *tag_ptr); 252 nsk_jvmti_setFailStatus(); 253 } 254 reported_objects++; 255 return 0; 256 } 257 258 JNIEXPORT void JNICALL 259 object_free_callback(jvmtiEnv* jvmti, jlong tag) { 260 if (DECODE_TYPE(tag) == OBJECT_TAG) { 261 objects_info[DECODE_OBJECT(tag)].collected = 1; 262 } else if (DECODE_TYPE(tag) == FIELD_TAG) { 263 objects_info[DECODE_OBJECT(tag)].fields[DECODE_FIELD(tag)].collected = 1; 264 } 265 } 266 267 //set expected fields value according to it's type 268 void set_expected_value(field_info_t *field, int tagged, int is_static) { 269 if (field->primitive) { 270 field->size = (int) sizeof(jint); 271 if (is_static) { 272 field->value = (void*)(tagged ? &TAGGED_STATIC_INT_VALUE: 273 &UNTAGGED_STATIC_INT_VALUE); 274 } else { 275 field->value = (void*)(tagged ? &TAGGED_INT_VALUE: 276 &UNTAGGED_INT_VALUE); 277 } 278 field->type = TYPE_FIELD; 279 } else if (0==strcmp(field->signature,STRING_SIGNATURE)) { 280 field->value = (void*)(tagged ? TAGGED_STRING_VALUE: 281 UNTAGGED_STRING_VALUE); 282 field->size = (int) wcslen((wchar_t*)field->value); 283 field->type = TYPE_STRING; 284 } else if (0==strcmp(field->signature,INT_ARRAY_SIGNATURE)) { 285 field->size = INT_ARRAY_LENGTH; 286 field->value = (void*)(tagged ? TAGGED_INT_ARRAY_VALUE: 287 UNTAGGED_INT_ARRAY_VALUE); 288 field->type = TYPE_ARRAY; 289 } 290 } 291 292 /** 293 * Read array of test objects. 294 * Tag each of these objects, their classes, non-primitive fields and non-primitive fields classes. 295 */ 296 int tag_objects(jvmtiEnv *jvmti, JNIEnv *jni) { 297 jclass debugee; 298 jfieldID testObjectsField; 299 jobjectArray testObjects; 300 int object; 301 302 if (!NSK_VERIFY(NULL != (debugee = jni->FindClass(className)))) 303 return JNI_ERR; 304 305 if (!NSK_VERIFY(NULL != (testObjectsField = jni->GetStaticFieldID(debugee, fieldName, fieldSig)))) 306 return JNI_ERR; 307 308 if (!NSK_VERIFY(NULL != (testObjects = (jobjectArray)(jni->GetStaticObjectField( 309 debugee, testObjectsField))))) 310 return JNI_ERR; 311 312 // For each of test objects tag every field 313 for (object = 0; object<TEST_OBJECTS_COUNT; object++) { 314 jobject target; 315 jclass targetClass; 316 jfieldID *targetFields; 317 jint field; 318 int tagged = object == 0; 319 320 memset(&objects_info[object],0,sizeof(object_info_t)); 321 if (!NSK_VERIFY(NULL != (target = jni->GetObjectArrayElement(testObjects, object)))) 322 return JNI_ERR; 323 324 if (!NSK_VERIFY(NULL != (targetClass = jni->GetObjectClass(target)))) 325 return JNI_ERR; 326 327 if (!NSK_JVMTI_VERIFY(jvmti->GetClassSignature(targetClass, &(objects_info[object].name), NULL))) 328 return JNI_ERR; 329 330 if (!NSK_JVMTI_VERIFY(jvmti->GetClassFields( 331 targetClass, &(objects_info[object].fields_count), &targetFields))) 332 return JNI_ERR; 333 334 objects_info[object].fields = (field_info_t*)calloc(objects_info[object].fields_count,sizeof(field_info_t)); 335 336 // Iterate over fields, collect info about it and tag non primitive fields. 337 for (field = 0; field < objects_info[object].fields_count; field++) { 338 jint modifiers; 339 int is_static = 0; 340 int is_primitive = 0; 341 if (!NSK_JVMTI_VERIFY(jvmti->GetFieldName(targetClass, 342 targetFields[field], 343 &objects_info[object].fields[field].name, 344 &objects_info[object].fields[field].signature, 345 NULL))) 346 return JNI_ERR; 347 if (!NSK_JVMTI_VERIFY(jvmti->GetFieldModifiers( 348 targetClass, targetFields[field], &modifiers))) { 349 return JNI_ERR; 350 } 351 is_static = (modifiers & STATIC_FIELD) == STATIC_FIELD; 352 if (is_primitive_type(objects_info[object].fields[field].signature)) { 353 objects_info[object].fields[field].primitive = 1; 354 is_primitive = 1; 355 } else { 356 jobject value; 357 if (!NSK_JVMTI_VERIFY(jvmti->GetFieldModifiers( 358 targetClass, targetFields[field], &modifiers))) { 359 return JNI_ERR; 360 } 361 if (is_static) { 362 if (!NSK_VERIFY(NULL != (value = jni->GetStaticObjectField( 363 targetClass, targetFields[field])))) { 364 return JNI_ERR; 365 } 366 } else { 367 if (!NSK_VERIFY(NULL != (value = jni->GetObjectField(target, targetFields[field])))) { 368 return JNI_ERR; 369 } 370 } 371 if (tagged) { 372 if (!NSK_JVMTI_VERIFY(jvmti->SetTag(value, ENCODE_TAG(FIELD_TAG,object,field)))) { 373 return JNI_ERR; 374 } 375 } 376 jni->DeleteLocalRef(value); 377 } 378 379 objects_info[object].fields[field].expected = 380 occurance_expected(tagged,is_static,is_primitive); 381 expected_object_count += 382 objects_info[object].fields[field].expected && !is_primitive; 383 set_expected_value(&objects_info[object].fields[field], tagged, is_static); 384 } 385 386 // tag class and it's instance to pass this tag into primitive field callback 387 if (tagged) { 388 if (!NSK_JVMTI_VERIFY(jvmti->SetTag(target, ENCODE_TAG(OBJECT_TAG,object,0)))) 389 return JNI_ERR; 390 if (!NSK_JVMTI_VERIFY(jvmti->SetTag(targetClass, ENCODE_TAG(CLASS_TAG,object,0)))) 391 return JNI_ERR; 392 } 393 394 NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)targetFields)); 395 jni->DeleteLocalRef(target); 396 jni->DeleteLocalRef(targetClass); 397 } 398 399 jni->DeleteLocalRef(testObjects); 400 401 return JNI_OK; 402 } 403 404 405 //release resources allocated in tag_objects 406 void release_object_info(jvmtiEnv *jvmti, JNIEnv *jni) { 407 int object; 408 int field; 409 for (object = 0; object < TEST_OBJECTS_COUNT; object++) { 410 for (field = 0; field < objects_info[object].fields_count; field++) { 411 jvmti->Deallocate((unsigned char*)objects_info[object].fields[field].name); 412 jvmti->Deallocate((unsigned char*)objects_info[object].fields[field].signature); 413 } 414 jvmti->Deallocate((unsigned char*)objects_info[object].name); 415 free(objects_info[object].fields); 416 } 417 } 418 419 // Check that every field was found expected amount of times 420 void verify_objects(int reachable) { 421 int object; 422 int field; 423 for (object = 0; object < (reachable?TEST_OBJECTS_COUNT:TAGGED_OBJECTS); object++) { 424 for (field = 0; field < objects_info[object].fields_count; field++) { 425 // If primitive field of object that was not collected or 426 // non primitive field that was not collected was not found 427 // expected amount of times, than test failed. 428 if ((objects_info[object].fields[field].primitive && 429 !objects_info[object].collected) 430 || 431 (!objects_info[object].fields[field].primitive && 432 !objects_info[object].fields[field].collected)) { 433 if (objects_info[object].fields[field].expected != 434 objects_info[object].fields[field].found) { 435 NSK_COMPLAIN4("Field %s::%s expected to be found %d times, " 436 "but it was found %d times.\n", 437 objects_info[object].name, 438 objects_info[object].fields[field].name, 439 objects_info[object].fields[field].expected, 440 objects_info[object].fields[field].found); 441 nsk_jvmti_setFailStatus(); 442 } 443 } 444 objects_info[object].fields[field].found = 0; 445 } 446 } 447 } 448 449 static void JNICALL 450 agent(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { 451 jvmtiEvent event = JVMTI_EVENT_OBJECT_FREE; 452 jvmtiHeapCallbacks primitive_callbacks; 453 jvmtiEventCallbacks event_callbacks; 454 455 NSK_DISPLAY0("Waiting debugee.\n"); 456 if (!NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_ENABLE, 1, &event, NULL))) { 457 return; 458 } 459 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) { 460 return; 461 } 462 463 NSK_DISPLAY0("Tagging fields.\n"); 464 if (!NSK_VERIFY(JNI_OK==tag_objects(jvmti, jni))) { 465 return; 466 } 467 468 memset(&primitive_callbacks, 0, sizeof(jvmtiHeapCallbacks)); 469 primitive_callbacks.primitive_field_callback = &field_callback; 470 primitive_callbacks.array_primitive_value_callback = &array_callback; 471 primitive_callbacks.string_primitive_value_callback = &string_callback; 472 primitive_callbacks.heap_iteration_callback = &heap_callback; 473 474 NSK_DISPLAY0("Iterating over reachable objects.\n"); 475 if (!NSK_JVMTI_VERIFY(jvmti->IterateThroughHeap(filter_type, NULL, &primitive_callbacks, NULL))) { 476 nsk_jvmti_setFailStatus(); 477 return; 478 } 479 480 NSK_DISPLAY0("Verifying that all fields were found.\n"); 481 verify_objects(1); 482 483 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { 484 return; 485 } 486 487 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) { 488 return; 489 } 490 491 NSK_DISPLAY0("Iterating over unreachable objects.\n"); 492 if (!NSK_JVMTI_VERIFY(jvmti->IterateThroughHeap(filter_type, NULL, &primitive_callbacks, NULL))) { 493 nsk_jvmti_setFailStatus(); 494 return; 495 } 496 497 NSK_DISPLAY0("Verifying that all fields were found.\n"); 498 verify_objects(0); 499 500 /* 501 * This is done to clear event_callbacks.ObjectFree before we call release_object_info(), 502 * since it will free some memory that the callback will access. 503 */ 504 memset(&event_callbacks, 0, sizeof(jvmtiEventCallbacks)); 505 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&event_callbacks, sizeof(jvmtiEventCallbacks)))) { 506 return; 507 } 508 509 release_object_info(jvmti, jni); 510 511 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) 512 return; 513 } 514 515 #ifdef STATIC_BUILD 516 JNIEXPORT jint JNICALL Agent_OnLoad_HeapFilter(JavaVM *jvm, char *options, void *reserved) { 517 return Agent_Initialize(jvm, options, reserved); 518 } 519 JNIEXPORT jint JNICALL Agent_OnAttach_HeapFilter(JavaVM *jvm, char *options, void *reserved) { 520 return Agent_Initialize(jvm, options, reserved); 521 } 522 JNIEXPORT jint JNI_OnLoad_HeapFilter(JavaVM *jvm, char *options, void *reserved) { 523 return JNI_VERSION_1_8; 524 } 525 #endif 526 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 527 jvmtiEnv *jvmti; 528 jvmtiCapabilities caps; 529 jvmtiEventCallbacks event_callbacks; 530 const char *type; 531 532 jvmti = nsk_jvmti_createJVMTIEnv(jvm, reserved); 533 if (!NSK_VERIFY(jvmti != NULL)) { 534 return JNI_ERR; 535 } 536 537 nsk_jvmti_parseOptions(options); 538 539 type = nsk_jvmti_findOptionValue("filter"); 540 if (type != NULL) { 541 if (0 == strcmp(type, "JVMTI_HEAP_FILTER_TAGGED")) { 542 filter_type = JVMTI_HEAP_FILTER_TAGGED; 543 } else if (0 == strcmp(type, "JVMTI_HEAP_FILTER_UNTAGGED")) { 544 filter_type = JVMTI_HEAP_FILTER_UNTAGGED; 545 } else if (0 == strcmp(type, "JVMTI_HEAP_FILTER_CLASS_TAGGED")) { 546 filter_type = JVMTI_HEAP_FILTER_CLASS_TAGGED; 547 } else if (0 == strcmp(type, "JVMTI_HEAP_FILTER_CLASS_UNTAGGED")) { 548 filter_type = JVMTI_HEAP_FILTER_CLASS_UNTAGGED; 549 } else { 550 NSK_COMPLAIN1("unknown filter value '%s'.\n",type); 551 return JNI_ERR; 552 } 553 } else { 554 NSK_COMPLAIN0("filter option shound be presented.\n"); 555 return JNI_ERR; 556 } 557 558 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 559 560 memset(&caps, 0, sizeof(caps)); 561 caps.can_tag_objects = 1; 562 caps.can_generate_object_free_events = 1; 563 564 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) { 565 return JNI_ERR; 566 } 567 568 memset(&event_callbacks, 0, sizeof(jvmtiEventCallbacks)); 569 event_callbacks.ObjectFree = &object_free_callback; 570 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&event_callbacks, sizeof(jvmtiEventCallbacks)))) { 571 return JNI_ERR; 572 } 573 574 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agent, NULL))) { 575 return JNI_ERR; 576 } 577 578 return JNI_OK; 579 } 580 581 }