1 /* 2 * Copyright (c) 2018, 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 <assert.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include "jvmti.h" 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 #ifndef JNI_ENV_ARG 35 36 #ifdef __cplusplus 37 #define JNI_ENV_ARG(x, y) y 38 #define JNI_ENV_PTR(x) x 39 #else 40 #define JNI_ENV_ARG(x,y) x, y 41 #define JNI_ENV_PTR(x) (*x) 42 #endif 43 44 #endif 45 46 #define TRUE 1 47 #define FALSE 0 48 #define PRINT_OUT 1 49 #define MAX_TRACES 400 50 51 static jvmtiEnv *jvmti = NULL; 52 53 typedef struct _LiveObjectTrace{ 54 jvmtiFrameInfo* frames; 55 size_t frame_count; 56 } LiveObjectTrace; 57 58 typedef struct _EventStorage { 59 int live_object_size; 60 int live_object_count; 61 LiveObjectTrace** live_objects; 62 } EventStorage; 63 64 typedef struct _ExpectedContentFrame { 65 const char *name; 66 const char *signature; 67 const char *file_name; 68 int line_number; 69 } ExpectedContentFrame; 70 71 // Given a method and a location, this method gets the line number. 72 static 73 jint get_line_number(jvmtiEnv *jvmti, jmethodID method, 74 jlocation location) { 75 // Read the line number table. 76 jvmtiLineNumberEntry *table_ptr = 0; 77 jint line_number_table_entries; 78 int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method, 79 &line_number_table_entries, 80 &table_ptr); 81 82 if (JVMTI_ERROR_NONE != jvmti_error) { 83 return -1; 84 } 85 if (line_number_table_entries <= 0) { 86 return -1; 87 } 88 if (line_number_table_entries == 1) { 89 return table_ptr[0].line_number; 90 } 91 92 // Go through all the line numbers... 93 jint last_location = table_ptr[0].start_location; 94 int l; 95 for (l = 1; l < line_number_table_entries; l++) { 96 // ... and if you see one that is in the right place for your 97 // location, you've found the line number! 98 if ((location < table_ptr[l].start_location) && 99 (location >= last_location)) { 100 return table_ptr[l - 1].line_number; 101 } 102 last_location = table_ptr[l].start_location; 103 } 104 105 if (location >= last_location) { 106 return table_ptr[line_number_table_entries - 1].line_number; 107 } else { 108 return -1; 109 } 110 } 111 112 static jboolean check_sample_content(JNIEnv *env, 113 LiveObjectTrace* trace, 114 ExpectedContentFrame *expected, 115 size_t expected_count, 116 int print_out_comparisons) { 117 if (expected_count > trace->frame_count) { 118 return FALSE; 119 } 120 121 jvmtiFrameInfo* frames = trace->frames; 122 123 size_t i; 124 for (i = 0; i < expected_count; i++) { 125 // Get basic information out of the trace. 126 int bci = frames[i].location; 127 jmethodID methodid = frames[i].method; 128 char *name = NULL, *signature = NULL, *file_name = NULL; 129 130 if (bci < 0) { 131 return FALSE; 132 } 133 134 // Transform into usable information. 135 int line_number = get_line_number(jvmti, methodid, bci); 136 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); 137 138 jclass declaring_class; 139 if (JVMTI_ERROR_NONE != 140 (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) { 141 return FALSE; 142 } 143 144 jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class, 145 &file_name); 146 if (err != JVMTI_ERROR_NONE) { 147 return FALSE; 148 } 149 150 // Compare now, none should be NULL. 151 if (name == NULL) { 152 return FALSE; 153 } 154 155 if (file_name == NULL) { 156 return FALSE; 157 } 158 159 if (signature == NULL) { 160 return FALSE; 161 } 162 163 if (print_out_comparisons) { 164 fprintf(stderr, "\tComparing:\n"); 165 fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name); 166 fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature); 167 fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name); 168 fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number); 169 fprintf(stderr, "\t\tResult is %d\n", 170 (strcmp(name, expected[i].name) || 171 strcmp(signature, expected[i].signature) || 172 strcmp(file_name, expected[i].file_name) || 173 line_number != expected[i].line_number)); 174 } 175 176 if (strcmp(name, expected[i].name) || 177 strcmp(signature, expected[i].signature) || 178 strcmp(file_name, expected[i].file_name) || 179 line_number != expected[i].line_number) { 180 return FALSE; 181 } 182 } 183 184 return TRUE; 185 } 186 187 // Static native API for various tests. 188 static void fill_native_frames(JNIEnv* env, jobjectArray frames, 189 ExpectedContentFrame* native_frames, size_t size) { 190 size_t i; 191 for (i = 0; i < size; i++) { 192 jobject obj = (*env)->GetObjectArrayElement(env, frames, i); 193 jclass frame_class = (*env)->GetObjectClass(env, obj); 194 jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class, 195 "lineNumber", "I"); 196 int line_number = (*env)->GetIntField(env, obj, line_number_field_id); 197 198 jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method", 199 "Ljava/lang/String;"); 200 jstring string_object = (jstring) (*env)->GetObjectField(env, obj, 201 string_id); 202 const char* method = (*env)->GetStringUTFChars(env, string_object, 0); 203 204 string_id = (*env)->GetFieldID(env, frame_class, "fileName", 205 "Ljava/lang/String;"); 206 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 207 const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0); 208 209 string_id = (*env)->GetFieldID(env, frame_class, "signature", 210 "Ljava/lang/String;"); 211 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 212 const char* signature= (*env)->GetStringUTFChars(env, string_object, 0); 213 214 native_frames[i].name = method; 215 native_frames[i].file_name = file_name; 216 native_frames[i].signature = signature; 217 native_frames[i].line_number = line_number; 218 } 219 } 220 221 // Internal storage system implementation. 222 223 static EventStorage global_event_storage; 224 225 static int event_storage_get_count(EventStorage* storage) { 226 return storage->live_object_count; 227 } 228 229 static jboolean event_storage_contains(JNIEnv* env, 230 EventStorage* storage, 231 ExpectedContentFrame* frames, 232 size_t size) { 233 fprintf(stderr, "Checking storage count %d\n", storage->live_object_count); 234 int i; 235 for (i = 0; i < storage->live_object_count; i++) { 236 LiveObjectTrace* trace = storage->live_objects[i]; 237 238 if (check_sample_content(env, trace, frames, size, PRINT_OUT)) { 239 return TRUE; 240 } 241 } 242 return FALSE; 243 } 244 245 static void event_storage_augment_storage(EventStorage* storage) { 246 int new_max = (storage->live_object_size * 2) + 1; 247 LiveObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects)); 248 249 int current_count = storage->live_object_count; 250 memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects)); 251 free(storage->live_objects); 252 storage->live_objects = new_objects; 253 254 storage->live_object_size = new_max; 255 } 256 257 static void event_storage_add(EventStorage* storage, 258 jthread thread, 259 jobject object, 260 jclass klass, 261 jlong size) { 262 jvmtiFrameInfo frames[64]; 263 jint count; 264 jvmtiError err; 265 err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count); 266 if (err == JVMTI_ERROR_NONE && count >= 1) { 267 if (storage->live_object_count >= storage->live_object_size) { 268 event_storage_augment_storage(storage); 269 } 270 assert(storage->live_object_count < storage->live_object_size); 271 272 jvmtiFrameInfo* allocated_frames = malloc(count * sizeof(*allocated_frames)); 273 memcpy(allocated_frames, frames, count * sizeof(*allocated_frames)); 274 275 LiveObjectTrace* live_object = malloc(sizeof(*live_object)); 276 live_object->frames = allocated_frames; 277 live_object->frame_count = count; 278 storage->live_objects[storage->live_object_count] = live_object; 279 storage->live_object_count++; 280 } 281 } 282 283 static void event_storage_reset(EventStorage* storage) { 284 int max = storage->live_object_count; 285 int i; 286 for (i = 0; i < max; i++) { 287 LiveObjectTrace* object = storage->live_objects[i]; 288 free(object); 289 } 290 free(storage->live_objects); 291 memset(storage, 0, sizeof(*storage)); 292 } 293 294 // Start of the JVMTI agent code. 295 296 static const char *EXC_CNAME = "java/lang/Exception"; 297 298 static int check_error(jvmtiError err, const char *s) { 299 if (err != JVMTI_ERROR_NONE) { 300 printf(" ## %s error: %d\n", s, err); 301 return 1; 302 } 303 return 0; 304 } 305 306 static int check_capability_error(jvmtiError err, const char *s) { 307 if (err != JVMTI_ERROR_NONE) { 308 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) { 309 return 0; 310 } 311 printf(" ## %s error: %d\n", s, err); 312 return 1; 313 } 314 return 1; 315 } 316 317 static 318 jint throw_exc(JNIEnv *env, char *msg) { 319 jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME)); 320 321 if (exc_class == NULL) { 322 printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME); 323 return -1; 324 } 325 return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg); 326 } 327 328 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 329 330 JNIEXPORT 331 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 332 return Agent_Initialize(jvm, options, reserved); 333 } 334 335 JNIEXPORT 336 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 337 return Agent_Initialize(jvm, options, reserved); 338 } 339 340 JNIEXPORT 341 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 342 return JNI_VERSION_1_8; 343 } 344 345 JNIEXPORT 346 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env, 347 JNIEnv* jni_env, 348 jthread thread, 349 jobject object, 350 jclass object_klass, 351 jlong size) { 352 event_storage_add(&global_event_storage, thread, object, object_klass, size); 353 } 354 355 static int enable_notifications() { 356 return check_error((*jvmti)->SetEventNotificationMode( 357 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), 358 "Set event notifications"); 359 } 360 361 static 362 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 363 jint res; 364 365 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), 366 JVMTI_VERSION_9); 367 if (res != JNI_OK || jvmti == NULL) { 368 printf(" Error: wrong result of a valid call to GetEnv!\n"); 369 return JNI_ERR; 370 } 371 372 jvmtiEventCallbacks callbacks; 373 memset(&callbacks, 0, sizeof(callbacks)); 374 callbacks.SampledObjectAlloc = &SampledObjectAlloc; 375 376 jvmtiCapabilities caps; 377 memset(&caps, 0, sizeof(caps)); 378 // Get line numbers, sample heap, sample events, and filename for the test. 379 caps.can_get_line_numbers = 1; 380 caps.can_sample_heap = 1; 381 caps.can_get_source_file_name = 1; 382 if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities")){ 383 return JNI_ERR; 384 } 385 386 if (enable_notifications()) { 387 return JNI_ERR; 388 } 389 390 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks, 391 sizeof(jvmtiEventCallbacks)), 392 " Set Event Callbacks")) { 393 return JNI_ERR; 394 } 395 return JNI_OK; 396 } 397 398 JNIEXPORT void JNICALL 399 Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) { 400 (*jvmti)->SetTlabHeapSampling(jvmti, value); 401 } 402 403 JNIEXPORT jboolean JNICALL 404 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) { 405 return event_storage_get_count(&global_event_storage) == 0; 406 } 407 408 JNIEXPORT void JNICALL 409 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) { 410 enable_notifications(); 411 } 412 413 JNIEXPORT void JNICALL 414 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) { 415 check_error((*jvmti)->SetEventNotificationMode( 416 jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), 417 "Set event notifications"); 418 } 419 420 JNIEXPORT void JNICALL 421 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) { 422 } 423 424 JNIEXPORT jboolean JNICALL 425 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) { 426 jsize size = (*env)->GetArrayLength(env, frames); 427 ExpectedContentFrame native_frames[size]; 428 fill_native_frames(env, frames, native_frames, size); 429 return event_storage_contains(env, &global_event_storage, native_frames, size); 430 } 431 432 JNIEXPORT void JNICALL 433 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) { 434 return event_storage_reset(&global_event_storage); 435 } 436 437 JNIEXPORT jboolean JNICALL 438 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env, 439 jclass cls) { 440 jvmtiCapabilities caps; 441 memset(&caps, 0, sizeof(caps)); 442 caps.can_sample_heap= 1; 443 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), 444 "Add capabilities\n")){ 445 return FALSE; 446 } 447 448 if (check_capability_error((*jvmti)->SetTlabHeapSampling(jvmti, 1<<19), 449 "Set Tlab Heap Sampling")) { 450 return FALSE; 451 } 452 return TRUE; 453 } 454 455 #ifdef __cplusplus 456 } 457 #endif