1 /* 2 * Copyright (c) 2004, 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 "mtrace.h" 44 #include "java_crw_demo.h" 45 46 47 /* ------------------------------------------------------------------- */ 48 /* Some constant maximum sizes */ 49 50 #define MAX_TOKEN_LENGTH 16 51 #define MAX_THREAD_NAME_LENGTH 512 52 #define MAX_METHOD_NAME_LENGTH 1024 53 54 /* Some constant names that tie to Java class/method names. 55 * We assume the Java class whose static methods we will be calling 56 * looks like: 57 * 58 * public class Mtrace { 59 * private static int engaged; 60 * private static native void _method_entry(Object thr, int cnum, int mnum); 61 * public static void method_entry(int cnum, int mnum) 62 * { 63 * if ( engaged != 0 ) { 64 * _method_entry(Thread.currentThread(), cnum, mnum); 65 * } 66 * } 67 * private static native void _method_exit(Object thr, int cnum, int mnum); 68 * public static void method_exit(int cnum, int mnum) 69 * { 70 * if ( engaged != 0 ) { 71 * _method_exit(Thread.currentThread(), cnum, mnum); 72 * } 73 * } 74 * } 75 * 76 * The engaged field allows us to inject all classes (even system classes) 77 * and delay the actual calls to the native code until the VM has reached 78 * a safe time to call native methods (Past the JVMTI VM_START event). 79 * 80 */ 81 82 #define MTRACE_class Mtrace /* Name of class we are using */ 83 #define MTRACE_entry method_entry /* Name of java entry method */ 84 #define MTRACE_exit method_exit /* Name of java exit method */ 85 #define MTRACE_native_entry _method_entry /* Name of java entry native */ 86 #define MTRACE_native_exit _method_exit /* Name of java exit native */ 87 #define MTRACE_engaged engaged /* Name of java static field */ 88 89 /* C macros to create strings from tokens */ 90 #define _STRING(s) #s 91 #define STRING(s) _STRING(s) 92 93 /* ------------------------------------------------------------------- */ 94 95 /* Data structure to hold method and class information in agent */ 96 97 typedef struct MethodInfo { 98 const char *name; /* Method name */ 99 const char *signature; /* Method signature */ 100 int calls; /* Method call count */ 101 int returns; /* Method return count */ 102 } MethodInfo; 103 104 typedef struct ClassInfo { 105 const char *name; /* Class name */ 106 int mcount; /* Method count */ 107 MethodInfo *methods; /* Method information */ 108 int calls; /* Method call count for this class */ 109 } ClassInfo; 110 111 /* Global agent data structure */ 112 113 typedef struct { 114 /* JVMTI Environment */ 115 jvmtiEnv *jvmti; 116 jboolean vm_is_dead; 117 jboolean vm_is_started; 118 /* Data access Lock */ 119 jrawMonitorID lock; 120 /* Options */ 121 char *include; 122 char *exclude; 123 int max_count; 124 /* ClassInfo Table */ 125 ClassInfo *classes; 126 jint ccount; 127 } GlobalAgentData; 128 129 static GlobalAgentData *gdata; 130 131 /* Enter a critical section by doing a JVMTI Raw Monitor Enter */ 132 static void 133 enter_critical_section(jvmtiEnv *jvmti) 134 { 135 jvmtiError error; 136 137 error = (*jvmti)->RawMonitorEnter(jvmti, gdata->lock); 138 check_jvmti_error(jvmti, error, "Cannot enter with raw monitor"); 139 } 140 141 /* Exit a critical section by doing a JVMTI Raw Monitor Exit */ 142 static void 143 exit_critical_section(jvmtiEnv *jvmti) 144 { 145 jvmtiError error; 146 147 error = (*jvmti)->RawMonitorExit(jvmti, gdata->lock); 148 check_jvmti_error(jvmti, error, "Cannot exit with raw monitor"); 149 } 150 151 /* Get a name for a jthread */ 152 static void 153 get_thread_name(jvmtiEnv *jvmti, jthread thread, char *tname, int maxlen) 154 { 155 jvmtiThreadInfo info; 156 jvmtiError error; 157 158 /* Make sure the stack variables are garbage free */ 159 (void)memset(&info,0, sizeof(info)); 160 161 /* Assume the name is unknown for now */ 162 (void)strcpy(tname, "Unknown"); 163 164 /* Get the thread information, which includes the name */ 165 error = (*jvmti)->GetThreadInfo(jvmti, thread, &info); 166 check_jvmti_error(jvmti, error, "Cannot get thread info"); 167 168 /* The thread might not have a name, be careful here. */ 169 if ( info.name != NULL ) { 170 int len; 171 172 /* Copy the thread name into tname if it will fit */ 173 len = (int)strlen(info.name); 174 if ( len < maxlen ) { 175 (void)strcpy(tname, info.name); 176 } 177 178 /* Every string allocated by JVMTI needs to be freed */ 179 deallocate(jvmti, (void*)info.name); 180 } 181 } 182 183 /* Qsort class compare routine */ 184 static int 185 class_compar(const void *e1, const void *e2) 186 { 187 ClassInfo *c1 = (ClassInfo*)e1; 188 ClassInfo *c2 = (ClassInfo*)e2; 189 if ( c1->calls > c2->calls ) return 1; 190 if ( c1->calls < c2->calls ) return -1; 191 return 0; 192 } 193 194 /* Qsort method compare routine */ 195 static int 196 method_compar(const void *e1, const void *e2) 197 { 198 MethodInfo *m1 = (MethodInfo*)e1; 199 MethodInfo *m2 = (MethodInfo*)e2; 200 if ( m1->calls > m2->calls ) return 1; 201 if ( m1->calls < m2->calls ) return -1; 202 return 0; 203 } 204 205 /* Callback from java_crw_demo() that gives us mnum mappings */ 206 static void 207 mnum_callbacks(unsigned cnum, const char **names, const char**sigs, int mcount) 208 { 209 ClassInfo *cp; 210 int mnum; 211 212 if ( cnum >= (unsigned)gdata->ccount ) { 213 fatal_error("ERROR: Class number out of range\n"); 214 } 215 if ( mcount == 0 ) { 216 return; 217 } 218 219 cp = gdata->classes + (int)cnum; 220 cp->calls = 0; 221 cp->mcount = mcount; 222 cp->methods = (MethodInfo*)calloc(mcount, sizeof(MethodInfo)); 223 if ( cp->methods == NULL ) { 224 fatal_error("ERROR: Out of malloc memory\n"); 225 } 226 227 for ( mnum = 0 ; mnum < mcount ; mnum++ ) { 228 MethodInfo *mp; 229 230 mp = cp->methods + mnum; 231 mp->name = (const char *)strdup(names[mnum]); 232 if ( mp->name == NULL ) { 233 fatal_error("ERROR: Out of malloc memory\n"); 234 } 235 mp->signature = (const char *)strdup(sigs[mnum]); 236 if ( mp->signature == NULL ) { 237 fatal_error("ERROR: Out of malloc memory\n"); 238 } 239 } 240 } 241 242 /* Java Native Method for entry */ 243 static void 244 MTRACE_native_entry(JNIEnv *env, jclass klass, jobject thread, jint cnum, jint mnum) 245 { 246 enter_critical_section(gdata->jvmti); { 247 /* It's possible we get here right after VmDeath event, be careful */ 248 if ( !gdata->vm_is_dead ) { 249 ClassInfo *cp; 250 MethodInfo *mp; 251 252 if ( cnum >= gdata->ccount ) { 253 fatal_error("ERROR: Class number out of range\n"); 254 } 255 cp = gdata->classes + cnum; 256 if ( mnum >= cp->mcount ) { 257 fatal_error("ERROR: Method number out of range\n"); 258 } 259 mp = cp->methods + mnum; 260 if ( interested((char*)cp->name, (char*)mp->name, 261 gdata->include, gdata->exclude) ) { 262 mp->calls++; 263 cp->calls++; 264 } 265 } 266 } exit_critical_section(gdata->jvmti); 267 } 268 269 /* Java Native Method for exit */ 270 static void 271 MTRACE_native_exit(JNIEnv *env, jclass klass, jobject thread, jint cnum, jint mnum) 272 { 273 enter_critical_section(gdata->jvmti); { 274 /* It's possible we get here right after VmDeath event, be careful */ 275 if ( !gdata->vm_is_dead ) { 276 ClassInfo *cp; 277 MethodInfo *mp; 278 279 if ( cnum >= gdata->ccount ) { 280 fatal_error("ERROR: Class number out of range\n"); 281 } 282 cp = gdata->classes + cnum; 283 if ( mnum >= cp->mcount ) { 284 fatal_error("ERROR: Method number out of range\n"); 285 } 286 mp = cp->methods + mnum; 287 if ( interested((char*)cp->name, (char*)mp->name, 288 gdata->include, gdata->exclude) ) { 289 mp->returns++; 290 } 291 } 292 } exit_critical_section(gdata->jvmti); 293 } 294 295 /* Callback for JVMTI_EVENT_VM_START */ 296 static void JNICALL 297 cbVMStart(jvmtiEnv *jvmti, JNIEnv *env) 298 { 299 enter_critical_section(jvmti); { 300 jclass klass; 301 jfieldID field; 302 int rc; 303 304 /* Java Native Methods for class */ 305 static JNINativeMethod registry[2] = { 306 {STRING(MTRACE_native_entry), "(Ljava/lang/Object;II)V", 307 (void*)&MTRACE_native_entry}, 308 {STRING(MTRACE_native_exit), "(Ljava/lang/Object;II)V", 309 (void*)&MTRACE_native_exit} 310 }; 311 312 /* The VM has started. */ 313 stdout_message("VMStart\n"); 314 315 /* Register Natives for class whose methods we use */ 316 klass = (*env)->FindClass(env, STRING(MTRACE_class)); 317 if ( klass == NULL ) { 318 fatal_error("ERROR: JNI: Cannot find %s with FindClass\n", 319 STRING(MTRACE_class)); 320 } 321 rc = (*env)->RegisterNatives(env, klass, registry, 2); 322 if ( rc != 0 ) { 323 fatal_error("ERROR: JNI: Cannot register native methods for %s\n", 324 STRING(MTRACE_class)); 325 } 326 327 /* Engage calls. */ 328 field = (*env)->GetStaticFieldID(env, klass, STRING(MTRACE_engaged), "I"); 329 if ( field == NULL ) { 330 fatal_error("ERROR: JNI: Cannot get field from %s\n", 331 STRING(MTRACE_class)); 332 } 333 (*env)->SetStaticIntField(env, klass, field, 1); 334 335 /* Indicate VM has started */ 336 gdata->vm_is_started = JNI_TRUE; 337 338 } exit_critical_section(jvmti); 339 } 340 341 /* Callback for JVMTI_EVENT_VM_INIT */ 342 static void JNICALL 343 cbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) 344 { 345 enter_critical_section(jvmti); { 346 char tname[MAX_THREAD_NAME_LENGTH]; 347 static jvmtiEvent events[] = 348 { JVMTI_EVENT_THREAD_START, JVMTI_EVENT_THREAD_END }; 349 int i; 350 351 /* The VM has started. */ 352 get_thread_name(jvmti, thread, tname, sizeof(tname)); 353 stdout_message("VMInit %s\n", tname); 354 355 /* The VM is now initialized, at this time we make our requests 356 * for additional events. 357 */ 358 359 for( i=0; i < (int)(sizeof(events)/sizeof(jvmtiEvent)); i++) { 360 jvmtiError error; 361 362 /* Setup event notification modes */ 363 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 364 events[i], (jthread)NULL); 365 check_jvmti_error(jvmti, error, "Cannot set event notification"); 366 } 367 368 } exit_critical_section(jvmti); 369 } 370 371 /* Callback for JVMTI_EVENT_VM_DEATH */ 372 static void JNICALL 373 cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env) 374 { 375 enter_critical_section(jvmti); { 376 jclass klass; 377 jfieldID field; 378 379 /* The VM has died. */ 380 stdout_message("VMDeath\n"); 381 382 /* Disengage calls in MTRACE_class. */ 383 klass = (*env)->FindClass(env, STRING(MTRACE_class)); 384 if ( klass == NULL ) { 385 fatal_error("ERROR: JNI: Cannot find %s with FindClass\n", 386 STRING(MTRACE_class)); 387 } 388 field = (*env)->GetStaticFieldID(env, klass, STRING(MTRACE_engaged), "I"); 389 if ( field == NULL ) { 390 fatal_error("ERROR: JNI: Cannot get field from %s\n", 391 STRING(MTRACE_class)); 392 } 393 (*env)->SetStaticIntField(env, klass, field, 0); 394 395 /* The critical section here is important to hold back the VM death 396 * until all other callbacks have completed. 397 */ 398 399 /* Since this critical section could be holding up other threads 400 * in other event callbacks, we need to indicate that the VM is 401 * dead so that the other callbacks can short circuit their work. 402 * We don't expect any further events after VmDeath but we do need 403 * to be careful that existing threads might be in our own agent 404 * callback code. 405 */ 406 gdata->vm_is_dead = JNI_TRUE; 407 408 /* Dump out stats */ 409 stdout_message("Begin Class Stats\n"); 410 if ( gdata->ccount > 0 ) { 411 int cnum; 412 413 /* Sort table (in place) by number of method calls into class. */ 414 /* Note: Do not use this table after this qsort! */ 415 qsort(gdata->classes, gdata->ccount, sizeof(ClassInfo), 416 &class_compar); 417 418 /* Dump out gdata->max_count most called classes */ 419 for ( cnum=gdata->ccount-1 ; 420 cnum >= 0 && cnum >= gdata->ccount - gdata->max_count; 421 cnum-- ) { 422 ClassInfo *cp; 423 int mnum; 424 425 cp = gdata->classes + cnum; 426 stdout_message("Class %s %d calls\n", cp->name, cp->calls); 427 if ( cp->calls==0 ) continue; 428 429 /* Sort method table (in place) by number of method calls. */ 430 /* Note: Do not use this table after this qsort! */ 431 qsort(cp->methods, cp->mcount, sizeof(MethodInfo), 432 &method_compar); 433 for ( mnum=cp->mcount-1 ; mnum >= 0 ; mnum-- ) { 434 MethodInfo *mp; 435 436 mp = cp->methods + mnum; 437 if ( mp->calls==0 ) continue; 438 stdout_message("\tMethod %s %s %d calls %d returns\n", 439 mp->name, mp->signature, mp->calls, mp->returns); 440 } 441 } 442 } 443 stdout_message("End Class Stats\n"); 444 (void)fflush(stdout); 445 446 } exit_critical_section(jvmti); 447 448 } 449 450 /* Callback for JVMTI_EVENT_THREAD_START */ 451 static void JNICALL 452 cbThreadStart(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) 453 { 454 enter_critical_section(jvmti); { 455 /* It's possible we get here right after VmDeath event, be careful */ 456 if ( !gdata->vm_is_dead ) { 457 char tname[MAX_THREAD_NAME_LENGTH]; 458 459 get_thread_name(jvmti, thread, tname, sizeof(tname)); 460 stdout_message("ThreadStart %s\n", tname); 461 } 462 } exit_critical_section(jvmti); 463 } 464 465 /* Callback for JVMTI_EVENT_THREAD_END */ 466 static void JNICALL 467 cbThreadEnd(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) 468 { 469 enter_critical_section(jvmti); { 470 /* It's possible we get here right after VmDeath event, be careful */ 471 if ( !gdata->vm_is_dead ) { 472 char tname[MAX_THREAD_NAME_LENGTH]; 473 474 get_thread_name(jvmti, thread, tname, sizeof(tname)); 475 stdout_message("ThreadEnd %s\n", tname); 476 } 477 } exit_critical_section(jvmti); 478 } 479 480 /* Callback for JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */ 481 static void JNICALL 482 cbClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv* env, 483 jclass class_being_redefined, jobject loader, 484 const char* name, jobject protection_domain, 485 jint class_data_len, const unsigned char* class_data, 486 jint* new_class_data_len, unsigned char** new_class_data) 487 { 488 enter_critical_section(jvmti); { 489 /* It's possible we get here right after VmDeath event, be careful */ 490 if ( !gdata->vm_is_dead ) { 491 492 const char *classname; 493 494 /* Name could be NULL */ 495 if ( name == NULL ) { 496 classname = java_crw_demo_classname(class_data, class_data_len, 497 NULL); 498 if ( classname == NULL ) { 499 fatal_error("ERROR: No classname inside classfile\n"); 500 } 501 } else { 502 classname = strdup(name); 503 if ( classname == NULL ) { 504 fatal_error("ERROR: Out of malloc memory\n"); 505 } 506 } 507 508 *new_class_data_len = 0; 509 *new_class_data = NULL; 510 511 /* The tracker class itself? */ 512 if ( interested((char*)classname, "", gdata->include, gdata->exclude) 513 && strcmp(classname, STRING(MTRACE_class)) != 0 ) { 514 jint cnum; 515 int system_class; 516 unsigned char *new_image; 517 long new_length; 518 ClassInfo *cp; 519 520 /* Get unique number for every class file image loaded */ 521 cnum = gdata->ccount++; 522 523 /* Save away class information */ 524 if ( gdata->classes == NULL ) { 525 gdata->classes = (ClassInfo*)malloc( 526 gdata->ccount*sizeof(ClassInfo)); 527 } else { 528 gdata->classes = (ClassInfo*) 529 realloc((void*)gdata->classes, 530 gdata->ccount*sizeof(ClassInfo)); 531 } 532 if ( gdata->classes == NULL ) { 533 fatal_error("ERROR: Out of malloc memory\n"); 534 } 535 cp = gdata->classes + cnum; 536 cp->name = (const char *)strdup(classname); 537 if ( cp->name == NULL ) { 538 fatal_error("ERROR: Out of malloc memory\n"); 539 } 540 cp->calls = 0; 541 cp->mcount = 0; 542 cp->methods = NULL; 543 544 /* Is it a system class? If the class load is before VmStart 545 * then we will consider it a system class that should 546 * be treated carefully. (See java_crw_demo) 547 */ 548 system_class = 0; 549 if ( !gdata->vm_is_started ) { 550 system_class = 1; 551 } 552 553 new_image = NULL; 554 new_length = 0; 555 556 /* Call the class file reader/write demo code */ 557 java_crw_demo(cnum, 558 classname, 559 class_data, 560 class_data_len, 561 system_class, 562 STRING(MTRACE_class), "L" STRING(MTRACE_class) ";", 563 STRING(MTRACE_entry), "(II)V", 564 STRING(MTRACE_exit), "(II)V", 565 NULL, NULL, 566 NULL, NULL, 567 &new_image, 568 &new_length, 569 NULL, 570 &mnum_callbacks); 571 572 /* If we got back a new class image, return it back as "the" 573 * new class image. This must be JVMTI Allocate space. 574 */ 575 if ( new_length > 0 ) { 576 unsigned char *jvmti_space; 577 578 jvmti_space = (unsigned char *)allocate(jvmti, (jint)new_length); 579 (void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length); 580 *new_class_data_len = (jint)new_length; 581 *new_class_data = jvmti_space; /* VM will deallocate */ 582 } 583 584 /* Always free up the space we get from java_crw_demo() */ 585 if ( new_image != NULL ) { 586 (void)free((void*)new_image); /* Free malloc() space with free() */ 587 } 588 } 589 (void)free((void*)classname); 590 } 591 } exit_critical_section(jvmti); 592 } 593 594 /* Parse the options for this mtrace agent */ 595 static void 596 parse_agent_options(char *options) 597 { 598 char token[MAX_TOKEN_LENGTH]; 599 char *next; 600 601 gdata->max_count = 10; /* Default max=n */ 602 603 /* Parse options and set flags in gdata */ 604 if ( options==NULL ) { 605 return; 606 } 607 608 /* Get the first token from the options string. */ 609 next = get_token(options, ",=", token, sizeof(token)); 610 611 /* While not at the end of the options string, process this option. */ 612 while ( next != NULL ) { 613 if ( strcmp(token,"help")==0 ) { 614 stdout_message("The mtrace JVMTI demo agent\n"); 615 stdout_message("\n"); 616 stdout_message(" java -agent:mtrace[=options] ...\n"); 617 stdout_message("\n"); 618 stdout_message("The options are comma separated:\n"); 619 stdout_message("\t help\t\t\t Print help information\n"); 620 stdout_message("\t max=n\t\t Only list top n classes\n"); 621 stdout_message("\t include=item\t\t Only these classes/methods\n"); 622 stdout_message("\t exclude=item\t\t Exclude these classes/methods\n"); 623 stdout_message("\n"); 624 stdout_message("item\t Qualified class and/or method names\n"); 625 stdout_message("\t\t e.g. (*.<init>;Foobar.method;sun.*)\n"); 626 stdout_message("\n"); 627 exit(0); 628 } else if ( strcmp(token,"max")==0 ) { 629 char number[MAX_TOKEN_LENGTH]; 630 631 /* Get the numeric option */ 632 next = get_token(next, ",=", number, (int)sizeof(number)); 633 /* Check for token scan error */ 634 if ( next==NULL ) { 635 fatal_error("ERROR: max=n option error\n"); 636 } 637 /* Save numeric value */ 638 gdata->max_count = atoi(number); 639 } else if ( strcmp(token,"include")==0 ) { 640 int used; 641 int maxlen; 642 643 maxlen = MAX_METHOD_NAME_LENGTH; 644 if ( gdata->include == NULL ) { 645 gdata->include = (char*)calloc(maxlen+1, 1); 646 used = 0; 647 } else { 648 used = (int)strlen(gdata->include); 649 gdata->include[used++] = ','; 650 gdata->include[used] = 0; 651 gdata->include = (char*) 652 realloc((void*)gdata->include, used+maxlen+1); 653 } 654 if ( gdata->include == NULL ) { 655 fatal_error("ERROR: Out of malloc memory\n"); 656 } 657 /* Add this item to the list */ 658 next = get_token(next, ",=", gdata->include+used, maxlen); 659 /* Check for token scan error */ 660 if ( next==NULL ) { 661 fatal_error("ERROR: include option error\n"); 662 } 663 } else if ( strcmp(token,"exclude")==0 ) { 664 int used; 665 int maxlen; 666 667 maxlen = MAX_METHOD_NAME_LENGTH; 668 if ( gdata->exclude == NULL ) { 669 gdata->exclude = (char*)calloc(maxlen+1, 1); 670 used = 0; 671 } else { 672 used = (int)strlen(gdata->exclude); 673 gdata->exclude[used++] = ','; 674 gdata->exclude[used] = 0; 675 gdata->exclude = (char*) 676 realloc((void*)gdata->exclude, used+maxlen+1); 677 } 678 if ( gdata->exclude == NULL ) { 679 fatal_error("ERROR: Out of malloc memory\n"); 680 } 681 /* Add this item to the list */ 682 next = get_token(next, ",=", gdata->exclude+used, maxlen); 683 /* Check for token scan error */ 684 if ( next==NULL ) { 685 fatal_error("ERROR: exclude option error\n"); 686 } 687 } else if ( token[0]!=0 ) { 688 /* We got a non-empty token and we don't know what it is. */ 689 fatal_error("ERROR: Unknown option: %s\n", token); 690 } 691 /* Get the next token (returns NULL if there are no more) */ 692 next = get_token(next, ",=", token, sizeof(token)); 693 } 694 } 695 696 /* Agent_OnLoad: This is called immediately after the shared library is 697 * loaded. This is the first code executed. 698 */ 699 JNIEXPORT jint JNICALL 700 Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 701 { 702 static GlobalAgentData data; 703 jvmtiEnv *jvmti; 704 jvmtiError error; 705 jint res; 706 jvmtiCapabilities capabilities; 707 jvmtiEventCallbacks callbacks; 708 709 /* Setup initial global agent data area 710 * Use of static/extern data should be handled carefully here. 711 * We need to make sure that we are able to cleanup after ourselves 712 * so anything allocated in this library needs to be freed in 713 * the Agent_OnUnload() function. 714 */ 715 (void)memset((void*)&data, 0, sizeof(data)); 716 gdata = &data; 717 718 /* First thing we need to do is get the jvmtiEnv* or JVMTI environment */ 719 res = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1); 720 if (res != JNI_OK) { 721 /* This means that the VM was unable to obtain this version of the 722 * JVMTI interface, this is a fatal error. 723 */ 724 fatal_error("ERROR: Unable to access JVMTI Version 1 (0x%x)," 725 " is your JDK a 5.0 or newer version?" 726 " JNIEnv's GetEnv() returned %d\n", 727 JVMTI_VERSION_1, res); 728 } 729 730 /* Here we save the jvmtiEnv* for Agent_OnUnload(). */ 731 gdata->jvmti = jvmti; 732 733 /* Parse any options supplied on java command line */ 734 parse_agent_options(options); 735 736 /* Immediately after getting the jvmtiEnv* we need to ask for the 737 * capabilities this agent will need. In this case we need to make 738 * sure that we can get all class load hooks. 739 */ 740 (void)memset(&capabilities,0, sizeof(capabilities)); 741 capabilities.can_generate_all_class_hook_events = 1; 742 error = (*jvmti)->AddCapabilities(jvmti, &capabilities); 743 check_jvmti_error(jvmti, error, "Unable to get necessary JVMTI capabilities."); 744 745 /* Next we need to provide the pointers to the callback functions to 746 * to this jvmtiEnv* 747 */ 748 (void)memset(&callbacks,0, sizeof(callbacks)); 749 /* JVMTI_EVENT_VM_START */ 750 callbacks.VMStart = &cbVMStart; 751 /* JVMTI_EVENT_VM_INIT */ 752 callbacks.VMInit = &cbVMInit; 753 /* JVMTI_EVENT_VM_DEATH */ 754 callbacks.VMDeath = &cbVMDeath; 755 /* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */ 756 callbacks.ClassFileLoadHook = &cbClassFileLoadHook; 757 /* JVMTI_EVENT_THREAD_START */ 758 callbacks.ThreadStart = &cbThreadStart; 759 /* JVMTI_EVENT_THREAD_END */ 760 callbacks.ThreadEnd = &cbThreadEnd; 761 error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks)); 762 check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks"); 763 764 /* At first the only initial events we are interested in are VM 765 * initialization, VM death, and Class File Loads. 766 * Once the VM is initialized we will request more events. 767 */ 768 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 769 JVMTI_EVENT_VM_START, (jthread)NULL); 770 check_jvmti_error(jvmti, error, "Cannot set event notification"); 771 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 772 JVMTI_EVENT_VM_INIT, (jthread)NULL); 773 check_jvmti_error(jvmti, error, "Cannot set event notification"); 774 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 775 JVMTI_EVENT_VM_DEATH, (jthread)NULL); 776 check_jvmti_error(jvmti, error, "Cannot set event notification"); 777 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 778 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, (jthread)NULL); 779 check_jvmti_error(jvmti, error, "Cannot set event notification"); 780 781 /* Here we create a raw monitor for our use in this agent to 782 * protect critical sections of code. 783 */ 784 error = (*jvmti)->CreateRawMonitor(jvmti, "agent data", &(gdata->lock)); 785 check_jvmti_error(jvmti, error, "Cannot create raw monitor"); 786 787 /* Add demo jar file to boot classpath */ 788 add_demo_jar_to_bootclasspath(jvmti, "mtrace"); 789 790 /* We return JNI_OK to signify success */ 791 return JNI_OK; 792 } 793 794 /* Agent_OnUnload: This is called immediately before the shared library is 795 * unloaded. This is the last code executed. 796 */ 797 JNIEXPORT void JNICALL 798 Agent_OnUnload(JavaVM *vm) 799 { 800 /* Make sure all malloc/calloc/strdup space is freed */ 801 if ( gdata->include != NULL ) { 802 (void)free((void*)gdata->include); 803 gdata->include = NULL; 804 } 805 if ( gdata->exclude != NULL ) { 806 (void)free((void*)gdata->exclude); 807 gdata->exclude = NULL; 808 } 809 if ( gdata->classes != NULL ) { 810 int cnum; 811 812 for ( cnum = 0 ; cnum < gdata->ccount ; cnum++ ) { 813 ClassInfo *cp; 814 815 cp = gdata->classes + cnum; 816 (void)free((void*)cp->name); 817 if ( cp->mcount > 0 ) { 818 int mnum; 819 820 for ( mnum = 0 ; mnum < cp->mcount ; mnum++ ) { 821 MethodInfo *mp; 822 823 mp = cp->methods + mnum; 824 (void)free((void*)mp->name); 825 (void)free((void*)mp->signature); 826 } 827 (void)free((void*)cp->methods); 828 } 829 } 830 (void)free((void*)gdata->classes); 831 gdata->classes = NULL; 832 } 833 }