1 /*
   2  * Copyright (c) 2017, 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 <stdlib.h>
  26 #include <string.h>
  27 #include <stdint.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 PASSED 0
  47 #define FAILED 2
  48 
  49 static jint result = PASSED;
  50 
  51 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
  52 
  53 JNIEXPORT
  54 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
  55     return Agent_Initialize(jvm, options, reserved);
  56 }
  57 
  58 JNIEXPORT
  59 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
  60     return Agent_Initialize(jvm, options, reserved);
  61 }
  62 
  63 JNIEXPORT
  64 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
  65     return JNI_VERSION_9;
  66 }
  67 
  68 static void check_jvmti_error(jvmtiEnv *jvmti, char* fname, jvmtiError err) {
  69     if (err != JVMTI_ERROR_NONE) {
  70         printf("  ## %s error: %d\n", fname, err);
  71         exit(err);
  72     }
  73 }
  74 
  75  static void deallocate(jvmtiEnv *jvmti, char* mem) {
  76     jvmtiError err = (*jvmti)->Deallocate(jvmti, (unsigned char*)mem);
  77     check_jvmti_error(jvmti, "Deallocate", err);
  78 }
  79 
  80 static void get_phase(jvmtiEnv *jvmti, jvmtiPhase *phase_ptr) {
  81     jvmtiError err = (*jvmti)->GetPhase(jvmti, phase_ptr);
  82     check_jvmti_error(jvmti, "GetPhase", err);
  83 }
  84 
  85 static jthread get_cur_thread(jvmtiEnv *jvmti) {
  86     jthread cur_thread = NULL;
  87     jvmtiError err = (*jvmti)->GetCurrentThread(jvmti, &cur_thread);
  88     check_jvmti_error(jvmti, "GetCurrentThread", err);
  89     return cur_thread;
  90 }
  91 
  92 static intptr_t get_thread_local(jvmtiEnv *jvmti, jthread thread) {
  93     void *val = NULL;
  94     jvmtiError err = (*jvmti)->GetThreadLocalStorage(jvmti, thread, &val);
  95     check_jvmti_error(jvmti, "GetThreadLocalStorage", err);
  96     return (intptr_t)val;
  97 }
  98 
  99 static void set_thread_local(jvmtiEnv *jvmti, jthread thread, intptr_t x) {
 100     void *val = (void*)x;
 101     jvmtiError err = (*jvmti)->SetThreadLocalStorage(jvmti, thread, val);
 102     check_jvmti_error(jvmti, "SetThreadLocalStorage", err);
 103 }
 104 
 105 static void print_class_status(jvmtiEnv *jvmti, jclass klass) {
 106     jint status = 0;
 107     jvmtiError err = (*jvmti)->GetClassStatus(jvmti, klass, &status);
 108 
 109     check_jvmti_error(jvmti, "GetClassStatus", err);
 110     // This function is only used in a ClassPrepare event context
 111     if ((status & JVMTI_CLASS_STATUS_VERIFIED)    == 0 ||
 112         (status & JVMTI_CLASS_STATUS_PREPARED)    == 0 ||
 113         (status & JVMTI_CLASS_STATUS_INITIALIZED) == 1 ||
 114         (status & JVMTI_CLASS_STATUS_ERROR)       == 1) {
 115         printf("  ## Error: unexpected class status: 0x%02x\n", status);
 116     }
 117     printf("    Class status: 0x%08x\n", status);
 118 }
 119 
 120 static void print_class_signature(jvmtiEnv *jvmti, jclass klass) {
 121     char* name = NULL;
 122     jvmtiError err = (*jvmti)->GetClassSignature(jvmti, klass, &name, NULL);
 123 
 124     check_jvmti_error(jvmti, "GetClassSignature", err);
 125     if (name != NULL) {
 126         printf(" class: %s\n", name);
 127         deallocate(jvmti, name);
 128     }
 129 }
 130 
 131 static void print_class_source_file_name(jvmtiEnv *jvmti, jclass klass) {
 132     char* name = NULL;
 133     jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, klass, &name);
 134 
 135     check_jvmti_error(jvmti, "GetSourceFileName", err);
 136     if (name != NULL) {
 137         printf("    Class source file name: %s\n", name);
 138         deallocate(jvmti, name);
 139     }
 140 }
 141 
 142 static void print_class_info(jvmtiEnv *jvmti, jclass klass) {
 143     jint mods = 0;
 144     jboolean is_interface  = JNI_FALSE;
 145     jboolean is_array      = JNI_FALSE;
 146     jboolean is_modifiable = JNI_FALSE;
 147     jvmtiError err = (*jvmti)->GetClassModifiers(jvmti, klass, &mods);
 148 
 149     check_jvmti_error(jvmti, "GetClassModifiers", err);
 150     printf("    Class modifiers: 0x%08x\n", mods);
 151 
 152     err = (*jvmti)->IsInterface(jvmti, klass, &is_interface);
 153     check_jvmti_error(jvmti, "IsInterface", err);
 154     printf("    Class is interface: %d\n", is_interface);
 155 
 156     err = (*jvmti)->IsArrayClass(jvmti, klass, &is_array);
 157     check_jvmti_error(jvmti, "IsArrayClass", err);
 158     printf("    Class is array: %d\n", is_array);
 159 
 160     err = (*jvmti)->IsModifiableClass(jvmti, klass, &is_modifiable);
 161     check_jvmti_error(jvmti, "IsModifiableClass", err);
 162     printf("    Class is modifiable: %d\n", is_modifiable);
 163 }
 164 
 165 static jint get_class_methods(jvmtiEnv *jvmti, jclass klass, jmethodID** methods_ptr) {
 166     jint count = 0;
 167     jvmtiError err = (*jvmti)->GetClassMethods(jvmti, klass, &count, methods_ptr);
 168     check_jvmti_error(jvmti, "GetClassMethods", err);
 169     return count;
 170 }
 171 
 172 static jint get_class_fields(jvmtiEnv *jvmti, jclass klass, jfieldID** fields_ptr) {
 173     jint count = 0;
 174     jvmtiError err = (*jvmti)->GetClassFields(jvmti, klass, &count, fields_ptr);
 175     check_jvmti_error(jvmti, "GetClassMethods", err);
 176     return count;
 177 }
 178 
 179 static void print_method_name_sign(jvmtiEnv *jvmti, jmethodID method) {
 180     char* name = NULL;
 181     char* sign = NULL;
 182     jvmtiError err = (*jvmti)->GetMethodName(jvmti, method, &name, &sign, NULL);
 183 
 184     check_jvmti_error(jvmti, "GetMethodName", err);
 185     printf("  Method: %s%s\n", name, sign);
 186     deallocate(jvmti, name);
 187     deallocate(jvmti, sign);
 188 }
 189 
 190 static void print_method_declaring_class(jvmtiEnv *jvmti, jmethodID method) {
 191     jclass dclass = NULL;
 192     jvmtiError err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &dclass);
 193 
 194     check_jvmti_error(jvmti, "GetMethodDeclaringClass", err);
 195     printf("    Method declaring");
 196     print_class_signature(jvmti, dclass);
 197 }
 198 
 199 static void print_method_info(jvmtiEnv *jvmti, jmethodID method) {
 200     jint mods = 0;
 201     jint locals_max = 0;
 202     jint args_size = 0;
 203     jboolean is_native   = JNI_FALSE;
 204     jboolean is_synth    = JNI_FALSE;
 205     jboolean is_obsolete = JNI_FALSE;
 206     jvmtiError err = (*jvmti)->GetMethodModifiers(jvmti, method, &mods);
 207 
 208     check_jvmti_error(jvmti, "GetMethodModifiers", err);
 209     printf("    Method modifiers: 0x%08x\n", mods);
 210 
 211     err = (*jvmti)->IsMethodNative(jvmti, method, &is_native);
 212     check_jvmti_error(jvmti, "IsMethodNative", err);
 213     printf("    Method is native: %d\n", is_native);
 214 
 215     if (is_native == JNI_FALSE) {
 216         err = (*jvmti)->GetMaxLocals(jvmti, method, &locals_max);
 217         check_jvmti_error(jvmti, "GetMaxLocals", err);
 218         printf("    Method max locals: %d\n", locals_max);
 219 
 220         err = (*jvmti)->GetArgumentsSize(jvmti, method, &args_size);
 221         check_jvmti_error(jvmti, "GetArgumentsSize", err);
 222         printf("    Method arguments size: %d\n", args_size);
 223     }
 224 
 225     err = (*jvmti)->IsMethodSynthetic(jvmti, method, &is_synth);
 226     check_jvmti_error(jvmti, "IsMethodSynthetic", err);
 227     printf("    Method is synthetic: %d\n", is_synth);
 228 
 229     err = (*jvmti)->IsMethodObsolete(jvmti, method, & is_obsolete);
 230     check_jvmti_error(jvmti, "IsMethodObsolete", err);
 231     printf("    Method is obsolete: %d\n", is_obsolete);
 232 }
 233 
 234 static void test_method_functions(jvmtiEnv *jvmti, jmethodID method) {
 235     print_method_name_sign(jvmti, method);
 236     print_method_declaring_class(jvmti, method);
 237     print_method_info(jvmti, method);
 238 }
 239 
 240 static void print_field_name_sign(jvmtiEnv *jvmti, jclass klass, jfieldID field) {
 241     char* name = NULL;
 242     char* sign = NULL;
 243     jvmtiError err = (*jvmti)->GetFieldName(jvmti, klass, field, &name, &sign, NULL);
 244 
 245     check_jvmti_error(jvmti, "GetFieldName", err);
 246     printf("  Field: %s %s\n", sign, name);
 247     deallocate(jvmti, name);
 248     deallocate(jvmti, sign);
 249 }
 250 
 251 static void print_field_declaring_class(jvmtiEnv *jvmti, jclass klass, jfieldID field) {
 252     jclass dclass = NULL;
 253     jvmtiError err = (*jvmti)->GetFieldDeclaringClass(jvmti, klass, field, &dclass);
 254 
 255     check_jvmti_error(jvmti, "GetFieldDeclaringClass", err);
 256     printf("    Field declaring");
 257     print_class_signature(jvmti, dclass);
 258 }
 259 
 260 static void print_field_info(jvmtiEnv *jvmti, jclass klass, jfieldID field) {
 261     jint mods = 0;
 262     jboolean is_synth = JNI_FALSE;
 263     jvmtiError err = (*jvmti)->GetFieldModifiers(jvmti, klass, field, &mods);
 264 
 265     check_jvmti_error(jvmti, "GetMethodModifiers", err);
 266     printf("    Field modifiers: 0x%08x\n", mods);
 267 
 268     err = (*jvmti)->IsFieldSynthetic(jvmti, klass, field, &is_synth);
 269     check_jvmti_error(jvmti, "IsFieldSynthetic", err);
 270     printf("    Field is synthetic: %d\n", is_synth);
 271 }
 272 
 273 static void test_field_functions(jvmtiEnv *jvmti, jclass klass, jfieldID field) {
 274     print_field_name_sign(jvmti, klass, field);
 275     print_field_declaring_class(jvmti, klass, field);
 276     print_field_info(jvmti, klass, field);
 277 }
 278 
 279 static void test_class_functions(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) {
 280     jint count = 0;
 281     jint idx = 0;
 282     jmethodID* methods = NULL;
 283     jfieldID*  fields = NULL;
 284 
 285     print_class_signature(jvmti, klass);
 286     print_class_status(jvmti, klass);
 287     print_class_source_file_name(jvmti, klass);
 288     print_class_info(jvmti, klass);
 289 
 290     count = get_class_methods(jvmti, klass, &methods);
 291     for (idx = 0; idx < count; idx++) {
 292         test_method_functions(jvmti, methods[idx]);
 293     }
 294     if (methods != NULL) {
 295         deallocate(jvmti, (char*)methods);
 296     }
 297     count = get_class_fields(jvmti, klass, &fields);
 298     for (idx = 0; idx < count; idx++) {
 299         test_field_functions(jvmti, klass, fields[idx]);
 300     }
 301     if (methods != NULL) {
 302         deallocate(jvmti, (char*)fields);
 303     }
 304 }
 305 
 306 static void JNICALL
 307 VMStart(jvmtiEnv *jvmti, JNIEnv* jni) {
 308     jvmtiError err;
 309     jvmtiPhase phase;
 310 
 311     printf("VMStart event\n");
 312     get_phase(jvmti, &phase);
 313     if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE) {
 314         printf("  ## Error: unexpected phase: %d, expected: %d or %d\n",
 315                phase, JVMTI_PHASE_START, JVMTI_PHASE_LIVE);
 316         result = FAILED;
 317     }
 318 } 
 319 
 320 static void JNICALL
 321 VMInit(jvmtiEnv *jvmti, JNIEnv* jnii, jthread thread) {
 322     jvmtiError err;
 323     jvmtiPhase phase;
 324 
 325     printf("VMInit event\n");
 326     get_phase(jvmti, &phase);
 327     if (phase != JVMTI_PHASE_LIVE) {
 328         printf("  ## Error: unexpected phase: %d, expected: %d\n",
 329                phase, JVMTI_PHASE_LIVE);
 330         result = FAILED;
 331     }
 332 }
 333 
 334 static void JNICALL
 335 ClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) {
 336     static const jint EVENTS_LIMIT = 2;
 337     static       jint event_no = 0;
 338     jthread cur_thread = get_cur_thread(jvmti);
 339     jvmtiPhase phase;
 340     intptr_t exp_val = 777;
 341     intptr_t act_val;
 342 
 343     get_phase(jvmti, &phase);
 344     if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE) {
 345         printf("  ## Error: unexpected phase: %d, expected: %d or %d\n",
 346                phase, JVMTI_PHASE_START, JVMTI_PHASE_LIVE);
 347         return;
 348     }
 349     if (phase == JVMTI_PHASE_START && event_no < EVENTS_LIMIT) {
 350         printf("\nClassPrepare event during the start phase: #%d\n", event_no);
 351         // Test the JVMTI class functions during the start phase 
 352         test_class_functions(jvmti, env, thread, klass);
 353 
 354         set_thread_local(jvmti, thread, exp_val);
 355         act_val = get_thread_local(jvmti, cur_thread);
 356         if (act_val != exp_val) { // Actual value does not match the expected
 357             printf("  ## Unexpected thread-local: %ld, expected: %ld\n", act_val, exp_val);
 358             result = FAILED;
 359         } else {
 360             printf("    Got expected thread-local: %ld\n", exp_val);
 361         }
 362         event_no++;
 363     }
 364 }
 365 
 366 static
 367 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 368     jboolean with_early_vm_start_capability = JNI_FALSE;
 369     jvmtiEnv *jvmti = NULL;
 370     jvmtiError err;
 371     jint res, size;
 372     jvmtiCapabilities caps;
 373     jvmtiEventCallbacks callbacks;
 374 
 375     if (options != NULL && strstr(options, "with_early_vmstart") != NULL) {
 376         with_early_vm_start_capability = JNI_TRUE;
 377     }
 378 
 379     res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), JVMTI_VERSION_9);
 380     if (res != JNI_OK || jvmti == NULL) {
 381         printf("## Agent_Initialize: Error in GetEnv: res: %d, jvmti env: %p\n", res, jvmti);
 382         return JNI_ERR;
 383     }
 384 
 385     memset(&caps, 0, sizeof(caps));
 386     caps.can_get_source_file_name = 1;
 387     caps.can_get_synthetic_attribute = 1;
 388 
 389     if (with_early_vm_start_capability == JNI_TRUE) {
 390         caps.can_generate_early_vmstart = 1;
 391         printf("Capability enabled: can_generate_early_vmstart\n");
 392     } else {
 393         printf("Capability disabled: can_generate_early_vmstart\n");
 394     }
 395     err = (*jvmti)->AddCapabilities(jvmti, &caps);
 396     check_jvmti_error(jvmti, "AddCapabilites", err);
 397 
 398     size = (jint)sizeof(callbacks);
 399     memset(&callbacks, 0, sizeof(callbacks));
 400     callbacks.VMStart = VMStart;
 401     callbacks.VMInit = VMInit;
 402     callbacks.ClassPrepare = ClassPrepare;
 403 
 404     err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size);
 405     check_jvmti_error(jvmti, "## Agent_Initialize: SetEventCallbacks", err);
 406 
 407     err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL);
 408     check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode VM_START", err);
 409 
 410     err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
 411     check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode VM_INIT", err);
 412 
 413     err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
 414     check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode CLASS_PREPARE", err);
 415     return JNI_OK;
 416 }
 417 
 418 JNIEXPORT jint JNICALL
 419 Java_AllowedFunctions_check(JNIEnv *env, jclass cls) {
 420     return result;
 421 }
 422 
 423 #ifdef __cplusplus
 424 }
 425 #endif