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