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 }