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 <stdint.h> 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28#include "jvmti.h" 29 30#ifdef __cplusplus 31extern "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 49static jint result = PASSED; 50 51static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 52 53JNIEXPORT 54jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 55 return Agent_Initialize(jvm, options, reserved); 56} 57 58JNIEXPORT 59jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 60 return Agent_Initialize(jvm, options, reserved); 61} 62 63JNIEXPORT 64jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 65 return JNI_VERSION_9; 66} 67 68static 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 80static 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 85static 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 92static 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 99static 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 105static 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%08x\n", status); 116 } 117 printf(" Class status: 0x%08x\n", status); 118} 119 120static 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 131static 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 142static 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 165static 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 172static 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, "GetClassFields", err); 176 return count; 177} 178 179static 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 190static 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 199static 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 234static 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 240static 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 251static 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 260static 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, "GetFieldModifiers", 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 273static 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 279static 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 (fields != NULL) { 302 deallocate(jvmti, (char*)fields); 303 } 304} 305 306static void JNICALL 307VMStart(jvmtiEnv *jvmti, JNIEnv* jni) { 308 jvmtiPhase phase; 309 310 printf("VMStart event\n"); 311 get_phase(jvmti, &phase); 312 if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE) { 313 printf(" ## Error: unexpected phase: %d, expected: %d or %d\n", 314 phase, JVMTI_PHASE_START, JVMTI_PHASE_LIVE); 315 result = FAILED; 316 } 317} 318 319static void JNICALL 320VMInit(jvmtiEnv *jvmti, JNIEnv* jnii, jthread thread) { 321 jvmtiPhase phase; 322 323 printf("VMInit event\n"); 324 get_phase(jvmti, &phase); 325 if (phase != JVMTI_PHASE_LIVE) { 326 printf(" ## Error: unexpected phase: %d, expected: %d\n", 327 phase, JVMTI_PHASE_LIVE); 328 result = FAILED; 329 } 330} 331 332static void JNICALL 333ClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) { 334 static const jint EVENTS_LIMIT = 2; 335 static jint event_no = 0; 336 jthread cur_thread = get_cur_thread(jvmti); 337 jvmtiPhase phase; 338 intptr_t exp_val = 777; 339 intptr_t act_val; 340 341 get_phase(jvmti, &phase); 342 if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE) { 343 printf(" ## Error: unexpected phase: %d, expected: %d or %d\n", 344 phase, JVMTI_PHASE_START, JVMTI_PHASE_LIVE); 345 return; 346 } 347 if (phase == JVMTI_PHASE_START && event_no < EVENTS_LIMIT) { 348 printf("\nClassPrepare event during the start phase: #%d\n", event_no); 349 // Test the JVMTI class functions during the start phase 350 test_class_functions(jvmti, env, thread, klass); 351 352 set_thread_local(jvmti, thread, exp_val); 353 act_val = get_thread_local(jvmti, cur_thread); 354 if (act_val != exp_val) { // Actual value does not match the expected 355 printf(" ## Unexpected thread-local: %ld, expected: %ld\n", 356 (long)act_val, (long)exp_val); 357 result = FAILED; 358 } else { 359 printf(" Got expected thread-local: %ld\n", (long)exp_val); 360 } 361 event_no++; 362 } 363} 364 365static 366jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 367 jboolean with_early_vm_start_capability = JNI_FALSE; 368 jvmtiEnv *jvmti = NULL; 369 jvmtiError err; 370 jint res, size; 371 jvmtiCapabilities caps; 372 jvmtiEventCallbacks callbacks; 373 374 if (options != NULL && strstr(options, "with_early_vmstart") != NULL) { 375 with_early_vm_start_capability = JNI_TRUE; 376 } 377 378 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), JVMTI_VERSION_9); 379 if (res != JNI_OK || jvmti == NULL) { 380 printf("## Agent_Initialize: Error in GetEnv: res: %d, jvmti env: %p\n", res, jvmti); 381 return JNI_ERR; 382 } 383 384 memset(&caps, 0, sizeof(caps)); 385 caps.can_get_source_file_name = 1; 386 caps.can_get_synthetic_attribute = 1; 387 388 if (with_early_vm_start_capability == JNI_TRUE) { 389 caps.can_generate_early_vmstart = 1; 390 printf("Capability enabled: can_generate_early_vmstart\n"); 391 } else { 392 printf("Capability disabled: can_generate_early_vmstart\n"); 393 } 394 err = (*jvmti)->AddCapabilities(jvmti, &caps); 395 check_jvmti_error(jvmti, "## Agent_Initialize: AddCapabilites", err); 396 397 size = (jint)sizeof(callbacks); 398 memset(&callbacks, 0, size); 399 callbacks.VMStart = VMStart; 400 callbacks.VMInit = VMInit; 401 callbacks.ClassPrepare = ClassPrepare; 402 403 err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size); 404 check_jvmti_error(jvmti, "## Agent_Initialize: SetEventCallbacks", err); 405 406 err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL); 407 check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode VM_START", err); 408 409 err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); 410 check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode VM_INIT", err); 411 412 err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL); 413 check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode CLASS_PREPARE", err); 414 return JNI_OK; 415} 416 417JNIEXPORT jint JNICALL 418Java_AllowedFunctions_check(JNIEnv *env, jclass cls) { 419 return result; 420} 421 422#ifdef __cplusplus 423} 424#endif 425