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