1 /* 2 * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 #include "stdlib.h" 42 43 #include "minst.h" 44 #include "java_crw_demo.h" 45 46 47 /* ------------------------------------------------------------------- */ 48 /* Some constant maximum sizes */ 49 50 #define MAX_TOKEN_LENGTH 80 51 #define MAX_METHOD_NAME_LENGTH 256 52 53 /* Some constant names that tie to Java class/method names. 54 * We assume the Java class whose static methods we will be calling 55 * looks like: 56 * 57 * public class Minst { 58 * private static int engaged; 59 * private static native void _method_entry(Object thr, int cnum, int mnum); 60 * public static void method_entry(int cnum, int mnum) 61 * { 62 * ... 63 * } 64 * } 65 * 66 */ 67 68 #define MINST_class Minst /* Name of class we are using */ 69 #define MINST_entry method_entry /* Name of java entry method */ 70 #define MINST_engaged engaged /* Name of java static field */ 71 72 /* C macros to create strings from tokens */ 73 #define _STRING(s) #s 74 #define STRING(s) _STRING(s) 75 76 /* ------------------------------------------------------------------- */ 77 78 /* Global agent data structure */ 79 80 typedef struct { 81 /* JVMTI Environment */ 82 jvmtiEnv *jvmti; 83 jboolean vm_is_dead; 84 jboolean vm_is_started; 85 /* Data access Lock */ 86 jrawMonitorID lock; 87 /* Options */ 88 char *include; 89 char *exclude; 90 /* Class Count/ID */ 91 jint ccount; 92 } GlobalAgentData; 93 94 static GlobalAgentData *gdata; 95 96 /* Enter a critical section by doing a JVMTI Raw Monitor Enter */ 97 static void 98 enter_critical_section(jvmtiEnv *jvmti) 99 { 100 jvmtiError error; 101 102 error = (*jvmti)->RawMonitorEnter(jvmti, gdata->lock); 103 check_jvmti_error(jvmti, error, "Cannot enter with raw monitor"); 104 } 105 106 /* Exit a critical section by doing a JVMTI Raw Monitor Exit */ 107 static void 108 exit_critical_section(jvmtiEnv *jvmti) 109 { 110 jvmtiError error; 111 112 error = (*jvmti)->RawMonitorExit(jvmti, gdata->lock); 113 check_jvmti_error(jvmti, error, "Cannot exit with raw monitor"); 114 } 115 116 /* Callback for JVMTI_EVENT_VM_START */ 117 static void JNICALL 118 cbVMStart(jvmtiEnv *jvmti, JNIEnv *env) 119 { 120 enter_critical_section(jvmti); { 121 /* Indicate VM has started */ 122 gdata->vm_is_started = JNI_TRUE; 123 } exit_critical_section(jvmti); 124 } 125 126 /* Callback for JVMTI_EVENT_VM_INIT */ 127 static void JNICALL 128 cbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) 129 { 130 enter_critical_section(jvmti); { 131 jclass klass; 132 jfieldID field; 133 134 /* Register Natives for class whose methods we use */ 135 klass = (*env)->FindClass(env, STRING(MINST_class)); 136 if ( klass == NULL ) { 137 fatal_error("ERROR: JNI: Cannot find %s with FindClass\n", 138 STRING(MINST_class)); 139 } 140 141 /* Engage calls. */ 142 field = (*env)->GetStaticFieldID(env, klass, STRING(MINST_engaged), "I"); 143 if ( field == NULL ) { 144 fatal_error("ERROR: JNI: Cannot get field from %s\n", 145 STRING(MINST_class)); 146 } 147 (*env)->SetStaticIntField(env, klass, field, 1); 148 } exit_critical_section(jvmti); 149 } 150 151 /* Callback for JVMTI_EVENT_VM_DEATH */ 152 static void JNICALL 153 cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env) 154 { 155 enter_critical_section(jvmti); { 156 jclass klass; 157 jfieldID field; 158 159 /* The VM has died. */ 160 stdout_message("VMDeath\n"); 161 162 /* Disengage calls in MINST_class. */ 163 klass = (*env)->FindClass(env, STRING(MINST_class)); 164 if ( klass == NULL ) { 165 fatal_error("ERROR: JNI: Cannot find %s with FindClass\n", 166 STRING(MINST_class)); 167 } 168 field = (*env)->GetStaticFieldID(env, klass, STRING(MINST_engaged), "I"); 169 if ( field == NULL ) { 170 fatal_error("ERROR: JNI: Cannot get field from %s\n", 171 STRING(MINST_class)); 172 } 173 (*env)->SetStaticIntField(env, klass, field, -1); 174 175 /* The critical section here is important to hold back the VM death 176 * until all other callbacks have completed. 177 */ 178 179 /* Since this critical section could be holding up other threads 180 * in other event callbacks, we need to indicate that the VM is 181 * dead so that the other callbacks can short circuit their work. 182 * We don't expect any further events after VmDeath but we do need 183 * to be careful that existing threads might be in our own agent 184 * callback code. 185 */ 186 gdata->vm_is_dead = JNI_TRUE; 187 188 } exit_critical_section(jvmti); 189 190 } 191 192 /* Callback for JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */ 193 static void JNICALL 194 cbClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv* env, 195 jclass class_being_redefined, jobject loader, 196 const char* name, jobject protection_domain, 197 jint class_data_len, const unsigned char* class_data, 198 jint* new_class_data_len, unsigned char** new_class_data) 199 { 200 enter_critical_section(jvmti); { 201 /* It's possible we get here right after VmDeath event, be careful */ 202 if ( !gdata->vm_is_dead ) { 203 204 const char *classname; 205 206 /* Name could be NULL */ 207 if ( name == NULL ) { 208 classname = java_crw_demo_classname(class_data, class_data_len, 209 NULL); 210 if ( classname == NULL ) { 211 fatal_error("ERROR: No classname inside classfile\n"); 212 } 213 } else { 214 classname = strdup(name); 215 if ( classname == NULL ) { 216 fatal_error("ERROR: Out of malloc memory\n"); 217 } 218 } 219 220 *new_class_data_len = 0; 221 *new_class_data = NULL; 222 223 /* The tracker class itself? */ 224 if ( interested((char*)classname, "", gdata->include, gdata->exclude) 225 && strcmp(classname, STRING(MINST_class)) != 0 ) { 226 jint cnum; 227 int system_class; 228 unsigned char *new_image; 229 long new_length; 230 231 /* Get unique number for every class file image loaded */ 232 cnum = gdata->ccount++; 233 234 /* Is it a system class? If the class load is before VmStart 235 * then we will consider it a system class that should 236 * be treated carefully. (See java_crw_demo) 237 */ 238 system_class = 0; 239 if ( !gdata->vm_is_started ) { 240 system_class = 1; 241 } 242 243 new_image = NULL; 244 new_length = 0; 245 246 /* Call the class file reader/write demo code */ 247 java_crw_demo(cnum, 248 classname, 249 class_data, 250 class_data_len, 251 system_class, 252 STRING(MINST_class), "L" STRING(MINST_class) ";", 253 STRING(MINST_entry), "(II)V", 254 NULL, NULL, 255 NULL, NULL, 256 NULL, NULL, 257 &new_image, 258 &new_length, 259 NULL, 260 NULL); 261 262 /* If we got back a new class image, return it back as "the" 263 * new class image. This must be JVMTI Allocate space. 264 */ 265 if ( new_length > 0 ) { 266 unsigned char *jvmti_space; 267 268 jvmti_space = (unsigned char *)allocate(jvmti, (jint)new_length); 269 (void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length); 270 *new_class_data_len = (jint)new_length; 271 *new_class_data = jvmti_space; /* VM will deallocate */ 272 } 273 274 /* Always free up the space we get from java_crw_demo() */ 275 if ( new_image != NULL ) { 276 (void)free((void*)new_image); /* Free malloc() space with free() */ 277 } 278 } 279 (void)free((void*)classname); 280 } 281 } exit_critical_section(jvmti); 282 } 283 284 /* Parse the options for this minst agent */ 285 static void 286 parse_agent_options(char *options) 287 { 288 char token[MAX_TOKEN_LENGTH]; 289 char *next; 290 291 /* Parse options and set flags in gdata */ 292 if ( options==NULL ) { 293 return; 294 } 295 296 /* Get the first token from the options string. */ 297 next = get_token(options, ",=", token, sizeof(token)); 298 299 /* While not at the end of the options string, process this option. */ 300 while ( next != NULL ) { 301 if ( strcmp(token,"help")==0 ) { 302 stdout_message("The minst JVMTI demo agent\n"); 303 stdout_message("\n"); 304 stdout_message(" java -agent:minst[=options] ...\n"); 305 stdout_message("\n"); 306 stdout_message("The options are comma separated:\n"); 307 stdout_message("\t help\t\t\t Print help information\n"); 308 stdout_message("\t include=item\t\t Only these classes/methods\n"); 309 stdout_message("\t exclude=item\t\t Exclude these classes/methods\n"); 310 stdout_message("\n"); 311 stdout_message("item\t Qualified class and/or method names\n"); 312 stdout_message("\t\t e.g. (*.<init>;Foobar.method;sun.*)\n"); 313 stdout_message("\n"); 314 exit(0); 315 } else if ( strcmp(token,"include")==0 ) { 316 int used; 317 int maxlen; 318 319 maxlen = MAX_METHOD_NAME_LENGTH; 320 if ( gdata->include == NULL ) { 321 gdata->include = (char*)calloc(maxlen+1, 1); 322 used = 0; 323 } else { 324 used = (int)strlen(gdata->include); 325 gdata->include[used++] = ','; 326 gdata->include[used] = 0; 327 gdata->include = (char*) 328 realloc((void*)gdata->include, used+maxlen+1); 329 } 330 if ( gdata->include == NULL ) { 331 fatal_error("ERROR: Out of malloc memory\n"); 332 } 333 /* Add this item to the list */ 334 next = get_token(next, ",=", gdata->include+used, maxlen); 335 /* Check for token scan error */ 336 if ( next==NULL ) { 337 fatal_error("ERROR: include option error\n"); 338 } 339 } else if ( strcmp(token,"exclude")==0 ) { 340 int used; 341 int maxlen; 342 343 maxlen = MAX_METHOD_NAME_LENGTH; 344 if ( gdata->exclude == NULL ) { 345 gdata->exclude = (char*)calloc(maxlen+1, 1); 346 used = 0; 347 } else { 348 used = (int)strlen(gdata->exclude); 349 gdata->exclude[used++] = ','; 350 gdata->exclude[used] = 0; 351 gdata->exclude = (char*) 352 realloc((void*)gdata->exclude, used+maxlen+1); 353 } 354 if ( gdata->exclude == NULL ) { 355 fatal_error("ERROR: Out of malloc memory\n"); 356 } 357 /* Add this item to the list */ 358 next = get_token(next, ",=", gdata->exclude+used, maxlen); 359 /* Check for token scan error */ 360 if ( next==NULL ) { 361 fatal_error("ERROR: exclude option error\n"); 362 } 363 } else if ( token[0]!=0 ) { 364 /* We got a non-empty token and we don't know what it is. */ 365 fatal_error("ERROR: Unknown option: %s\n", token); 366 } 367 /* Get the next token (returns NULL if there are no more) */ 368 next = get_token(next, ",=", token, sizeof(token)); 369 } 370 } 371 372 /* Agent_OnLoad: This is called immediately after the shared library is 373 * loaded. This is the first code executed. 374 */ 375 JNIEXPORT jint JNICALL 376 Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 377 { 378 static GlobalAgentData data; 379 jvmtiEnv *jvmti; 380 jvmtiError error; 381 jint res; 382 jvmtiCapabilities capabilities; 383 jvmtiEventCallbacks callbacks; 384 385 /* Setup initial global agent data area 386 * Use of static/extern data should be handled carefully here. 387 * We need to make sure that we are able to cleanup after ourselves 388 * so anything allocated in this library needs to be freed in 389 * the Agent_OnUnload() function. 390 */ 391 (void)memset((void*)&data, 0, sizeof(data)); 392 gdata = &data; 393 394 /* First thing we need to do is get the jvmtiEnv* or JVMTI environment */ 395 res = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1); 396 if (res != JNI_OK) { 397 /* This means that the VM was unable to obtain this version of the 398 * JVMTI interface, this is a fatal error. 399 */ 400 fatal_error("ERROR: Unable to access JVMTI Version 1 (0x%x)," 401 " is your JDK a 5.0 or newer version?" 402 " JNIEnv's GetEnv() returned %d\n", 403 JVMTI_VERSION_1, res); 404 } 405 406 /* Here we save the jvmtiEnv* for Agent_OnUnload(). */ 407 gdata->jvmti = jvmti; 408 409 /* Parse any options supplied on java command line */ 410 parse_agent_options(options); 411 412 /* Immediately after getting the jvmtiEnv* we need to ask for the 413 * capabilities this agent will need. In this case we need to make 414 * sure that we can get all class load hooks. 415 */ 416 (void)memset(&capabilities,0, sizeof(capabilities)); 417 capabilities.can_generate_all_class_hook_events = 1; 418 error = (*jvmti)->AddCapabilities(jvmti, &capabilities); 419 check_jvmti_error(jvmti, error, "Unable to get necessary JVMTI capabilities."); 420 421 /* Next we need to provide the pointers to the callback functions to 422 * to this jvmtiEnv* 423 */ 424 (void)memset(&callbacks,0, sizeof(callbacks)); 425 /* JVMTI_EVENT_VM_START */ 426 callbacks.VMStart = &cbVMStart; 427 /* JVMTI_EVENT_VM_INIT */ 428 callbacks.VMInit = &cbVMInit; 429 /* JVMTI_EVENT_VM_DEATH */ 430 callbacks.VMDeath = &cbVMDeath; 431 /* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */ 432 callbacks.ClassFileLoadHook = &cbClassFileLoadHook; 433 error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks)); 434 check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks"); 435 436 /* At first the only initial events we are interested in are VM 437 * initialization, VM death, and Class File Loads. 438 * Once the VM is initialized we will request more events. 439 */ 440 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 441 JVMTI_EVENT_VM_START, (jthread)NULL); 442 check_jvmti_error(jvmti, error, "Cannot set event notification"); 443 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 444 JVMTI_EVENT_VM_INIT, (jthread)NULL); 445 check_jvmti_error(jvmti, error, "Cannot set event notification"); 446 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 447 JVMTI_EVENT_VM_DEATH, (jthread)NULL); 448 check_jvmti_error(jvmti, error, "Cannot set event notification"); 449 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 450 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, (jthread)NULL); 451 check_jvmti_error(jvmti, error, "Cannot set event notification"); 452 453 /* Here we create a raw monitor for our use in this agent to 454 * protect critical sections of code. 455 */ 456 error = (*jvmti)->CreateRawMonitor(jvmti, "agent data", &(gdata->lock)); 457 check_jvmti_error(jvmti, error, "Cannot create raw monitor"); 458 459 /* Add demo jar file to boot classpath */ 460 add_demo_jar_to_bootclasspath(jvmti, "minst"); 461 462 /* We return JNI_OK to signify success */ 463 return JNI_OK; 464 } 465 466 /* Agent_OnUnload: This is called immediately before the shared library is 467 * unloaded. This is the last code executed. 468 */ 469 JNIEXPORT void JNICALL 470 Agent_OnUnload(JavaVM *vm) 471 { 472 /* Make sure all malloc/calloc/strdup space is freed */ 473 if ( gdata->include != NULL ) { 474 (void)free((void*)gdata->include); 475 gdata->include = NULL; 476 } 477 if ( gdata->exclude != NULL ) { 478 (void)free((void*)gdata->exclude); 479 gdata->exclude = NULL; 480 } 481 }