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