1 /* 2 * Copyright (c) 2017, Google 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 <stdio.h> 25 #include <string.h> 26 #include "jvmti.h" 27 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 32 #ifndef JNI_ENV_ARG 33 34 #ifdef __cplusplus 35 #define JNI_ENV_ARG(x, y) y 36 #define JNI_ENV_PTR(x) x 37 #else 38 #define JNI_ENV_ARG(x,y) x, y 39 #define JNI_ENV_PTR(x) (*x) 40 #endif 41 42 #endif 43 44 #define PASSED 0 45 #define FAILED 2 46 47 #define MAX_TRACES 400 48 49 static const char *EXC_CNAME = "java/lang/Exception"; 50 static jvmtiEnv *jvmti = NULL; 51 52 static int check_error(jvmtiError err, const char* s) { 53 if (err != JVMTI_ERROR_NONE) { 54 printf(" ## %s error: %d\n", s, err); 55 return 1; 56 } 57 return 0; 58 } 59 60 static int check_capability_error(jvmtiError err, const char* s) { 61 if (err != JVMTI_ERROR_NONE) { 62 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) { 63 return 0; 64 } 65 printf(" ## %s error: %d\n", s, err); 66 return 1; 67 } 68 return 1; 69 } 70 71 static 72 jint throw_exc(JNIEnv *env, char *msg) { 73 jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME)); 74 75 if (exc_class == NULL) { 76 printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME); 77 return -1; 78 } 79 return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg); 80 } 81 82 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 83 84 JNIEXPORT 85 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 86 return Agent_Initialize(jvm, options, reserved); 87 } 88 89 JNIEXPORT 90 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 91 return Agent_Initialize(jvm, options, reserved); 92 } 93 94 JNIEXPORT 95 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 96 return JNI_VERSION_1_8; 97 } 98 99 JNIEXPORT void JNICALL OnVMInit(jvmtiEnv *jvmti, JNIEnv *jni_env, jthread thread) { 100 } 101 102 JNIEXPORT void JNICALL OnClassLoad(jvmtiEnv *jvmti_env, JNIEnv *jni_env, 103 jthread thread, jclass klass) { 104 // NOP. 105 } 106 107 JNIEXPORT void JNICALL OnClassPrepare(jvmtiEnv *jvmti_env, JNIEnv *jni_env, 108 jthread thread, jclass klass) { 109 // We need to do this to "prime the pump", as it were -- make sure 110 // that all of the methodIDs have been initialized internally, for 111 // AsyncGetCallTrace. 112 jint method_count; 113 jmethodID *methods = 0; 114 jvmtiError err = (*jvmti)->GetClassMethods(jvmti, klass, &method_count, &methods); 115 if ((err != JVMTI_ERROR_NONE) && (err != JVMTI_ERROR_CLASS_NOT_PREPARED)) { 116 // JVMTI_ERROR_CLASS_NOT_PREPARED is okay because some classes may 117 // be loaded but not prepared at this point. 118 throw_exc(jni_env, "Failed to create method IDs for methods in class\n"); 119 } 120 } 121 122 static 123 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 124 jint res; 125 126 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), 127 JVMTI_VERSION_9); 128 if (res != JNI_OK || jvmti == NULL) { 129 printf(" Error: wrong result of a valid call to GetEnv!\n"); 130 return JNI_ERR; 131 } 132 133 jvmtiEventCallbacks callbacks; 134 memset(&callbacks, 0, sizeof(callbacks)); 135 136 callbacks.VMInit = &OnVMInit; 137 callbacks.ClassLoad = &OnClassLoad; 138 callbacks.ClassPrepare = &OnClassPrepare; 139 140 jvmtiCapabilities caps; 141 memset(&caps, 0, sizeof(caps)); 142 // Get line numbers, sample heap, and filename for the test. 143 caps.can_get_line_numbers = 1; 144 caps.can_sample_heap= 1; 145 caps.can_get_source_file_name = 1; 146 if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), 147 "Add capabilities\n")){ 148 return JNI_ERR; 149 } 150 151 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks, 152 sizeof(jvmtiEventCallbacks)), 153 " Set Event Callbacks")) { 154 return JNI_ERR; 155 } 156 if (check_error((*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 157 JVMTI_EVENT_VM_INIT, NULL), 158 "Set Event for VM Init")) { 159 return JNI_ERR; 160 } 161 if (check_error((*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 162 JVMTI_EVENT_CLASS_LOAD, NULL), 163 "Set Event for Class Load")) { 164 return JNI_ERR; 165 } 166 if (check_error( (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 167 JVMTI_EVENT_CLASS_PREPARE, NULL), 168 "Set Event for Class Prepare")) { 169 return JNI_ERR; 170 } 171 172 return JNI_OK; 173 } 174 175 // Given a method and a location, this method gets the line number. 176 // Kind of expensive, comparatively. 177 static 178 jint get_line_number(jvmtiEnv *jvmti, jmethodID method, jlocation location) { 179 // The location is -1 if the bci isn't known or -3 for a native method. 180 if (location == -1 || location == -3) { 181 return -1; 182 } 183 184 // Read the line number table. 185 jvmtiLineNumberEntry *table_ptr = 0; 186 jint line_number_table_entries; 187 int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method, 188 &line_number_table_entries, 189 &table_ptr); 190 191 if (JVMTI_ERROR_NONE != jvmti_error) { 192 return -1; 193 } 194 if (line_number_table_entries <= 0) { 195 return -1; 196 } 197 if (line_number_table_entries == 1) { 198 return table_ptr[0].line_number; 199 } 200 201 // Go through all the line numbers... 202 jint last_location = table_ptr[0].start_location; 203 int l; 204 for (l = 1; l < line_number_table_entries; l++) { 205 // ... and if you see one that is in the right place for your 206 // location, you've found the line number! 207 if ((location < table_ptr[l].start_location) && 208 (location >= last_location)) { 209 return table_ptr[l - 1].line_number; 210 } 211 last_location = table_ptr[l].start_location; 212 } 213 214 if (location >= last_location) { 215 return table_ptr[line_number_table_entries - 1].line_number; 216 } else { 217 return -1; 218 } 219 } 220 221 typedef struct _ExpectedContentFrame { 222 const char *name; 223 const char *signature; 224 const char *file_name; 225 int line_number; 226 } ExpectedContentFrame; 227 228 static jint check_sample_content(JNIEnv *env, 229 jvmtiStackTrace *trace, 230 ExpectedContentFrame *expected, 231 int expected_count) { 232 int i; 233 234 if (expected_count > trace->frame_count) { 235 return 0; 236 } 237 238 for (i = 0; i < expected_count; i++) { 239 // Get basic information out of the trace. 240 int bci = trace->frames[i].bci; 241 jmethodID methodid = trace->frames[i].method_id; 242 char *name = NULL, *signature = NULL, *file_name = NULL; 243 244 if (bci < 0) { 245 return 0; 246 } 247 248 // Transform into usable information. 249 int line_number = get_line_number(jvmti, methodid, bci); 250 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); 251 252 jclass declaring_class; 253 if (JVMTI_ERROR_NONE != 254 (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) { 255 return 0; 256 } 257 258 jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class, 259 &file_name); 260 if (err != JVMTI_ERROR_NONE) { 261 return 0; 262 } 263 264 // Compare now, none should be NULL. 265 if (name == NULL) { 266 return 0; 267 } 268 269 if (file_name == NULL) { 270 return 0; 271 } 272 273 if (signature == NULL) { 274 return 0; 275 } 276 277 if (strcmp(name, expected[i].name) || 278 strcmp(signature, expected[i].signature) || 279 strcmp(file_name, expected[i].file_name) || 280 line_number != expected[i].line_number) { 281 return 0; 282 } 283 } 284 285 return 1; 286 } 287 288 static jint compare_samples(JNIEnv* env, jvmtiStackTrace* traces, int trace_count, 289 ExpectedContentFrame* expected_content, size_t size) { 290 // We expect the code to record correctly the bci, retrieve the line 291 // number, have the right method and the class name of the first frames. 292 int i; 293 for (i = 0; i < trace_count; i++) { 294 jvmtiStackTrace *trace = traces + i; 295 if (check_sample_content(env, trace, expected_content, size)) { 296 // At least one frame matched what we were looking for. 297 return 1; 298 } 299 } 300 301 return 0; 302 } 303 304 static jint check_samples(JNIEnv* env, ExpectedContentFrame* expected, 305 size_t size, 306 jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiStackTraces*)) { 307 jvmtiStackTraces traces; 308 jvmtiError error = get_traces(jvmti, &traces); 309 310 if (error != JVMTI_ERROR_NONE) { 311 return 0; 312 } 313 314 int result = compare_samples(env, traces.stack_traces, traces.trace_count, 315 expected, size); 316 (*jvmti)->ReleaseTraces(jvmti, &traces); 317 return result; 318 } 319 320 static jint frames_exist_live(JNIEnv* env, ExpectedContentFrame* expected, 321 size_t size) { 322 return check_samples(env, expected, size, (*jvmti)->GetLiveTraces); 323 } 324 325 static jint frames_exist_recent(JNIEnv* env, ExpectedContentFrame* expected, 326 size_t size) { 327 return check_samples(env, expected, size, (*jvmti)->GetGarbageTraces); 328 } 329 330 static jint frames_exist_frequent(JNIEnv* env, ExpectedContentFrame* expected, 331 size_t size) { 332 return check_samples(env, expected, size, (*jvmti)->GetFrequentGarbageTraces); 333 } 334 335 // Static native API for various tests. 336 static void fill_native_frames(JNIEnv* env, jobjectArray frames, 337 ExpectedContentFrame* native_frames, size_t size) { 338 size_t i; 339 for(i = 0; i < size; i++) { 340 jobject obj = (*env)->GetObjectArrayElement(env, frames, i); 341 jclass frame_class = (*env)->GetObjectClass(env, obj); 342 jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class, "lineNumber", "I"); 343 int line_number = (*env)->GetIntField(env, obj, line_number_field_id); 344 345 jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method", "Ljava/lang/String;"); 346 jstring string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 347 const char* method = (*env)->GetStringUTFChars(env, string_object, 0); 348 349 string_id = (*env)->GetFieldID(env, frame_class, "fileName", "Ljava/lang/String;"); 350 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 351 const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0); 352 353 string_id = (*env)->GetFieldID(env, frame_class, "signature", "Ljava/lang/String;"); 354 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 355 const char* signature= (*env)->GetStringUTFChars(env, string_object, 0); 356 357 native_frames[i].name = method; 358 native_frames[i].file_name = file_name; 359 native_frames[i].signature = signature; 360 native_frames[i].line_number = line_number; 361 } 362 } 363 364 static jint checkAnd(JNIEnv *env, jobjectArray frames, int live, int recent, 365 int frequent) { 366 jobject loader = NULL; 367 368 if (frames == NULL) { 369 return 0; 370 } 371 372 // Start by transforming the frames into a C-friendly structure. 373 jsize size = (*env)->GetArrayLength(env, frames); 374 ExpectedContentFrame native_frames[size]; 375 fill_native_frames(env, frames, native_frames, size); 376 377 if (jvmti == NULL) { 378 throw_exc(env, "JVMTI client was not properly loaded!\n"); 379 return 0; 380 } 381 382 int result = 1; 383 384 if (live) { 385 result = frames_exist_live(env, native_frames, size); 386 } 387 388 if (recent) { 389 result = result && 390 frames_exist_recent(env, native_frames, size); 391 } 392 393 if (frequent) { 394 result = result && 395 frames_exist_frequent(env, native_frames, size); 396 } 397 398 return result; 399 } 400 401 static jint checkOr(JNIEnv *env, jobjectArray frames, int live, int recent, 402 int frequent) { 403 jobject loader = NULL; 404 405 if (frames == NULL) { 406 return 0; 407 } 408 409 // Start by transforming the frames into a C-friendly structure. 410 jsize size = (*env)->GetArrayLength(env, frames); 411 ExpectedContentFrame native_frames[size]; 412 fill_native_frames(env, frames, native_frames, size); 413 414 if (jvmti == NULL) { 415 throw_exc(env, "JVMTI client was not properly loaded!\n"); 416 return 0; 417 } 418 419 int result = 0; 420 421 if (live) { 422 result = frames_exist_live(env, native_frames, size); 423 } 424 425 if (recent) { 426 result = result || 427 frames_exist_recent(env, native_frames, size); 428 } 429 430 if (frequent) { 431 result = result || 432 frames_exist_frequent(env, native_frames, size); 433 } 434 435 return result; 436 } 437 438 static jint checkAll(JNIEnv *env, jobjectArray frames) { 439 return checkAnd(env, frames, 1, 1, 1); 440 } 441 442 static jint checkNone(JNIEnv *env, jobjectArray frames) { 443 jobject loader = NULL; 444 445 if (frames == NULL) { 446 return 0; 447 } 448 449 // Start by transforming the frames into a C-friendly structure. 450 jsize size = (*env)->GetArrayLength(env, frames); 451 ExpectedContentFrame native_frames[size]; 452 fill_native_frames(env, frames, native_frames, size); 453 454 if (jvmti == NULL) { 455 throw_exc(env, "JVMTI client was not properly loaded!\n"); 456 return 0; 457 } 458 459 if ((!frames_exist_live(env, native_frames, size)) && 460 (!frames_exist_recent(env, native_frames, size)) && 461 (!frames_exist_frequent(env, native_frames, size))) { 462 return 1; 463 } 464 return 0; 465 } 466 467 static void enable_sampling() { 468 check_error((*jvmti)->StartHeapSampling(jvmti, 1<<19, MAX_TRACES), 469 "Start Heap Sampling"); 470 } 471 472 static void disable_sampling() { 473 check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling"); 474 } 475 476 // HeapMonitorTest JNI. 477 JNIEXPORT jint JNICALL 478 Java_MyPackage_HeapMonitorTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) { 479 // We want the frames in each part. 480 if (!checkAll(env, frames)) { 481 return FAILED; 482 } 483 return PASSED; 484 } 485 486 JNIEXPORT void JNICALL 487 Java_MyPackage_HeapMonitorTest_enableSampling(JNIEnv *env, jclass cls) { 488 enable_sampling(); 489 } 490 491 // HeapMonitorOnOffTest JNI. 492 JNIEXPORT jint JNICALL 493 Java_MyPackage_HeapMonitorOnOffTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) { 494 // We want the frames in each part. 495 if (!checkAll(env, frames)) { 496 return FAILED; 497 } 498 return PASSED; 499 } 500 501 JNIEXPORT jint JNICALL 502 Java_MyPackage_HeapMonitorOnOffTest_checkWipeOut(JNIEnv *env, jclass cls, jobjectArray frames) { 503 // We want the frames in none of the parts. 504 if (!checkNone(env, frames)) { 505 return FAILED; 506 } 507 return PASSED; 508 } 509 510 JNIEXPORT void JNICALL 511 Java_MyPackage_HeapMonitorOnOffTest_enableSampling(JNIEnv *env, jclass cls) { 512 enable_sampling(); 513 } 514 515 JNIEXPORT void JNICALL 516 Java_MyPackage_HeapMonitorOnOffTest_disableSampling(JNIEnv *env, jclass cls) { 517 disable_sampling(); 518 } 519 520 // HeapMonitorRecentTest JNI. 521 JNIEXPORT jint JNICALL 522 Java_MyPackage_HeapMonitorRecentTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) { 523 // We want the frames in each part. 524 if (!checkAll(env, frames)) { 525 return FAILED; 526 } 527 return PASSED; 528 } 529 530 JNIEXPORT jint JNICALL 531 Java_MyPackage_HeapMonitorRecentTest_checkLiveOrRecentFrames(JNIEnv *env, jclass cls, jobjectArray frames) { 532 if (checkOr(env, frames, 1, 1, 0)) { 533 return FAILED; 534 } 535 return PASSED; 536 } 537 538 JNIEXPORT jint JNICALL 539 Java_MyPackage_HeapMonitorRecentTest_checkLiveAndRecentFrames(JNIEnv *env, jclass cls, jobjectArray frames) { 540 if (checkAnd(env, frames, 1, 1, 0)) { 541 return FAILED; 542 } 543 return PASSED; 544 } 545 546 JNIEXPORT void JNICALL 547 Java_MyPackage_HeapMonitorRecentTest_enableSampling(JNIEnv *env, jclass cls) { 548 enable_sampling(); 549 } 550 551 // HeapMonitorFrequentTest JNI. 552 JNIEXPORT jint JNICALL 553 Java_MyPackage_HeapMonitorFrequentTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) { 554 // We want the frames in each part. 555 if (!checkAll(env, frames)) { 556 return FAILED; 557 } 558 return PASSED; 559 } 560 561 JNIEXPORT jint JNICALL 562 Java_MyPackage_HeapMonitorFrequentTest_checkFrequentFrames(JNIEnv *env, jclass cls, jobjectArray frames) { 563 if (checkAnd(env, frames, 0, 0, 1)) { 564 return PASSED; 565 } 566 return FAILED; 567 } 568 569 JNIEXPORT void JNICALL 570 Java_MyPackage_HeapMonitorFrequentTest_enableSampling(JNIEnv *env, jclass cls) { 571 enable_sampling(); 572 } 573 574 JNIEXPORT jboolean JNICALL 575 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env, jclass cls) { 576 jvmtiCapabilities caps; 577 memset(&caps, 0, sizeof(caps)); 578 caps.can_sample_heap= 1; 579 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), 580 "Add capabilities\n")){ 581 return 0; 582 } 583 584 if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19, 585 MAX_TRACES), 586 "Start Heap Sampling")) { 587 return 0; 588 } 589 590 if (check_capability_error((*jvmti)->StopHeapSampling(jvmti), 591 "Stop Heap Sampling")) { 592 return 0; 593 } 594 595 if (check_capability_error((*jvmti)->ReleaseTraces(jvmti, NULL), 596 "Release Traces")) { 597 return 0; 598 } 599 600 if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL), 601 "Get Heap Sampling Stats")) { 602 return 0; 603 } 604 605 if (check_capability_error((*jvmti)->GetGarbageTraces(jvmti, NULL), 606 "Get Garbage Traces")) { 607 return 0; 608 } 609 610 if (check_capability_error((*jvmti)->GetFrequentGarbageTraces(jvmti, NULL), 611 "Get Frequent Garbage Traces")) { 612 return 0; 613 } 614 615 if (check_capability_error((*jvmti)->GetLiveTraces(jvmti, NULL), 616 "Get Live Traces")) { 617 return 0; 618 } 619 620 // Calling enable sampling should fail now. 621 return 1; 622 } 623 624 JNIEXPORT void JNICALL 625 Java_MyPackage_HeapMonitorStatTest_enableSampling(JNIEnv *env, jclass cls) { 626 enable_sampling(); 627 } 628 629 JNIEXPORT jint JNICALL 630 Java_MyPackage_HeapMonitorStatTest_statsNull(JNIEnv *env, jclass cls) { 631 jvmtiHeapSamplingStats stats; 632 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats), 633 "Heap Sampling Statistics"); 634 635 jvmtiHeapSamplingStats zero; 636 memset(&zero, 0, sizeof(zero)); 637 return memcmp(&stats, &zero, sizeof(zero)) == 0; 638 } 639 640 #ifdef __cplusplus 641 } 642 #endif