1 /* 2 * Copyright (c) 2003, 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 24 #include <stdio.h> 25 #include <string.h> 26 #include <inttypes.h> 27 #include "jvmti.h" 28 #include "agent_common.h" 29 #include "JVMTITools.h" 30 31 extern "C" { 32 33 34 #define PASSED 0 35 #define STATUS_FAILED 2 36 37 typedef struct { 38 jfieldID fid; 39 char *m_cls; 40 char *m_name; 41 char *m_sig; 42 jlocation loc; 43 char *f_cls; 44 char *f_name; 45 char *f_sig; 46 jboolean is_static; 47 } writable_watch_info; 48 49 typedef struct { 50 jfieldID fid; 51 const char *m_cls; 52 const char *m_name; 53 const char *m_sig; 54 jlocation loc; 55 const char *f_cls; 56 const char *f_name; 57 const char *f_sig; 58 jboolean is_static; 59 } watch_info; 60 61 static jvmtiEnv *jvmti; 62 static jvmtiEventCallbacks callbacks; 63 static jvmtiCapabilities caps; 64 static jint result = PASSED; 65 static jboolean printdump = JNI_FALSE; 66 static int eventsExpected = 0; 67 static int eventsCount = 0; 68 static watch_info watches[] = { 69 { NULL, "Lnsk/jvmti/FieldAccess/fieldacc003a;", "run", "()I", 3, 70 "Lnsk/jvmti/FieldAccess/fieldacc003a;", "extendsBoolean", "Z", JNI_FALSE }, 71 { NULL, "Lnsk/jvmti/FieldAccess/fieldacc003a;", "run", "()I", 14, 72 "Lnsk/jvmti/FieldAccess/fieldacc003a;", "extendsByte", "B", JNI_FALSE }, 73 { NULL, "Lnsk/jvmti/FieldAccess/fieldacc003a;", "run", "()I", 25, 74 "Lnsk/jvmti/FieldAccess/fieldacc003a;", "extendsShort", "S", JNI_FALSE }, 75 { NULL, "Lnsk/jvmti/FieldAccess/fieldacc003a;", "run", "()I", 36, 76 "Lnsk/jvmti/FieldAccess/fieldacc003a;", "extendsInt", "I", JNI_FALSE }, 77 { NULL, "Lnsk/jvmti/FieldAccess/fieldacc003a;", "run", "()I", 47, 78 "Lnsk/jvmti/FieldAccess/fieldacc003a;", "extendsLong", "J", JNI_FALSE }, 79 { NULL, "Lnsk/jvmti/FieldAccess/fieldacc003a;", "run", "()I", 61, 80 "Lnsk/jvmti/FieldAccess/fieldacc003a;", "extendsFloat", "F", JNI_FALSE }, 81 { NULL, "Lnsk/jvmti/FieldAccess/fieldacc003a;", "run", "()I", 74, 82 "Lnsk/jvmti/FieldAccess/fieldacc003a;", "extendsDouble", "D", JNI_FALSE }, 83 { NULL, "Lnsk/jvmti/FieldAccess/fieldacc003a;", "run", "()I", 88, 84 "Lnsk/jvmti/FieldAccess/fieldacc003a;", "extendsChar", "C", JNI_FALSE }, 85 { NULL, "Lnsk/jvmti/FieldAccess/fieldacc003a;", "run", "()I", 100, 86 "Lnsk/jvmti/FieldAccess/fieldacc003a;", "extendsObject", "Ljava/lang/Object;", JNI_FALSE }, 87 { NULL, "Lnsk/jvmti/FieldAccess/fieldacc003a;", "run", "()I", 111, 88 "Lnsk/jvmti/FieldAccess/fieldacc003a;", "extendsArrInt", "[I", JNI_FALSE } 89 }; 90 91 void JNICALL FieldAccess(jvmtiEnv *jvmti_env, JNIEnv *env, 92 jthread thr, jmethodID method, 93 jlocation location, jclass field_klass, jobject obj, jfieldID field) { 94 jvmtiError err; 95 jclass cls; 96 writable_watch_info watch; 97 char *generic; 98 size_t i; 99 100 eventsCount++; 101 if (printdump == JNI_TRUE) { 102 printf(">>> retrieving access watch info ...\n"); 103 } 104 watch.fid = field; 105 watch.loc = location; 106 watch.is_static = (obj == NULL) ? JNI_TRUE : JNI_FALSE; 107 err = jvmti_env->GetMethodDeclaringClass(method, &cls); 108 if (err != JVMTI_ERROR_NONE) { 109 printf("(GetMethodDeclaringClass) unexpected error: %s (%d)\n", 110 TranslateError(err), err); 111 result = STATUS_FAILED; 112 } 113 err = jvmti_env->GetClassSignature(cls, 114 &watch.m_cls, &generic); 115 if (err != JVMTI_ERROR_NONE) { 116 printf("(GetClassSignature) unexpected error: %s (%d)\n", 117 TranslateError(err), err); 118 result = STATUS_FAILED; 119 } 120 err = jvmti_env->GetMethodName(method, 121 &watch.m_name, &watch.m_sig, &generic); 122 if (err != JVMTI_ERROR_NONE) { 123 printf("(GetMethodName) unexpected error: %s (%d)\n", 124 TranslateError(err), err); 125 result = STATUS_FAILED; 126 } 127 err = jvmti_env->GetClassSignature(field_klass, 128 &watch.f_cls, &generic); 129 if (err != JVMTI_ERROR_NONE) { 130 printf("(GetClassSignature) unexpected error: %s (%d)\n", 131 TranslateError(err), err); 132 result = STATUS_FAILED; 133 } 134 err = jvmti_env->GetFieldName(field_klass, field, 135 &watch.f_name, &watch.f_sig, &generic); 136 if (err != JVMTI_ERROR_NONE) { 137 printf("(GetFieldName) unexpected error: %s (%d)\n", 138 TranslateError(err), err); 139 result = STATUS_FAILED; 140 } 141 if (printdump == JNI_TRUE) { 142 printf(">>> class: \"%s\"\n", watch.m_cls); 143 printf(">>> method: \"%s%s\"\n", watch.m_name, watch.m_sig); 144 printf(">>> location: 0x%x%08x\n", 145 (jint)(watch.loc >> 32), (jint)watch.loc); 146 printf(">>> field cls: \"%s\"\n", watch.f_cls); 147 printf(">>> field: \"%s:%s\"\n", watch.f_name, watch.f_sig); 148 printf(">>> object: 0x%p\n", obj); 149 printf(">>> ... done\n"); 150 } 151 for (i = 0; i < sizeof(watches)/sizeof(watch_info); i++) { 152 if (watch.fid == watches[i].fid) { 153 if (watch.m_cls == NULL || 154 strcmp(watch.m_cls, watches[i].m_cls) != 0) { 155 printf("(watch#%" PRIuPTR ") wrong class: \"%s\", expected: \"%s\"\n", 156 i, watch.m_cls, watches[i].m_cls); 157 result = STATUS_FAILED; 158 } 159 if (watch.m_name == NULL || 160 strcmp(watch.m_name, watches[i].m_name) != 0) { 161 printf("(watch#%" PRIuPTR ") wrong method name: \"%s\"", 162 i, watch.m_name); 163 printf(", expected: \"%s\"\n", watches[i].m_name); 164 result = STATUS_FAILED; 165 } 166 if (watch.m_sig == NULL || 167 strcmp(watch.m_sig, watches[i].m_sig) != 0) { 168 printf("(watch#%" PRIuPTR ") wrong method sig: \"%s\"", 169 i, watch.m_sig); 170 printf(", expected: \"%s\"\n", watches[i].m_sig); 171 result = STATUS_FAILED; 172 } 173 if (watch.loc != watches[i].loc) { 174 printf("(watch#%" PRIuPTR ") wrong location: 0x%x%08x", 175 i, (jint)(watch.loc >> 32), (jint)watch.loc); 176 printf(", expected: 0x%x%08x\n", 177 (jint)(watches[i].loc >> 32), (jint)watches[i].loc); 178 result = STATUS_FAILED; 179 } 180 if (watch.f_name == NULL || 181 strcmp(watch.f_name, watches[i].f_name) != 0) { 182 printf("(watch#%" PRIuPTR ") wrong field name: \"%s\"", 183 i, watch.f_name); 184 printf(", expected: \"%s\"\n", watches[i].f_name); 185 result = STATUS_FAILED; 186 } 187 if (watch.f_sig == NULL || 188 strcmp(watch.f_sig, watches[i].f_sig) != 0) { 189 printf("(watch#%" PRIuPTR ") wrong field sig: \"%s\"", 190 i, watch.f_sig); 191 printf(", expected: \"%s\"\n", watches[i].f_sig); 192 result = STATUS_FAILED; 193 } 194 if (watch.is_static != watches[i].is_static) { 195 printf("(watch#%" PRIuPTR ") wrong field type: %s", i, 196 (watch.is_static==JNI_TRUE)?"static":"instance"); 197 printf(", expected: %s\n", 198 (watches[i].is_static==JNI_TRUE)?"static":"instance"); 199 result = STATUS_FAILED; 200 } 201 return; 202 } 203 } 204 printf("Unexpected field access catched: 0x%p\n", watch.fid); 205 result = STATUS_FAILED; 206 } 207 208 #ifdef STATIC_BUILD 209 JNIEXPORT jint JNICALL Agent_OnLoad_fieldacc003(JavaVM *jvm, char *options, void *reserved) { 210 return Agent_Initialize(jvm, options, reserved); 211 } 212 JNIEXPORT jint JNICALL Agent_OnAttach_fieldacc003(JavaVM *jvm, char *options, void *reserved) { 213 return Agent_Initialize(jvm, options, reserved); 214 } 215 JNIEXPORT jint JNI_OnLoad_fieldacc003(JavaVM *jvm, char *options, void *reserved) { 216 return JNI_VERSION_1_8; 217 } 218 #endif 219 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 220 jvmtiError err; 221 jint res; 222 223 if (options != NULL && strcmp(options, "printdump") == 0) { 224 printdump = JNI_TRUE; 225 } 226 227 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); 228 if (res != JNI_OK || jvmti == NULL) { 229 printf("Wrong result of a valid call to GetEnv!\n"); 230 return JNI_ERR; 231 } 232 233 err = jvmti->GetPotentialCapabilities(&caps); 234 if (err != JVMTI_ERROR_NONE) { 235 printf("(GetPotentialCapabilities) unexpected error: %s (%d)\n", 236 TranslateError(err), err); 237 return JNI_ERR; 238 } 239 240 err = jvmti->AddCapabilities(&caps); 241 if (err != JVMTI_ERROR_NONE) { 242 printf("(AddCapabilities) unexpected error: %s (%d)\n", 243 TranslateError(err), err); 244 return JNI_ERR; 245 } 246 247 err = jvmti->GetCapabilities(&caps); 248 if (err != JVMTI_ERROR_NONE) { 249 printf("(GetCapabilities) unexpected error: %s (%d)\n", 250 TranslateError(err), err); 251 return JNI_ERR; 252 } 253 254 if (caps.can_generate_field_access_events) { 255 callbacks.FieldAccess = &FieldAccess; 256 err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 257 if (err != JVMTI_ERROR_NONE) { 258 printf("(SetEventCallbacks) unexpected error: %s (%d)\n", 259 TranslateError(err), err); 260 return JNI_ERR; 261 } 262 263 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, 264 JVMTI_EVENT_FIELD_ACCESS, NULL); 265 if (err != JVMTI_ERROR_NONE) { 266 printf("Failed to enable JVMTI_EVENT_FIELD_ACCESS: %s (%d)\n", 267 TranslateError(err), err); 268 return JNI_ERR; 269 } 270 } else { 271 printf("Warning: FieldAccess watch is not implemented\n"); 272 } 273 274 return JNI_OK; 275 } 276 277 JNIEXPORT void JNICALL 278 Java_nsk_jvmti_FieldAccess_fieldacc003_getReady(JNIEnv *env, jclass klass) { 279 jvmtiError err; 280 jclass cls; 281 size_t i; 282 283 if (!caps.can_generate_field_access_events) { 284 return; 285 } 286 287 if (printdump == JNI_TRUE) { 288 printf(">>> setting field access watches ...\n"); 289 } 290 for (i = 0; i < sizeof(watches)/sizeof(watch_info); i++) { 291 cls = env->FindClass(watches[i].f_cls); 292 if (cls == NULL) { 293 printf("Cannot find %s class!\n", watches[i].f_cls); 294 result = STATUS_FAILED; 295 return; 296 } 297 if (watches[i].is_static == JNI_TRUE) { 298 watches[i].fid = env->GetStaticFieldID( 299 cls, watches[i].f_name, watches[i].f_sig); 300 } else { 301 watches[i].fid = env->GetFieldID( 302 cls, watches[i].f_name, watches[i].f_sig); 303 } 304 if (watches[i].fid == NULL) { 305 printf("Cannot get field ID for \"%s:%s\"\n", 306 watches[i].f_name, watches[i].f_sig); 307 result = STATUS_FAILED; 308 return; 309 } 310 err = jvmti->SetFieldAccessWatch(cls, watches[i].fid); 311 if (err == JVMTI_ERROR_NONE) { 312 eventsExpected++; 313 } else { 314 printf("(SetFieldAccessWatch#%" PRIuPTR ") unexpected error: %s (%d)\n", 315 i, TranslateError(err), err); 316 result = STATUS_FAILED; 317 } 318 } 319 if (printdump == JNI_TRUE) { 320 printf(">>> ... done\n"); 321 } 322 } 323 324 JNIEXPORT jint JNICALL 325 Java_nsk_jvmti_FieldAccess_fieldacc003_check(JNIEnv *env, jclass cls) { 326 if (eventsCount != eventsExpected) { 327 printf("Wrong number of field access events: %d, expected: %d\n", 328 eventsCount, eventsExpected); 329 result = STATUS_FAILED; 330 } 331 return result; 332 } 333 334 }