1 /* 2 * Copyright (c) 2019 SAP SE 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 27 #include "jvmti.h" 28 29 static jvmtiEnv *jvmti = NULL; 30 31 static const char* fields[] = { "Z", "B", "C", "S", "I", "J", "F", "D" }; 32 #define NUM_FIELDS (sizeof fields / sizeof fields[0]) 33 static jfieldID fieldIDs[NUM_FIELDS]; 34 static jlong fieldAccessCount = 0; 35 36 37 JNIEXPORT jboolean JNICALL Java_FastGetField_initFieldIDs(JNIEnv *env, jobject this, jclass c) { 38 for (int i = 0; i < (int)NUM_FIELDS; ++i) { 39 fieldIDs[i] = (*env)->GetFieldID(env, c, fields[i], fields[i]); 40 if (fieldIDs[i] == NULL) { 41 printf("field %d not found\n", i); 42 return JNI_FALSE; 43 } 44 } 45 return JNI_TRUE; 46 } 47 48 49 JNIEXPORT jboolean JNICALL Java_FastGetField_initWatchers(JNIEnv *env, jobject this, jclass c) { 50 if (jvmti == NULL) { 51 printf("jvmti is NULL\n"); 52 return JNI_FALSE; 53 } 54 55 for (int i = 0; i < (int)NUM_FIELDS; ++i) { 56 jvmtiError err = (*jvmti)->SetFieldAccessWatch(jvmti, c, fieldIDs[i]); 57 if (err != JVMTI_ERROR_NONE) { 58 printf("SetFieldAccessWatch failed with error %d\n", err); 59 return JNI_FALSE; 60 } 61 } 62 63 return JNI_TRUE; 64 } 65 66 67 JNIEXPORT jlong JNICALL Java_FastGetField_accessFields(JNIEnv *env, jobject this, jobject obj) { 68 return 69 (*env)->GetBooleanField(env, obj, fieldIDs[0]) + 70 (*env)->GetByteField(env, obj, fieldIDs[1]) + 71 (*env)->GetCharField(env, obj, fieldIDs[2]) + 72 (*env)->GetShortField(env, obj, fieldIDs[3]) + 73 (*env)->GetIntField(env, obj, fieldIDs[4]) + 74 (*env)->GetLongField(env, obj, fieldIDs[5]) + 75 (jlong)((*env)->GetFloatField(env, obj, fieldIDs[6])) + 76 (jlong)((*env)->GetDoubleField(env, obj, fieldIDs[7])); 77 } 78 79 80 JNIEXPORT jlong JNICALL Java_FastGetField_getFieldAccessCount(JNIEnv *env, jclass c) { 81 return fieldAccessCount; 82 } 83 84 85 static void JNICALL onFieldAccess(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, 86 jmethodID method, jlocation location, jclass field_klass, 87 jobject object, jfieldID field) { 88 char *fname = NULL, *mname = NULL; 89 90 jvmtiError err = (*jvmti)->GetFieldName(jvmti, field_klass, field, &fname, NULL, NULL); 91 if (err != JVMTI_ERROR_NONE) { 92 printf("GetFieldName failed with error %d\n", err); 93 return; 94 } 95 96 err = (*jvmti)->GetMethodName(jvmti, method, &mname, NULL, NULL); 97 if (err != JVMTI_ERROR_NONE) { 98 printf("GetMethodName failed with error %d\n", err); 99 return; 100 } 101 102 printf("%s accessed field %s\n", mname, fname); 103 104 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)fname); 105 if (err != JVMTI_ERROR_NONE) { 106 printf("Deallocate failed with error %d\n", err); 107 return; 108 } 109 110 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)mname); 111 if (err != JVMTI_ERROR_NONE) { 112 printf("Deallocate failed with error %d\n", err); 113 return; 114 } 115 116 fieldAccessCount++; 117 } 118 119 120 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { 121 jvmtiCapabilities capa; 122 jvmtiEventCallbacks cbs = {0}; 123 124 (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_0); 125 126 memset(&capa, 0, sizeof(capa)); 127 capa.can_generate_field_access_events = 1; 128 (*jvmti)->AddCapabilities(jvmti, &capa); 129 130 cbs.FieldAccess = &onFieldAccess; 131 (*jvmti)->SetEventCallbacks(jvmti, &cbs, sizeof(cbs)); 132 (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_ACCESS, NULL); 133 printf("Loaded agent\n"); 134 fflush(stdout); 135 136 return 0; 137 }