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