1 /*
   2  * Copyright (c) 2003, 2012, 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 /* Main source file, the basic JVMTI connection/startup code. */
  42 
  43 #include "hprof.h"
  44 
  45 #include "java_crw_demo.h"
  46 
  47 /*
  48  * This file contains all the startup logic (Agent_Onload) and
  49  *   connection to the JVMTI interface.
  50  * All JVMTI Event callbacks are in this file.
  51  * All setting of global data (gdata) is done here.
  52  * Options are parsed here.
  53  * Option help messages are here.
  54  * Termination handled here (VM_DEATH) and shutdown (Agent_OnUnload).
  55  * Spawning of the cpu sample loop thread and listener thread is done here.
  56  *
  57  * Use of private 'static' data has been limited, most shared static data
  58  *    should be found in the GlobalData structure pointed to by gdata
  59  *    (see hprof.h).
  60  *
  61  */
  62 
  63 /* The default output filenames. */
  64 
  65 #define DEFAULT_TXT_SUFFIX      ".txt"
  66 #define DEFAULT_OUTPUTFILE      "java.hprof"
  67 #define DEFAULT_OUTPUTTEMP      "java.hprof.temp"
  68 
  69 /* The only global variable, defined by this library */
  70 GlobalData *gdata;
  71 
  72 /* Experimental options */
  73 #define EXPERIMENT_NO_EARLY_HOOK 0x1
  74 
  75 /* Default trace depth */
  76 #define DEFAULT_TRACE_DEPTH 4
  77 
  78 /* Default sample interval */
  79 #define DEFAULT_SAMPLE_INTERVAL 10
  80 
  81 /* Default cutoff */
  82 #define DEFAULT_CUTOFF_POINT 0.0001
  83 
  84 /* Stringize macros for help. */
  85 #define _TO_STR(a) #a
  86 #define TO_STR(a) _TO_STR(a)
  87 
  88 /* Macros to surround callback code (non-VM_DEATH callbacks).
  89  *   Note that this just keeps a count of the non-VM_DEATH callbacks that
  90  *   are currently active, it does not prevent these callbacks from
  91  *   operating in parallel. It's the VM_DEATH callback that will wait
  92  *   for all these callbacks to either complete and block, or just block.
  93  *   We need to hold back these threads so they don't die during the final
  94  *   VM_DEATH processing.
  95  *   If the VM_DEATH callback is active in the beginning, then this callback
  96  *   just blocks to prevent further execution of the thread.
  97  *   If the VM_DEATH callback is active at the end, then this callback
  98  *   will notify the VM_DEATH callback if it's the last one.
  99  *   In all cases, the last thing they do is Enter/Exit the monitor
 100  *   gdata->callbackBlock, which will block this callback if VM_DEATH
 101  *   is running.
 102  *
 103  *   WARNING: No not 'return' or 'goto' out of the BEGIN_CALLBACK/END_CALLBACK
 104  *            block, this will mess up the count.
 105  */
 106 
 107 #define BEGIN_CALLBACK()                                            \
 108 { /* BEGIN OF CALLBACK */                                           \
 109     jboolean bypass;                                                \
 110     rawMonitorEnter(gdata->callbackLock);                           \
 111     if (gdata->vm_death_callback_active) {                          \
 112         /* VM_DEATH is active, we will bypass the CALLBACK CODE */  \
 113         bypass = JNI_TRUE;                                          \
 114         rawMonitorExit(gdata->callbackLock);                        \
 115         /* Bypassed CALLBACKS block here until VM_DEATH done */     \
 116         rawMonitorEnter(gdata->callbackBlock);                      \
 117         rawMonitorExit(gdata->callbackBlock);                       \
 118     } else {                                                        \
 119         /* We will be executing the CALLBACK CODE in this case */   \
 120         gdata->active_callbacks++;                                  \
 121         bypass = JNI_FALSE;                                         \
 122         rawMonitorExit(gdata->callbackLock);                        \
 123     }                                                               \
 124     if ( !bypass ) {                                                \
 125         /* BODY OF CALLBACK CODE (with no callback locks held) */
 126 
 127 #define END_CALLBACK() /* Part of bypass if body */                 \
 128         rawMonitorEnter(gdata->callbackLock);                       \
 129         gdata->active_callbacks--;                                  \
 130         /* If VM_DEATH is active, and last one, send notify. */     \
 131         if (gdata->vm_death_callback_active) {                      \
 132             if (gdata->active_callbacks == 0) {                     \
 133                 rawMonitorNotifyAll(gdata->callbackLock);           \
 134             }                                                       \
 135         }                                                           \
 136         rawMonitorExit(gdata->callbackLock);                        \
 137         /* Non-Bypassed CALLBACKS block here until VM_DEATH done */ \
 138         rawMonitorEnter(gdata->callbackBlock);                      \
 139         rawMonitorExit(gdata->callbackBlock);                       \
 140     }                                                               \
 141 } /* END OF CALLBACK */
 142 
 143 /* Forward declarations */
 144 static void set_callbacks(jboolean on);
 145 
 146 /* ------------------------------------------------------------------- */
 147 /* Global data initialization */
 148 
 149 /* Get initialized global data area */
 150 static GlobalData *
 151 get_gdata(void)
 152 {
 153     static GlobalData data;
 154 
 155     /* Create initial default values */
 156     (void)memset(&data, 0, sizeof(GlobalData));
 157 
 158     data.fd                             = -1; /* Non-zero file or socket. */
 159     data.heap_fd                        = -1; /* For heap=dump, see hprof_io */
 160     data.check_fd                       = -1; /* For heap=dump, see hprof_io */
 161     data.max_trace_depth                = DEFAULT_TRACE_DEPTH;
 162     data.prof_trace_depth               = DEFAULT_TRACE_DEPTH;
 163     data.sample_interval                = DEFAULT_SAMPLE_INTERVAL;
 164     data.lineno_in_traces               = JNI_TRUE;
 165     data.output_format                  = 'a';      /* 'b' for binary */
 166     data.cutoff_point                   = DEFAULT_CUTOFF_POINT;
 167     data.dump_on_exit                   = JNI_TRUE;
 168     data.gc_start_time                  = -1L;
 169 #ifdef DEBUG
 170     data.debug                          = JNI_TRUE;
 171     data.coredump                       = JNI_TRUE;
 172 #endif
 173     data.micro_state_accounting         = JNI_FALSE;
 174     data.force_output                   = JNI_TRUE;
 175     data.verbose                        = JNI_TRUE;
 176     data.primfields                     = JNI_TRUE;
 177     data.primarrays                     = JNI_TRUE;
 178 
 179     data.table_serial_number_start    = 1;
 180     data.class_serial_number_start    = 100000;
 181     data.thread_serial_number_start   = 200000;
 182     data.trace_serial_number_start    = 300000;
 183     data.object_serial_number_start   = 400000;
 184     data.frame_serial_number_start    = 500000;
 185     data.gref_serial_number_start     = 1;
 186 
 187     data.table_serial_number_counter  = data.table_serial_number_start;
 188     data.class_serial_number_counter  = data.class_serial_number_start;
 189     data.thread_serial_number_counter = data.thread_serial_number_start;
 190     data.trace_serial_number_counter  = data.trace_serial_number_start;
 191     data.object_serial_number_counter = data.object_serial_number_start;
 192     data.frame_serial_number_counter  = data.frame_serial_number_start;
 193     data.gref_serial_number_counter   = data.gref_serial_number_start;
 194 
 195     data.unknown_thread_serial_num    = data.thread_serial_number_counter++;
 196     return &data;
 197 }
 198 
 199 /* ------------------------------------------------------------------- */
 200 /* Error handler callback for the java_crw_demo (classfile read write) functions. */
 201 
 202 static void
 203 my_crw_fatal_error_handler(const char * msg, const char *file, int line)
 204 {
 205     char errmsg[256];
 206 
 207     (void)md_snprintf(errmsg, sizeof(errmsg),
 208                 "%s [%s:%d]", msg, file, line);
 209     errmsg[sizeof(errmsg)-1] = 0;
 210     HPROF_ERROR(JNI_TRUE, errmsg);
 211 }
 212 
 213 static void
 214 list_all_tables(void)
 215 {
 216     string_list();
 217     class_list();
 218     frame_list();
 219     site_list();
 220     object_list();
 221     trace_list();
 222     monitor_list();
 223     tls_list();
 224     loader_list();
 225 }
 226 
 227 /* ------------------------------------------------------------------- */
 228 /* Option Parsing support */
 229 
 230 /**
 231  * Socket connection
 232  */
 233 
 234 /*
 235  * Return a socket  connect()ed to a "hostname" that is
 236  * accept()ing heap profile data on "port." Return a value <= 0 if
 237  * such a connection can't be made.
 238  */
 239 static int
 240 connect_to_socket(char *hostname, unsigned short port)
 241 {
 242     int fd;
 243 
 244     if (port == 0 || port > 65535) {
 245         HPROF_ERROR(JNI_FALSE, "invalid port number");
 246         return -1;
 247     }
 248     if (hostname == NULL) {
 249         HPROF_ERROR(JNI_FALSE, "hostname is NULL");
 250         return -1;
 251     }
 252 
 253     /* create a socket */
 254     fd = md_connect(hostname, port);
 255     return fd;
 256 }
 257 
 258 /* Accept a filename, and adjust the name so that it is unique for this PID */
 259 static void
 260 make_unique_filename(char **filename)
 261 {
 262     int fd;
 263 
 264     /* Find a file that doesn't exist */
 265     fd = md_open(*filename);
 266     if ( fd >= 0 ) {
 267         int   pid;
 268         char *new_name;
 269         char *old_name;
 270         char *prefix;
 271         char  suffix[5];
 272         int   new_len;
 273 
 274         /* Close the file. */
 275         md_close(fd);
 276 
 277         /* Make filename name.PID[.txt] */
 278         pid = md_getpid();
 279         old_name = *filename;
 280         new_len = (int)strlen(old_name)+64;
 281         new_name = HPROF_MALLOC(new_len);
 282         prefix = old_name;
 283         suffix[0] = 0;
 284 
 285         /* Look for .txt suffix if not binary output */
 286         if (gdata->output_format != 'b') {
 287             char *dot;
 288             char *format_suffix;
 289 
 290             format_suffix = DEFAULT_TXT_SUFFIX;
 291 
 292             (void)strcpy(suffix, format_suffix);
 293 
 294             dot = strrchr(old_name, '.');
 295             if ( dot != NULL ) {
 296                 int i;
 297                 int slen;
 298                 int match;
 299 
 300                 slen = (int)strlen(format_suffix);
 301                 match = 1;
 302                 for ( i = 0; i < slen; i++ ) {
 303                     if ( dot[i]==0 ||
 304                          tolower(format_suffix[i]) != tolower(dot[i]) ) {
 305                         match = 0;
 306                         break;
 307                     }
 308                 }
 309                 if ( match ) {
 310                     (void)strcpy(suffix, dot);
 311                     *dot = 0; /* truncates prefix and old_name */
 312                 }
 313             }
 314         }
 315 
 316         /* Construct the name */
 317         (void)md_snprintf(new_name, new_len,
 318                    "%s.%d%s", prefix, pid, suffix);
 319         *filename = new_name;
 320         HPROF_FREE(old_name);
 321 
 322         /* Odds are with Windows, this file may not be so unique. */
 323         (void)remove(gdata->output_filename);
 324     }
 325 }
 326 
 327 static int
 328 get_tok(char **src, char *buf, int buflen, int sep)
 329 {
 330     int len;
 331     char *p;
 332 
 333     buf[0] = 0;
 334     if ( **src == 0 ) {
 335         return 0;
 336     }
 337     p = strchr(*src, sep);
 338     if ( p==NULL ) {
 339         len = (int)strlen(*src);
 340         p = (*src) + len;
 341     } else {
 342         /*LINTED*/
 343         len = (int)(p - (*src));
 344     }
 345     if ( (len+1) > buflen ) {
 346         return 0;
 347     }
 348     (void)memcpy(buf, *src, len);
 349     buf[len] = 0;
 350     if ( *p != 0 && *p == sep ) {
 351         (*src) = p+1;
 352     } else {
 353         (*src) = p;
 354     }
 355     return len;
 356 }
 357 
 358 static jboolean
 359 setBinarySwitch(char **src, jboolean *ptr)
 360 {
 361     char buf[80];
 362 
 363     if (!get_tok(src, buf, (int)sizeof(buf), ',')) {
 364         return JNI_FALSE;
 365     }
 366     if (strcmp(buf, "y") == 0) {
 367         *ptr = JNI_TRUE;
 368     } else if (strcmp(buf, "n") == 0) {
 369         *ptr = JNI_FALSE;
 370     } else {
 371         return JNI_FALSE;
 372     }
 373     return JNI_TRUE;
 374 }
 375 
 376 static void
 377 print_usage(void)
 378 {
 379 
 380     (void)fprintf(stdout,
 381 "\n"
 382 "     HPROF: Heap and CPU Profiling Agent (JVMTI Demonstration Code)\n"
 383 "\n"
 384 AGENTNAME " usage: java " AGENTLIB "=[help]|[<option>=<value>, ...]\n"
 385 "\n"
 386 "Option Name and Value  Description                    Default\n"
 387 "---------------------  -----------                    -------\n"
 388 "heap=dump|sites|all    heap profiling                 all\n"
 389 "cpu=samples|times|old  CPU usage                      off\n"
 390 "monitor=y|n            monitor contention             n\n"
 391 "format=a|b             text(txt) or binary output     a\n"
 392 "file=<file>            write data to file             " DEFAULT_OUTPUTFILE "[{" DEFAULT_TXT_SUFFIX "}]\n"
 393 "net=<host>:<port>      send data over a socket        off\n"
 394 "depth=<size>           stack trace depth              " TO_STR(DEFAULT_TRACE_DEPTH) "\n"
 395 "interval=<ms>          sample interval in ms          " TO_STR(DEFAULT_SAMPLE_INTERVAL) "\n"
 396 "cutoff=<value>         output cutoff point            " TO_STR(DEFAULT_CUTOFF_POINT) "\n"
 397 "lineno=y|n             line number in traces?         y\n"
 398 "thread=y|n             thread in traces?              n\n"
 399 "doe=y|n                dump on exit?                  y\n"
 400 "msa=y|n                Solaris micro state accounting n\n"
 401 "force=y|n              force output to <file>         y\n"
 402 "verbose=y|n            print messages about dumps     y\n"
 403 "\n"
 404 "Obsolete Options\n"
 405 "----------------\n"
 406 "gc_okay=y|n\n"
 407 
 408 #ifdef DEBUG
 409 "\n"
 410 "DEBUG Option           Description                    Default\n"
 411 "------------           -----------                    -------\n"
 412 "primfields=y|n         include primitive field values y\n"
 413 "primarrays=y|n         include primitive array values y\n"
 414 "debugflags=MASK        Various debug flags            0\n"
 415 "                        0x01   Report refs in and of unprepared classes\n"
 416 "logflags=MASK          Logging to stderr              0\n"
 417 "                        " TO_STR(LOG_DUMP_MISC)    " Misc logging\n"
 418 "                        " TO_STR(LOG_DUMP_LISTS)   " Dump out the tables\n"
 419 "                        " TO_STR(LOG_CHECK_BINARY) " Verify & dump format=b\n"
 420 "coredump=y|n           Core dump on fatal             n\n"
 421 "errorexit=y|n          Exit on any error              n\n"
 422 "pause=y|n              Pause on onload & echo PID     n\n"
 423 "debug=y|n              Turn on all debug checking     n\n"
 424 "X=MASK                 Internal use only              0\n"
 425 
 426 "\n"
 427 "Environment Variables\n"
 428 "---------------------\n"
 429 "_JAVA_HPROF_OPTIONS\n"
 430 "    Options can be added externally via this environment variable.\n"
 431 "    Anything contained in it will get a comma prepended to it (if needed),\n"
 432 "    then it will be added to the end of the options supplied via the\n"
 433 "    " XRUN " or " AGENTLIB " command line option.\n"
 434 
 435 #endif
 436 
 437 "\n"
 438 "Examples\n"
 439 "--------\n"
 440 "  - Get sample cpu information every 20 millisec, with a stack depth of 3:\n"
 441 "      java " AGENTLIB "=cpu=samples,interval=20,depth=3 classname\n"
 442 "  - Get heap usage information based on the allocation sites:\n"
 443 "      java " AGENTLIB "=heap=sites classname\n"
 444 
 445 #ifdef DEBUG
 446 "  - Using the external option addition with csh, log details on all runs:\n"
 447 "      setenv _JAVA_HPROF_OPTIONS \"logflags=0xC\"\n"
 448 "      java " AGENTLIB "=cpu=samples classname\n"
 449 "    is the same as:\n"
 450 "      java " AGENTLIB "=cpu=samples,logflags=0xC classname\n"
 451 #endif
 452 
 453 "\n"
 454 "Notes\n"
 455 "-----\n"
 456 "  - The option format=b cannot be used with monitor=y.\n"
 457 "  - The option format=b cannot be used with cpu=old|times.\n"
 458 "  - Use of the " XRUN " interface can still be used, e.g.\n"
 459 "       java " XRUN ":[help]|[<option>=<value>, ...]\n"
 460 "    will behave exactly the same as:\n"
 461 "       java " AGENTLIB "=[help]|[<option>=<value>, ...]\n"
 462 
 463 #ifdef DEBUG
 464 "  - The debug options and environment variables are available with both java\n"
 465 "    and java_g versions.\n"
 466 #endif
 467 
 468 "\n"
 469 "Warnings\n"
 470 "--------\n"
 471 "  - This is demonstration code for the JVMTI interface and use of BCI,\n"
 472 "    it is not an official product or formal part of the JDK.\n"
 473 "  - The " XRUN " interface will be removed in a future release.\n"
 474 "  - The option format=b is considered experimental, this format may change\n"
 475 "    in a future release.\n"
 476 
 477 #ifdef DEBUG
 478 "  - The obsolete options may be completely removed in a future release.\n"
 479 "  - The debug options and environment variables are not considered public\n"
 480 "    interfaces and can change or be removed with any type of update of\n"
 481 "    " AGENTNAME ", including patches.\n"
 482 #endif
 483 
 484         );
 485 }
 486 
 487 static void
 488 option_error(char *description)
 489 {
 490     char errmsg[FILENAME_MAX+80];
 491 
 492     (void)md_snprintf(errmsg, sizeof(errmsg),
 493            "%s option error: %s (%s)", AGENTNAME, description, gdata->options);
 494     errmsg[sizeof(errmsg)-1] = 0;
 495     HPROF_ERROR(JNI_FALSE, errmsg);
 496     error_exit_process(1);
 497 }
 498 
 499 static void
 500 parse_options(char *command_line_options)
 501 {
 502     int file_or_net_option_seen = JNI_FALSE;
 503     char *all_options;
 504     char *extra_options;
 505     char *options;
 506     char *default_filename;
 507     int   ulen;
 508 
 509     if (command_line_options == 0)
 510         command_line_options = "";
 511 
 512     if ((strcmp(command_line_options, "help")) == 0) {
 513         print_usage();
 514         error_exit_process(0);
 515     }
 516 
 517     extra_options = getenv("_JAVA_HPROF_OPTIONS");
 518     if ( extra_options == NULL ) {
 519         extra_options = "";
 520     }
 521 
 522     all_options = HPROF_MALLOC((int)strlen(command_line_options) +
 523                                 (int)strlen(extra_options) + 2);
 524     gdata->options = all_options;
 525     (void)strcpy(all_options, command_line_options);
 526     if ( extra_options[0] != 0 ) {
 527         if ( all_options[0] != 0 ) {
 528             (void)strcat(all_options, ",");
 529         }
 530         (void)strcat(all_options, extra_options);
 531     }
 532     options = all_options;
 533 
 534     LOG2("parse_options()", all_options);
 535 
 536     while (*options) {
 537         char option[16];
 538         char suboption[FILENAME_MAX+1];
 539         char *endptr;
 540 
 541         if (!get_tok(&options, option, (int)sizeof(option), '=')) {
 542             option_error("general syntax error parsing options");
 543         }
 544         if (strcmp(option, "file") == 0) {
 545             if ( file_or_net_option_seen  ) {
 546                 option_error("file or net options should only appear once");
 547             }
 548             if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
 549                 option_error("syntax error parsing file=filename");
 550             }
 551             gdata->utf8_output_filename = HPROF_MALLOC((int)strlen(suboption)+1);
 552             (void)strcpy(gdata->utf8_output_filename, suboption);
 553             file_or_net_option_seen = JNI_TRUE;
 554         } else if (strcmp(option, "net") == 0) {
 555             char port_number[16];
 556             if (file_or_net_option_seen ) {
 557                 option_error("file or net options should only appear once");
 558             }
 559             if (!get_tok(&options, suboption, (int)sizeof(suboption), ':')) {
 560                 option_error("net option missing ':'");
 561             }
 562             if (!get_tok(&options, port_number, (int)sizeof(port_number), ',')) {
 563                 option_error("net option missing port");
 564             }
 565             gdata->net_hostname = HPROF_MALLOC((int)strlen(suboption)+1);
 566             (void)strcpy(gdata->net_hostname, suboption);
 567             gdata->net_port = (int)strtol(port_number, NULL, 10);
 568             file_or_net_option_seen = JNI_TRUE;
 569         } else if (strcmp(option, "format") == 0) {
 570             if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
 571                 option_error("syntax error parsing format=a|b");
 572             }
 573             if (strcmp(suboption, "a") == 0) {
 574                 gdata->output_format = 'a';
 575             } else if (strcmp(suboption, "b") == 0) {
 576                 gdata->output_format = 'b';
 577             } else {
 578                 option_error("format option value must be a|b");
 579             }
 580         } else if (strcmp(option, "depth") == 0) {
 581             if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
 582                 option_error("syntax error parsing depth=DECIMAL");
 583             }
 584             gdata->max_trace_depth = (int)strtol(suboption, &endptr, 10);
 585             if ((endptr != NULL && *endptr != 0) || gdata->max_trace_depth < 0) {
 586                 option_error("depth option value must be decimal and >= 0");
 587             }
 588             gdata->prof_trace_depth = gdata->max_trace_depth;
 589         } else if (strcmp(option, "interval") == 0) {
 590             if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
 591                 option_error("syntax error parsing interval=DECIMAL");
 592             }
 593             gdata->sample_interval = (int)strtol(suboption, &endptr, 10);
 594             if ((endptr != NULL && *endptr != 0) || gdata->sample_interval <= 0) {
 595                 option_error("interval option value must be decimal and > 0");
 596             }
 597         } else if (strcmp(option, "cutoff") == 0) {
 598             if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
 599                 option_error("syntax error parsing cutoff=DOUBLE");
 600             }
 601             gdata->cutoff_point = strtod(suboption, &endptr);
 602             if ((endptr != NULL && *endptr != 0) || gdata->cutoff_point < 0) {
 603                 option_error("cutoff option value must be floating point and >= 0");
 604             }
 605         } else if (strcmp(option, "cpu") == 0) {
 606             if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
 607                 option_error("syntax error parsing cpu=y|samples|times|old");
 608             }
 609             if ((strcmp(suboption, "samples") == 0) ||
 610                 (strcmp(suboption, "y") == 0)) {
 611                 gdata->cpu_sampling = JNI_TRUE;
 612             } else if (strcmp(suboption, "times") == 0) {
 613                 gdata->cpu_timing = JNI_TRUE;
 614                 gdata->old_timing_format = JNI_FALSE;
 615             } else if (strcmp(suboption, "old") == 0) {
 616                 gdata->cpu_timing = JNI_TRUE;
 617                 gdata->old_timing_format = JNI_TRUE;
 618             } else {
 619                 option_error("cpu option value must be y|samples|times|old");
 620             }
 621         } else if (strcmp(option, "heap") == 0) {
 622             if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
 623                 option_error("syntax error parsing heap=dump|sites|all");
 624             }
 625             if (strcmp(suboption, "dump") == 0) {
 626                 gdata->heap_dump = JNI_TRUE;
 627             } else if (strcmp(suboption, "sites") == 0) {
 628                 gdata->alloc_sites = JNI_TRUE;
 629             } else if (strcmp(suboption, "all") == 0) {
 630                 gdata->heap_dump = JNI_TRUE;
 631                 gdata->alloc_sites = JNI_TRUE;
 632             } else {
 633                 option_error("heap option value must be dump|sites|all");
 634             }
 635         } else if( strcmp(option,"lineno") == 0) {
 636             if ( !setBinarySwitch(&options, &(gdata->lineno_in_traces)) ) {
 637                 option_error("lineno option value must be y|n");
 638             }
 639         } else if( strcmp(option,"thread") == 0) {
 640             if ( !setBinarySwitch(&options, &(gdata->thread_in_traces)) ) {
 641                 option_error("thread option value must be y|n");
 642             }
 643         } else if( strcmp(option,"doe") == 0) {
 644             if ( !setBinarySwitch(&options, &(gdata->dump_on_exit)) ) {
 645                 option_error("doe option value must be y|n");
 646             }
 647         } else if( strcmp(option,"msa") == 0) {
 648             if ( !setBinarySwitch(&options, &(gdata->micro_state_accounting)) ) {
 649                 option_error("msa option value must be y|n");
 650             }
 651         } else if( strcmp(option,"force") == 0) {
 652             if ( !setBinarySwitch(&options, &(gdata->force_output)) ) {
 653                 option_error("force option value must be y|n");
 654             }
 655         } else if( strcmp(option,"verbose") == 0) {
 656             if ( !setBinarySwitch(&options, &(gdata->verbose)) ) {
 657                 option_error("verbose option value must be y|n");
 658             }
 659         } else if( strcmp(option,"primfields") == 0) {
 660             if ( !setBinarySwitch(&options, &(gdata->primfields)) ) {
 661                 option_error("primfields option value must be y|n");
 662             }
 663         } else if( strcmp(option,"primarrays") == 0) {
 664             if ( !setBinarySwitch(&options, &(gdata->primarrays)) ) {
 665                 option_error("primarrays option value must be y|n");
 666             }
 667         } else if( strcmp(option,"monitor") == 0) {
 668             if ( !setBinarySwitch(&options, &(gdata->monitor_tracing)) ) {
 669                 option_error("monitor option value must be y|n");
 670             }
 671         } else if( strcmp(option,"gc_okay") == 0) {
 672             if ( !setBinarySwitch(&options, &(gdata->gc_okay)) ) {
 673                 option_error("gc_okay option value must be y|n");
 674             }
 675         } else if (strcmp(option, "logflags") == 0) {
 676             if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
 677                 option_error("logflags option value must be numeric");
 678             }
 679             gdata->logflags = (int)strtol(suboption, NULL, 0);
 680         } else if (strcmp(option, "debugflags") == 0) {
 681             if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
 682                 option_error("debugflags option value must be numeric");
 683             }
 684             gdata->debugflags = (int)strtol(suboption, NULL, 0);
 685         } else if (strcmp(option, "coredump") == 0) {
 686             if ( !setBinarySwitch(&options, &(gdata->coredump)) ) {
 687                 option_error("coredump option value must be y|n");
 688             }
 689         } else if (strcmp(option, "exitpause") == 0) {
 690             option_error("The exitpause option was removed, use -XX:OnError='cmd %%p'");
 691         } else if (strcmp(option, "errorexit") == 0) {
 692             if ( !setBinarySwitch(&options, &(gdata->errorexit)) ) {
 693                 option_error("errorexit option value must be y|n");
 694             }
 695         } else if (strcmp(option, "pause") == 0) {
 696             if ( !setBinarySwitch(&options, &(gdata->pause)) ) {
 697                 option_error("pause option value must be y|n");
 698             }
 699         } else if (strcmp(option, "debug") == 0) {
 700             if ( !setBinarySwitch(&options, &(gdata->debug)) ) {
 701                 option_error("debug option value must be y|n");
 702             }
 703         } else if (strcmp(option, "precrash") == 0) {
 704             option_error("The precrash option was removed, use -XX:OnError='precrash -p %%p'");
 705         } else if (strcmp(option, "X") == 0) {
 706             if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
 707                 option_error("X option value must be numeric");
 708             }
 709             gdata->experiment = (int)strtol(suboption, NULL, 0);
 710         } else {
 711             char errmsg[80];
 712             (void)strcpy(errmsg, "Unknown option: ");
 713             (void)strcat(errmsg, option);
 714             option_error(errmsg);
 715         }
 716     }
 717 
 718     if (gdata->output_format == 'b') {
 719         if (gdata->cpu_timing) {
 720             option_error("cpu=times|old is not supported with format=b");
 721         }
 722         if (gdata->monitor_tracing) {
 723             option_error("monitor=y is not supported with format=b");
 724         }
 725     }
 726 
 727     if (gdata->old_timing_format) {
 728         gdata->prof_trace_depth = 2;
 729     }
 730 
 731     if (gdata->output_format == 'b') {
 732         default_filename = DEFAULT_OUTPUTFILE;
 733     } else {
 734         default_filename = DEFAULT_OUTPUTFILE DEFAULT_TXT_SUFFIX;
 735     }
 736 
 737     if (!file_or_net_option_seen) {
 738         gdata->utf8_output_filename = HPROF_MALLOC((int)strlen(default_filename)+1);
 739         (void)strcpy(gdata->utf8_output_filename, default_filename);
 740     }
 741 
 742     if ( gdata->utf8_output_filename != NULL ) {
 743         /* UTF-8 to platform encoding (fill in gdata->output_filename) */
 744         ulen = (int)strlen(gdata->utf8_output_filename);
 745         gdata->output_filename = (char*)HPROF_MALLOC(ulen*3+3);
 746 #ifdef SKIP_NPT
 747         (void)strcpy(gdata->output_filename, gdata->utf8_output_filename);
 748 #else
 749         (void)(gdata->npt->utf8ToPlatform)
 750               (gdata->npt->utf, (jbyte*)gdata->utf8_output_filename, ulen,
 751                gdata->output_filename, ulen*3+3);
 752 #endif
 753     }
 754 
 755     /* By default we turn on gdata->alloc_sites and gdata->heap_dump */
 756     if (     !gdata->cpu_timing &&
 757              !gdata->cpu_sampling &&
 758              !gdata->monitor_tracing &&
 759              !gdata->alloc_sites &&
 760              !gdata->heap_dump) {
 761         gdata->heap_dump = JNI_TRUE;
 762         gdata->alloc_sites = JNI_TRUE;
 763     }
 764 
 765     if ( gdata->alloc_sites || gdata->heap_dump ) {
 766         gdata->obj_watch = JNI_TRUE;
 767     }
 768     if ( gdata->obj_watch || gdata->cpu_timing ) {
 769         gdata->bci = JNI_TRUE;
 770     }
 771 
 772     /* Create files & sockets needed */
 773     if (gdata->heap_dump) {
 774         char *base;
 775         int   len;
 776 
 777         /* Get a fast tempfile for the heap information */
 778         base = gdata->output_filename;
 779         if ( base==NULL ) {
 780             base = default_filename;
 781         }
 782         len = (int)strlen(base);
 783         gdata->heapfilename = HPROF_MALLOC(len + 5);
 784         (void)strcpy(gdata->heapfilename, base);
 785         (void)strcat(gdata->heapfilename, ".TMP");
 786         make_unique_filename(&(gdata->heapfilename));
 787         (void)remove(gdata->heapfilename);
 788         if (gdata->output_format == 'b') {
 789             if ( gdata->logflags & LOG_CHECK_BINARY ) {
 790                 char * check_suffix;
 791 
 792                 check_suffix = ".check" DEFAULT_TXT_SUFFIX;
 793                 gdata->checkfilename =
 794                     HPROF_MALLOC((int)strlen(default_filename)+
 795                                 (int)strlen(check_suffix)+1);
 796                 (void)strcpy(gdata->checkfilename, default_filename);
 797                 (void)strcat(gdata->checkfilename, check_suffix);
 798                 (void)remove(gdata->checkfilename);
 799                 gdata->check_fd = md_creat(gdata->checkfilename);
 800             }
 801             if ( gdata->debug ) {
 802                 gdata->logflags |= LOG_CHECK_BINARY;
 803             }
 804             gdata->heap_fd = md_creat_binary(gdata->heapfilename);
 805         } else {
 806             gdata->heap_fd = md_creat(gdata->heapfilename);
 807         }
 808         if ( gdata->heap_fd < 0 ) {
 809             char errmsg[FILENAME_MAX+80];
 810 
 811             (void)md_snprintf(errmsg, sizeof(errmsg),
 812                      "can't create temp heap file: %s", gdata->heapfilename);
 813                     errmsg[sizeof(errmsg)-1] = 0;
 814             HPROF_ERROR(JNI_TRUE, errmsg);
 815         }
 816     }
 817 
 818     if ( gdata->net_port > 0 ) {
 819         LOG2("Agent_OnLoad", "Connecting to socket");
 820         gdata->fd = connect_to_socket(gdata->net_hostname, (unsigned short)gdata->net_port);
 821         if (gdata->fd <= 0) {
 822             char errmsg[120];
 823 
 824             (void)md_snprintf(errmsg, sizeof(errmsg),
 825                 "can't connect to %s:%u", gdata->net_hostname, gdata->net_port);
 826             errmsg[sizeof(errmsg)-1] = 0;
 827             HPROF_ERROR(JNI_FALSE, errmsg);
 828             error_exit_process(1);
 829         }
 830         gdata->socket = JNI_TRUE;
 831     } else {
 832         /* If going out to a file, obey the force=y|n option */
 833         if ( !gdata->force_output ) {
 834             make_unique_filename(&(gdata->output_filename));
 835         }
 836         /* Make doubly sure this file does NOT exist */
 837         (void)remove(gdata->output_filename);
 838         /* Create the file */
 839         if (gdata->output_format == 'b') {
 840             gdata->fd = md_creat_binary(gdata->output_filename);
 841         } else {
 842             gdata->fd = md_creat(gdata->output_filename);
 843         }
 844         if (gdata->fd < 0) {
 845             char errmsg[FILENAME_MAX+80];
 846 
 847             (void)md_snprintf(errmsg, sizeof(errmsg),
 848                 "can't create profile file: %s", gdata->output_filename);
 849             errmsg[sizeof(errmsg)-1] = 0;
 850             HPROF_ERROR(JNI_FALSE, errmsg);
 851             error_exit_process(1);
 852         }
 853     }
 854 
 855 }
 856 
 857 /* ------------------------------------------------------------------- */
 858 /* Data reset and dump functions */
 859 
 860 static void
 861 reset_all_data(void)
 862 {
 863     if (gdata->cpu_sampling || gdata->cpu_timing || gdata->monitor_tracing) {
 864         rawMonitorEnter(gdata->data_access_lock);
 865     }
 866 
 867     if (gdata->cpu_sampling || gdata->cpu_timing) {
 868         trace_clear_cost();
 869     }
 870     if (gdata->monitor_tracing) {
 871         monitor_clear();
 872     }
 873 
 874     if (gdata->cpu_sampling || gdata->cpu_timing || gdata->monitor_tracing) {
 875         rawMonitorExit(gdata->data_access_lock);
 876     }
 877 }
 878 
 879 static void reset_class_load_status(JNIEnv *env, jthread thread);
 880 
 881 static void
 882 dump_all_data(JNIEnv *env)
 883 {
 884     verbose_message("Dumping");
 885     if (gdata->monitor_tracing) {
 886         verbose_message(" contended monitor usage ...");
 887         tls_dump_monitor_state(env);
 888         monitor_write_contended_time(env, gdata->cutoff_point);
 889     }
 890     if (gdata->heap_dump) {
 891         verbose_message(" Java heap ...");
 892         /* Update the class table */
 893         reset_class_load_status(env, NULL);
 894         site_heapdump(env);
 895     }
 896     if (gdata->alloc_sites) {
 897         verbose_message(" allocation sites ...");
 898         site_write(env, 0, gdata->cutoff_point);
 899     }
 900     if (gdata->cpu_sampling) {
 901         verbose_message(" CPU usage by sampling running threads ...");
 902         trace_output_cost(env, gdata->cutoff_point);
 903     }
 904     if (gdata->cpu_timing) {
 905         if (!gdata->old_timing_format) {
 906             verbose_message(" CPU usage by timing methods ...");
 907             trace_output_cost(env, gdata->cutoff_point);
 908         } else {
 909             verbose_message(" CPU usage in old prof format ...");
 910             trace_output_cost_in_prof_format(env);
 911         }
 912     }
 913     reset_all_data();
 914     io_flush();
 915     verbose_message(" done.\n");
 916 }
 917 
 918 /* ------------------------------------------------------------------- */
 919 /* Dealing with class load and unload status */
 920 
 921 static void
 922 reset_class_load_status(JNIEnv *env, jthread thread)
 923 {
 924 
 925     WITH_LOCAL_REFS(env, 1) {
 926         jint    class_count;
 927         jclass *classes;
 928         jint    i;
 929 
 930         /* Get all classes from JVMTI, make sure they are in the class table. */
 931         getLoadedClasses(&classes, &class_count);
 932 
 933         /* We don't know if the class list has changed really, so we
 934          *    guess by the class count changing. Don't want to do
 935          *    a bunch of work on classes when it's unnecessary.
 936          *    I assume that even though we have global references on the
 937          *    jclass object that the class is still considered unloaded.
 938          *    (e.g. GC of jclass isn't required for it to be included
 939          *    in the unloaded list, or not in the load list)
 940          *    [Note: Use of Weak references was a performance problem.]
 941          */
 942         if ( class_count != gdata->class_count ) {
 943 
 944             rawMonitorEnter(gdata->data_access_lock); {
 945 
 946                 /* Unmark the classes in the load list */
 947                 class_all_status_remove(CLASS_IN_LOAD_LIST);
 948 
 949                 /* Pretend like it was a class load event */
 950                 for ( i = 0 ; i < class_count ; i++ ) {
 951                     jobject loader;
 952 
 953                     loader = getClassLoader(classes[i]);
 954                     event_class_load(env, thread, classes[i], loader);
 955                 }
 956 
 957                 /* Process the classes that have been unloaded */
 958                 class_do_unloads(env);
 959 
 960             } rawMonitorExit(gdata->data_access_lock);
 961 
 962         }
 963 
 964         /* Free the space and save the count. */
 965         jvmtiDeallocate(classes);
 966         gdata->class_count = class_count;
 967 
 968     } END_WITH_LOCAL_REFS;
 969 
 970 }
 971 
 972 /* A GC or Death event has happened, so do some cleanup */
 973 static void
 974 object_free_cleanup(JNIEnv *env, jboolean force_class_table_reset)
 975 {
 976     Stack *stack;
 977 
 978     /* Then we process the ObjectFreeStack */
 979     rawMonitorEnter(gdata->object_free_lock); {
 980         stack = gdata->object_free_stack;
 981         gdata->object_free_stack = NULL; /* Will trigger new stack */
 982     } rawMonitorExit(gdata->object_free_lock);
 983 
 984     /* Notice we just grabbed the stack of freed objects so
 985      *    any object free events will create a new stack.
 986      */
 987     if ( stack != NULL ) {
 988         int count;
 989         int i;
 990 
 991         count = stack_depth(stack);
 992 
 993         /* If we saw something freed in this GC */
 994         if ( count > 0 ) {
 995 
 996             for ( i = 0 ; i < count ; i++ ) {
 997                 ObjectIndex object_index;
 998                 jlong tag;
 999 
1000                 tag = *(jlong*)stack_element(stack,i);
1001                     object_index = tag_extract(tag);
1002 
1003                 (void)object_free(object_index);
1004             }
1005 
1006             /* We reset the class load status (only do this once) */
1007             reset_class_load_status(env, NULL);
1008             force_class_table_reset = JNI_FALSE;
1009 
1010         }
1011 
1012         /* Just terminate this stack object */
1013         stack_term(stack);
1014     }
1015 
1016     /* We reset the class load status if we haven't and need to */
1017     if ( force_class_table_reset ) {
1018         reset_class_load_status(env, NULL);
1019     }
1020 
1021 }
1022 
1023 /* Main function for thread that watches for GC finish events */
1024 static void JNICALL
1025 gc_finish_watcher(jvmtiEnv *jvmti, JNIEnv *env, void *p)
1026 {
1027     jboolean active;
1028 
1029     active = JNI_TRUE;
1030 
1031     /* Indicate the watcher thread is active */
1032     rawMonitorEnter(gdata->gc_finish_lock); {
1033         gdata->gc_finish_active = JNI_TRUE;
1034     } rawMonitorExit(gdata->gc_finish_lock);
1035 
1036     /* Loop while active */
1037     while ( active ) {
1038         jboolean do_cleanup;
1039 
1040         do_cleanup = JNI_FALSE;
1041         rawMonitorEnter(gdata->gc_finish_lock); {
1042             /* Don't wait if VM_DEATH wants us to quit */
1043             if ( gdata->gc_finish_stop_request ) {
1044                 /* Time to terminate */
1045                 active = JNI_FALSE;
1046             } else {
1047                 /* Wait for notification to do cleanup, or terminate */
1048                 rawMonitorWait(gdata->gc_finish_lock, 0);
1049                 /* After wait, check to see if VM_DEATH wants us to quit */
1050                 if ( gdata->gc_finish_stop_request ) {
1051                     /* Time to terminate */
1052                     active = JNI_FALSE;
1053                 }
1054             }
1055             if ( active && gdata->gc_finish > 0 ) {
1056                 /* Time to cleanup, reset count and prepare for cleanup */
1057                 gdata->gc_finish = 0;
1058                 do_cleanup = JNI_TRUE;
1059             }
1060         } rawMonitorExit(gdata->gc_finish_lock);
1061 
1062         /* Do the cleanup if requested outside gc_finish_lock */
1063         if ( do_cleanup ) {
1064             /* Free up all freed objects, don't force class table reset
1065              *   We cannot let the VM_DEATH complete while we are doing
1066              *   this cleanup. So if during this, VM_DEATH happens,
1067              *   the VM_DEATH callback should block waiting for this
1068              *   loop to terminate, and send a notification to the
1069              *   VM_DEATH thread.
1070              */
1071             object_free_cleanup(env, JNI_FALSE);
1072 
1073             /* Cleanup the tls table where the Thread objects were GC'd */
1074             tls_garbage_collect(env);
1075         }
1076 
1077     }
1078 
1079     /* Falling out means VM_DEATH is happening, we need to notify VM_DEATH
1080      *    that we are done doing the cleanup. VM_DEATH is waiting on this
1081      *    notify.
1082      */
1083     rawMonitorEnter(gdata->gc_finish_lock); {
1084         gdata->gc_finish_active = JNI_FALSE;
1085         rawMonitorNotifyAll(gdata->gc_finish_lock);
1086     } rawMonitorExit(gdata->gc_finish_lock);
1087 }
1088 
1089 /* ------------------------------------------------------------------- */
1090 /* JVMTI Event callback functions */
1091 
1092 static void
1093 setup_event_mode(jboolean onload_set_only, jvmtiEventMode state)
1094 {
1095     if ( onload_set_only ) {
1096         setEventNotificationMode(state,
1097                         JVMTI_EVENT_VM_INIT,                   NULL);
1098         setEventNotificationMode(state,
1099                         JVMTI_EVENT_VM_DEATH,                  NULL);
1100         if (gdata->bci) {
1101             setEventNotificationMode(state,
1102                         JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,      NULL);
1103         }
1104     } else {
1105         /* Enable all other JVMTI events of interest now. */
1106         setEventNotificationMode(state,
1107                         JVMTI_EVENT_THREAD_START,              NULL);
1108         setEventNotificationMode(state,
1109                         JVMTI_EVENT_THREAD_END,                NULL);
1110         setEventNotificationMode(state,
1111                         JVMTI_EVENT_CLASS_LOAD,                NULL);
1112         setEventNotificationMode(state,
1113                         JVMTI_EVENT_CLASS_PREPARE,             NULL);
1114         setEventNotificationMode(state,
1115                         JVMTI_EVENT_DATA_DUMP_REQUEST,         NULL);
1116         if (gdata->cpu_timing) {
1117             setEventNotificationMode(state,
1118                         JVMTI_EVENT_EXCEPTION_CATCH,           NULL);
1119         }
1120         if (gdata->monitor_tracing) {
1121             setEventNotificationMode(state,
1122                         JVMTI_EVENT_MONITOR_WAIT,              NULL);
1123             setEventNotificationMode(state,
1124                         JVMTI_EVENT_MONITOR_WAITED,            NULL);
1125             setEventNotificationMode(state,
1126                         JVMTI_EVENT_MONITOR_CONTENDED_ENTER,   NULL);
1127             setEventNotificationMode(state,
1128                         JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
1129         }
1130         if (gdata->obj_watch) {
1131             setEventNotificationMode(state,
1132                         JVMTI_EVENT_OBJECT_FREE,               NULL);
1133         }
1134         setEventNotificationMode(state,
1135                         JVMTI_EVENT_GARBAGE_COLLECTION_START,  NULL);
1136         setEventNotificationMode(state,
1137                         JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL);
1138     }
1139 }
1140 
1141 /* JVMTI_EVENT_VM_INIT */
1142 static void JNICALL
1143 cbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
1144 {
1145     rawMonitorEnter(gdata->data_access_lock); {
1146 
1147         LoaderIndex loader_index;
1148         ClassIndex  cnum;
1149         TlsIndex    tls_index;
1150 
1151         gdata->jvm_initializing = JNI_TRUE;
1152 
1153         /* Header to use in heap dumps */
1154         gdata->header    = "JAVA PROFILE 1.0.1";
1155         gdata->segmented = JNI_FALSE;
1156         if (gdata->output_format == 'b') {
1157             /* We need JNI here to call in and get the current maximum memory */
1158             gdata->maxMemory      = getMaxMemory(env);
1159             gdata->maxHeapSegment = (jlong)2000000000;
1160             /* More than 2Gig triggers segments and 1.0.2 */
1161             if ( gdata->maxMemory >= gdata->maxHeapSegment ) {
1162                 gdata->header    = "JAVA PROFILE 1.0.2";
1163                 gdata->segmented = JNI_TRUE; /* 1.0.2 */
1164             }
1165         }
1166 
1167         /* We write the initial header after the VM initializes now
1168          *    because we needed to use JNI to get maxMemory and determine if
1169          *    a 1.0.1 or a 1.0.2 header will be used.
1170          *    This used to be done in Agent_OnLoad.
1171          */
1172         io_write_file_header();
1173 
1174         LOG("cbVMInit begin");
1175 
1176         /* Create a system loader entry first */
1177         loader_index            = loader_find_or_create(NULL,NULL);
1178 
1179         /* Find the thread jclass (does JNI calls) */
1180         gdata->thread_cnum = class_find_or_create("Ljava/lang/Thread;",
1181                         loader_index);
1182         class_add_status(gdata->thread_cnum, CLASS_SYSTEM);
1183 
1184         /* Issue fake system thread start */
1185         tls_index = tls_find_or_create(env, thread);
1186 
1187         /* Setup the Tracker class (should be first class in table) */
1188         tracker_setup_class();
1189 
1190         /* Find selected system classes to keep track of */
1191         gdata->system_class_size = 0;
1192         cnum = class_find_or_create("Ljava/lang/Object;", loader_index);
1193 
1194         gdata->system_trace_index = tls_get_trace(tls_index, env,
1195                                 gdata->max_trace_depth, JNI_FALSE);
1196         gdata->system_object_site_index = site_find_or_create(
1197                     cnum, gdata->system_trace_index);
1198 
1199         /* Used to ID HPROF generated items */
1200         gdata->hprof_trace_index = tls_get_trace(tls_index, env,
1201                                 gdata->max_trace_depth, JNI_FALSE);
1202         gdata->hprof_site_index = site_find_or_create(
1203                     cnum, gdata->hprof_trace_index);
1204 
1205         if ( gdata->logflags & LOG_DUMP_LISTS ) {
1206             list_all_tables();
1207         }
1208 
1209         /* Prime the class table */
1210         reset_class_load_status(env, thread);
1211 
1212         /* Find the tracker jclass and jmethodID's (does JNI calls) */
1213         if ( gdata->bci ) {
1214             tracker_setup_methods(env);
1215         }
1216 
1217         /* Start any agent threads (does JNI, JVMTI, and Java calls) */
1218 
1219         /* Thread to watch for gc_finish events */
1220         rawMonitorEnter(gdata->gc_finish_lock); {
1221             createAgentThread(env, "HPROF gc_finish watcher",
1222                               &gc_finish_watcher);
1223         } rawMonitorExit(gdata->gc_finish_lock);
1224 
1225         /* Start up listener thread if we need it */
1226         if ( gdata->socket ) {
1227             listener_init(env);
1228         }
1229 
1230         /* Start up cpu sampling thread if we need it */
1231         if ( gdata->cpu_sampling ) {
1232             /* Note: this could also get started later (see cpu) */
1233             cpu_sample_init(env);
1234         }
1235 
1236         /* Setup event modes */
1237         setup_event_mode(JNI_FALSE, JVMTI_ENABLE);
1238 
1239         /* Engage tracking (sets Java Tracker field so injections call into
1240          *     agent library).
1241          */
1242         if ( gdata->bci ) {
1243             tracker_engage(env);
1244         }
1245 
1246         /* Indicate the VM is initialized now */
1247         gdata->jvm_initialized = JNI_TRUE;
1248         gdata->jvm_initializing = JNI_FALSE;
1249 
1250         LOG("cbVMInit end");
1251 
1252     } rawMonitorExit(gdata->data_access_lock);
1253 }
1254 
1255 /* JVMTI_EVENT_VM_DEATH */
1256 static void JNICALL
1257 cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env)
1258 {
1259     /*
1260      * Use local flag to minimize gdata->dump_lock hold time.
1261      */
1262     jboolean need_to_dump = JNI_FALSE;
1263 
1264     LOG("cbVMDeath");
1265 
1266     /* Shutdown thread watching gc_finish, outside CALLBACK locks.
1267      *   We need to make sure the watcher thread is done doing any cleanup
1268      *   work before we continue here.
1269      */
1270     rawMonitorEnter(gdata->gc_finish_lock); {
1271         /* Notify watcher thread to finish up, it will send
1272          *   another notify when done. If the watcher thread is busy
1273          *   cleaning up, it will detect gc_finish_stop_request when it's done.
1274          *   Then it sets gc_finish_active to JNI_FALSE and will notify us.
1275          *   If the watcher thread is waiting to be notified, then the
1276          *   notification wakes it up.
1277          *   We do not want to do the VM_DEATH while the gc_finish
1278          *   watcher thread is in the middle of a cleanup.
1279          */
1280         gdata->gc_finish_stop_request = JNI_TRUE;
1281         rawMonitorNotifyAll(gdata->gc_finish_lock);
1282         /* Wait for the gc_finish watcher thread to notify us it's done */
1283         while ( gdata->gc_finish_active ) {
1284             rawMonitorWait(gdata->gc_finish_lock,0);
1285         }
1286     } rawMonitorExit(gdata->gc_finish_lock);
1287 
1288     /* The gc_finish watcher thread should be done now, or done shortly. */
1289 
1290 
1291     /* BEGIN_CALLBACK/END_CALLBACK handling. */
1292 
1293     /* The callbackBlock prevents any active callbacks from returning
1294      *   back to the VM, and also blocks all new callbacks.
1295      *   We want to prevent any threads from premature death, so
1296      *   that we don't have worry about that during thread queries
1297      *   in this final dump process.
1298      */
1299     rawMonitorEnter(gdata->callbackBlock); {
1300 
1301         /* We need to wait for all callbacks actively executing to block
1302          *   on exit, and new ones will block on entry.
1303          *   The BEGIN_CALLBACK/END_CALLBACK macros keep track of callbacks
1304          *   that are active.
1305          *   Once the last active callback is done, it will notify this
1306          *   thread and block.
1307          */
1308 
1309         rawMonitorEnter(gdata->callbackLock); {
1310             /* Turn off native calls */
1311             if ( gdata->bci ) {
1312                 tracker_disengage(env);
1313             }
1314             gdata->vm_death_callback_active = JNI_TRUE;
1315             while (gdata->active_callbacks > 0) {
1316                 rawMonitorWait(gdata->callbackLock, 0);
1317             }
1318         } rawMonitorExit(gdata->callbackLock);
1319 
1320         /* Now we know that no threads will die on us, being blocked
1321          *   on some event callback, at a minimum ThreadEnd.
1322          */
1323 
1324         /* Make some basic checks. */
1325         rawMonitorEnter(gdata->data_access_lock); {
1326             if ( gdata->jvm_initializing ) {
1327                 HPROF_ERROR(JNI_TRUE, "VM Death during VM Init");
1328                 return;
1329             }
1330             if ( !gdata->jvm_initialized ) {
1331                 HPROF_ERROR(JNI_TRUE, "VM Death before VM Init");
1332                 return;
1333             }
1334             if (gdata->jvm_shut_down) {
1335                 HPROF_ERROR(JNI_TRUE, "VM Death more than once?");
1336                 return;
1337             }
1338         } rawMonitorExit(gdata->data_access_lock);
1339 
1340         /* Shutdown the cpu loop thread */
1341         if ( gdata->cpu_sampling ) {
1342             cpu_sample_term(env);
1343         }
1344 
1345         /* Time to dump the final data */
1346         rawMonitorEnter(gdata->dump_lock); {
1347 
1348             gdata->jvm_shut_down = JNI_TRUE;
1349 
1350             if (!gdata->dump_in_process) {
1351                 need_to_dump    = JNI_TRUE;
1352                 gdata->dump_in_process = JNI_TRUE;
1353                 /*
1354                  * Setting gdata->dump_in_process will cause cpu sampling to pause
1355                  * (if we are sampling). We don't resume sampling after the
1356                  * dump_all_data() call below because the VM is shutting
1357                  * down.
1358                  */
1359             }
1360 
1361         } rawMonitorExit(gdata->dump_lock);
1362 
1363         /* Dump everything if we need to */
1364         if (gdata->dump_on_exit && need_to_dump) {
1365 
1366             dump_all_data(env);
1367         }
1368 
1369         /* Disable all events and callbacks now, all of them.
1370          *   NOTE: It's important that this be done after the dump
1371          *         it prevents other threads from messing up the data
1372          *         because they will block on ThreadStart and ThreadEnd
1373          *         events due to the CALLBACK block.
1374          */
1375         set_callbacks(JNI_FALSE);
1376         setup_event_mode(JNI_FALSE, JVMTI_DISABLE);
1377         setup_event_mode(JNI_TRUE, JVMTI_DISABLE);
1378 
1379         /* Write tail of file */
1380         io_write_file_footer();
1381 
1382     } rawMonitorExit(gdata->callbackBlock);
1383 
1384     /* Shutdown the listener thread and socket, or flush I/O buffers */
1385     if (gdata->socket) {
1386         listener_term(env);
1387     } else {
1388         io_flush();
1389     }
1390 
1391     /* Close the file descriptors down */
1392     if ( gdata->fd  >= 0 ) {
1393         (void)md_close(gdata->fd);
1394         gdata->fd = -1;
1395         if ( gdata->logflags & LOG_CHECK_BINARY ) {
1396             if (gdata->output_format == 'b' && gdata->output_filename != NULL) {
1397                 check_binary_file(gdata->output_filename);
1398             }
1399         }
1400     }
1401     if ( gdata->heap_fd  >= 0 ) {
1402         (void)md_close(gdata->heap_fd);
1403         gdata->heap_fd = -1;
1404     }
1405 
1406     if ( gdata->check_fd  >= 0 ) {
1407         (void)md_close(gdata->check_fd);
1408         gdata->check_fd = -1;
1409     }
1410 
1411     /* Remove the temporary heap file */
1412     if (gdata->heap_dump) {
1413         (void)remove(gdata->heapfilename);
1414     }
1415 
1416     /* If logging, dump the tables */
1417     if ( gdata->logflags & LOG_DUMP_LISTS ) {
1418         list_all_tables();
1419     }
1420 
1421     /* Make sure all global references are deleted */
1422     class_delete_global_references(env);
1423     loader_delete_global_references(env);
1424     tls_delete_global_references(env);
1425 
1426 }
1427 
1428 /* JVMTI_EVENT_THREAD_START */
1429 static void JNICALL
1430 cbThreadStart(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
1431 {
1432     LOG3("cbThreadStart", "thread is", (int)(long)(ptrdiff_t)thread);
1433 
1434     BEGIN_CALLBACK() {
1435         event_thread_start(env, thread);
1436     } END_CALLBACK();
1437 }
1438 
1439 /* JVMTI_EVENT_THREAD_END */
1440 static void JNICALL
1441 cbThreadEnd(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
1442 {
1443     LOG3("cbThreadEnd", "thread is", (int)(long)(ptrdiff_t)thread);
1444 
1445     BEGIN_CALLBACK() {
1446         event_thread_end(env, thread);
1447     } END_CALLBACK();
1448 }
1449 
1450 /* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */
1451 static void JNICALL
1452 cbClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv* env,
1453                 jclass class_being_redefined, jobject loader,
1454                 const char* name, jobject protection_domain,
1455                 jint class_data_len, const unsigned char* class_data,
1456                 jint* new_class_data_len, unsigned char** new_class_data)
1457 {
1458 
1459     /* WARNING: This will be called before VM_INIT. */
1460 
1461     LOG2("cbClassFileLoadHook:",(name==NULL?"Unknown":name));
1462 
1463     if (!gdata->bci) {
1464         return;
1465     }
1466 
1467     BEGIN_CALLBACK() {
1468         rawMonitorEnter(gdata->data_access_lock); {
1469             const char *classname;
1470 
1471             if ( gdata->bci_counter == 0 ) {
1472                 /* Prime the system classes */
1473                 class_prime_system_classes();
1474             }
1475 
1476             gdata->bci_counter++;
1477 
1478             *new_class_data_len = 0;
1479             *new_class_data     = NULL;
1480 
1481             /* Name could be NULL */
1482             if ( name == NULL ) {
1483                 classname = ((JavaCrwDemoClassname)
1484                              (gdata->java_crw_demo_classname_function))
1485                     (class_data, class_data_len, &my_crw_fatal_error_handler);
1486                 if ( classname == NULL ) {
1487                     HPROF_ERROR(JNI_TRUE, "No classname in classfile");
1488                 }
1489             } else {
1490                 classname = strdup(name);
1491                 if ( classname == NULL ) {
1492                     HPROF_ERROR(JNI_TRUE, "Ran out of malloc() space");
1493                 }
1494             }
1495 
1496             /* The tracker class itself? */
1497             if ( strcmp(classname, TRACKER_CLASS_NAME) != 0 ) {
1498                 ClassIndex            cnum;
1499                 int                   system_class;
1500                 unsigned char *       new_image;
1501                 long                  new_length;
1502                 int                   len;
1503                 char                 *signature;
1504                 LoaderIndex           loader_index;
1505 
1506                 LOG2("cbClassFileLoadHook injecting class" , classname);
1507 
1508                 /* Define a unique class number for this class */
1509                 len              = (int)strlen(classname);
1510                 signature        = HPROF_MALLOC(len+3);
1511                 signature[0]     = JVM_SIGNATURE_CLASS;
1512                 (void)memcpy(signature+1, classname, len);
1513                 signature[len+1] = JVM_SIGNATURE_ENDCLASS;
1514                 signature[len+2] = 0;
1515                 loader_index = loader_find_or_create(env,loader);
1516                 if ( class_being_redefined != NULL ) {
1517                     cnum  = class_find_or_create(signature, loader_index);
1518                 } else {
1519                     cnum  = class_create(signature, loader_index);
1520                 }
1521                 HPROF_FREE(signature);
1522                 signature        = NULL;
1523 
1524                 /* Make sure class doesn't get unloaded by accident */
1525                 class_add_status(cnum, CLASS_IN_LOAD_LIST);
1526 
1527                 /* Is it a system class? */
1528                 system_class = 0;
1529                 if (    (!gdata->jvm_initialized)
1530                      && (!gdata->jvm_initializing)
1531                      && ( ( class_get_status(cnum) & CLASS_SYSTEM) != 0
1532                             || gdata->bci_counter < 8 ) ) {
1533                     system_class = 1;
1534                     LOG2(classname, " is a system class");
1535                 }
1536 
1537                 new_image = NULL;
1538                 new_length = 0;
1539 
1540                 /* Call the class file reader/write demo code */
1541                 ((JavaCrwDemo)(gdata->java_crw_demo_function))(
1542                     cnum,
1543                     classname,
1544                     class_data,
1545                     class_data_len,
1546                     system_class,
1547                     TRACKER_CLASS_NAME,
1548                     TRACKER_CLASS_SIG,
1549                     (gdata->cpu_timing)?TRACKER_CALL_NAME:NULL,
1550                     (gdata->cpu_timing)?TRACKER_CALL_SIG:NULL,
1551                     (gdata->cpu_timing)?TRACKER_RETURN_NAME:NULL,
1552                     (gdata->cpu_timing)?TRACKER_RETURN_SIG:NULL,
1553                     (gdata->obj_watch)?TRACKER_OBJECT_INIT_NAME:NULL,
1554                     (gdata->obj_watch)?TRACKER_OBJECT_INIT_SIG:NULL,
1555                     (gdata->obj_watch)?TRACKER_NEWARRAY_NAME:NULL,
1556                     (gdata->obj_watch)?TRACKER_NEWARRAY_SIG:NULL,
1557                     &new_image,
1558                     &new_length,
1559                     &my_crw_fatal_error_handler,
1560                     &class_set_methods);
1561 
1562                 if ( new_length > 0 ) {
1563                     unsigned char *jvmti_space;
1564 
1565                     LOG2("cbClassFileLoadHook DID inject this class", classname);
1566                     jvmti_space = (unsigned char *)jvmtiAllocate((jint)new_length);
1567                     (void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length);
1568                     *new_class_data_len = (jint)new_length;
1569                     *new_class_data     = jvmti_space; /* VM will deallocate */
1570                 } else {
1571                     LOG2("cbClassFileLoadHook DID NOT inject this class", classname);
1572                     *new_class_data_len = 0;
1573                     *new_class_data     = NULL;
1574                 }
1575                 if ( new_image != NULL ) {
1576                     (void)free((void*)new_image); /* Free malloc() space with free() */
1577                 }
1578             }
1579             (void)free((void*)classname);
1580         } rawMonitorExit(gdata->data_access_lock);
1581     } END_CALLBACK();
1582 }
1583 
1584 /* JVMTI_EVENT_CLASS_LOAD */
1585 static void JNICALL
1586 cbClassLoad(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass)
1587 {
1588 
1589     /* WARNING: This MAY be called before VM_INIT. */
1590 
1591     LOG("cbClassLoad");
1592 
1593     BEGIN_CALLBACK() {
1594         rawMonitorEnter(gdata->data_access_lock); {
1595 
1596             WITH_LOCAL_REFS(env, 1) {
1597                 jobject loader;
1598 
1599                 loader = getClassLoader(klass);
1600                 event_class_load(env, thread, klass, loader);
1601             } END_WITH_LOCAL_REFS;
1602 
1603         } rawMonitorExit(gdata->data_access_lock);
1604     } END_CALLBACK();
1605 }
1606 
1607 /* JVMTI_EVENT_CLASS_PREPARE */
1608 static void JNICALL
1609 cbClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass)
1610 {
1611 
1612     /* WARNING: This will be called before VM_INIT. */
1613 
1614     LOG("cbClassPrepare");
1615 
1616     BEGIN_CALLBACK() {
1617         rawMonitorEnter(gdata->data_access_lock); {
1618 
1619             WITH_LOCAL_REFS(env, 1) {
1620                 jobject loader;
1621 
1622                 loader = NULL;
1623                 loader = getClassLoader(klass);
1624                 event_class_prepare(env, thread, klass, loader);
1625             } END_WITH_LOCAL_REFS;
1626 
1627         } rawMonitorExit(gdata->data_access_lock);
1628     } END_CALLBACK();
1629 
1630 }
1631 
1632 /* JVMTI_EVENT_DATA_DUMP_REQUEST */
1633 static void JNICALL
1634 cbDataDumpRequest(jvmtiEnv *jvmti)
1635 {
1636     jboolean need_to_dump;
1637 
1638     LOG("cbDataDumpRequest");
1639 
1640     BEGIN_CALLBACK() {
1641         need_to_dump = JNI_FALSE;
1642         rawMonitorEnter(gdata->dump_lock); {
1643             if (!gdata->dump_in_process) {
1644                 need_to_dump    = JNI_TRUE;
1645                 gdata->dump_in_process = JNI_TRUE;
1646             }
1647         } rawMonitorExit(gdata->dump_lock);
1648 
1649         if (need_to_dump) {
1650             dump_all_data(getEnv());
1651 
1652             rawMonitorEnter(gdata->dump_lock); {
1653                 gdata->dump_in_process = JNI_FALSE;
1654             } rawMonitorExit(gdata->dump_lock);
1655 
1656             if (gdata->cpu_sampling && !gdata->jvm_shut_down) {
1657                 cpu_sample_on(NULL, 0); /* resume sampling */
1658             }
1659         }
1660     } END_CALLBACK();
1661 
1662 }
1663 
1664 /* JVMTI_EVENT_EXCEPTION_CATCH */
1665 static void JNICALL
1666 cbExceptionCatch(jvmtiEnv *jvmti, JNIEnv* env,
1667                 jthread thread, jmethodID method, jlocation location,
1668                 jobject exception)
1669 {
1670     LOG("cbExceptionCatch");
1671 
1672     BEGIN_CALLBACK() {
1673         event_exception_catch(env, thread, method, location, exception);
1674     } END_CALLBACK();
1675 }
1676 
1677 /* JVMTI_EVENT_MONITOR_WAIT */
1678 static void JNICALL
1679 cbMonitorWait(jvmtiEnv *jvmti, JNIEnv* env,
1680                 jthread thread, jobject object, jlong timeout)
1681 {
1682     LOG("cbMonitorWait");
1683 
1684     BEGIN_CALLBACK() {
1685         monitor_wait_event(env, thread, object, timeout);
1686     } END_CALLBACK();
1687 }
1688 
1689 /* JVMTI_EVENT_MONITOR_WAITED */
1690 static void JNICALL
1691 cbMonitorWaited(jvmtiEnv *jvmti, JNIEnv* env,
1692                 jthread thread, jobject object, jboolean timed_out)
1693 {
1694     LOG("cbMonitorWaited");
1695 
1696     BEGIN_CALLBACK() {
1697         monitor_waited_event(env, thread, object, timed_out);
1698     } END_CALLBACK();
1699 }
1700 
1701 /* JVMTI_EVENT_MONITOR_CONTENDED_ENTER */
1702 static void JNICALL
1703 cbMonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv* env,
1704                 jthread thread, jobject object)
1705 {
1706     LOG("cbMonitorContendedEnter");
1707 
1708     BEGIN_CALLBACK() {
1709         monitor_contended_enter_event(env, thread, object);
1710     } END_CALLBACK();
1711 }
1712 
1713 /* JVMTI_EVENT_MONITOR_CONTENDED_ENTERED */
1714 static void JNICALL
1715 cbMonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv* env,
1716                 jthread thread, jobject object)
1717 {
1718     LOG("cbMonitorContendedEntered");
1719 
1720     BEGIN_CALLBACK() {
1721         monitor_contended_entered_event(env, thread, object);
1722     } END_CALLBACK();
1723 }
1724 
1725 /* JVMTI_EVENT_GARBAGE_COLLECTION_START */
1726 static void JNICALL
1727 cbGarbageCollectionStart(jvmtiEnv *jvmti)
1728 {
1729     LOG("cbGarbageCollectionStart");
1730 
1731     /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit
1732      *   are allowed here (see the JVMTI Spec).
1733      */
1734 
1735     gdata->gc_start_time = md_get_timemillis();
1736 }
1737 
1738 /* JVMTI_EVENT_GARBAGE_COLLECTION_FINISH */
1739 static void JNICALL
1740 cbGarbageCollectionFinish(jvmtiEnv *jvmti)
1741 {
1742     LOG("cbGarbageCollectionFinish");
1743 
1744     /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit
1745      *   are allowed here (see the JVMTI Spec).
1746      */
1747 
1748     if ( gdata->gc_start_time != -1L ) {
1749         gdata->time_in_gc += (md_get_timemillis() - gdata->gc_start_time);
1750         gdata->gc_start_time = -1L;
1751     }
1752 
1753     /* Increment gc_finish counter, notify watcher thread */
1754     rawMonitorEnter(gdata->gc_finish_lock); {
1755         /* If VM_DEATH is trying to shut it down, don't do anything at all.
1756          *    Never send notify if VM_DEATH wants the watcher thread to quit.
1757          */
1758         if ( gdata->gc_finish_active ) {
1759             gdata->gc_finish++;
1760             rawMonitorNotifyAll(gdata->gc_finish_lock);
1761         }
1762     } rawMonitorExit(gdata->gc_finish_lock);
1763 }
1764 
1765 /* JVMTI_EVENT_OBJECT_FREE */
1766 static void JNICALL
1767 cbObjectFree(jvmtiEnv *jvmti, jlong tag)
1768 {
1769     LOG3("cbObjectFree", "tag", (int)tag);
1770 
1771     /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit
1772      *   are allowed here (see the JVMTI Spec).
1773      */
1774 
1775     HPROF_ASSERT(tag!=(jlong)0);
1776     rawMonitorEnter(gdata->object_free_lock); {
1777         if ( !gdata->jvm_shut_down ) {
1778             Stack *stack;
1779 
1780             stack = gdata->object_free_stack;
1781             if ( stack == NULL ) {
1782                 gdata->object_free_stack = stack_init(512, 512, sizeof(jlong));
1783                 stack = gdata->object_free_stack;
1784             }
1785             stack_push(stack, (void*)&tag);
1786         }
1787     } rawMonitorExit(gdata->object_free_lock);
1788 }
1789 
1790 static void
1791 set_callbacks(jboolean on)
1792 {
1793     jvmtiEventCallbacks callbacks;
1794 
1795     (void)memset(&callbacks,0,sizeof(callbacks));
1796     if ( ! on ) {
1797         setEventCallbacks(&callbacks);
1798         return;
1799     }
1800 
1801     /* JVMTI_EVENT_VM_INIT */
1802     callbacks.VMInit                     = &cbVMInit;
1803     /* JVMTI_EVENT_VM_DEATH */
1804     callbacks.VMDeath                    = &cbVMDeath;
1805     /* JVMTI_EVENT_THREAD_START */
1806     callbacks.ThreadStart                = &cbThreadStart;
1807     /* JVMTI_EVENT_THREAD_END */
1808     callbacks.ThreadEnd                  = &cbThreadEnd;
1809     /* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */
1810     callbacks.ClassFileLoadHook          = &cbClassFileLoadHook;
1811     /* JVMTI_EVENT_CLASS_LOAD */
1812     callbacks.ClassLoad                  = &cbClassLoad;
1813     /* JVMTI_EVENT_CLASS_PREPARE */
1814     callbacks.ClassPrepare               = &cbClassPrepare;
1815     /* JVMTI_EVENT_DATA_DUMP_REQUEST */
1816     callbacks.DataDumpRequest            = &cbDataDumpRequest;
1817     /* JVMTI_EVENT_EXCEPTION_CATCH */
1818     callbacks.ExceptionCatch             = &cbExceptionCatch;
1819     /* JVMTI_EVENT_MONITOR_WAIT */
1820     callbacks.MonitorWait                = &cbMonitorWait;
1821     /* JVMTI_EVENT_MONITOR_WAITED */
1822     callbacks.MonitorWaited              = &cbMonitorWaited;
1823     /* JVMTI_EVENT_MONITOR_CONTENDED_ENTER */
1824     callbacks.MonitorContendedEnter      = &cbMonitorContendedEnter;
1825     /* JVMTI_EVENT_MONITOR_CONTENDED_ENTERED */
1826     callbacks.MonitorContendedEntered    = &cbMonitorContendedEntered;
1827     /* JVMTI_EVENT_GARBAGE_COLLECTION_START */
1828     callbacks.GarbageCollectionStart     = &cbGarbageCollectionStart;
1829     /* JVMTI_EVENT_GARBAGE_COLLECTION_FINISH */
1830     callbacks.GarbageCollectionFinish    = &cbGarbageCollectionFinish;
1831     /* JVMTI_EVENT_OBJECT_FREE */
1832     callbacks.ObjectFree                 = &cbObjectFree;
1833 
1834     setEventCallbacks(&callbacks);
1835 
1836 }
1837 
1838 static void
1839 getCapabilities(void)
1840 {
1841     jvmtiCapabilities needed_capabilities;
1842     jvmtiCapabilities potential_capabilities;
1843 
1844     /* Fill in ones that we must have */
1845     (void)memset(&needed_capabilities,0,sizeof(needed_capabilities));
1846     needed_capabilities.can_generate_garbage_collection_events   = 1;
1847     needed_capabilities.can_tag_objects                          = 1;
1848     if (gdata->bci) {
1849         needed_capabilities.can_generate_all_class_hook_events   = 1;
1850     }
1851     if (gdata->obj_watch) {
1852         needed_capabilities.can_generate_object_free_events      = 1;
1853     }
1854     if (gdata->cpu_timing || gdata->cpu_sampling) {
1855         #if 0 /* Not needed until we call JVMTI for CpuTime */
1856         needed_capabilities.can_get_thread_cpu_time              = 1;
1857         needed_capabilities.can_get_current_thread_cpu_time      = 1;
1858         #endif
1859         needed_capabilities.can_generate_exception_events        = 1;
1860     }
1861     if (gdata->monitor_tracing) {
1862         #if 0 /* Not needed until we call JVMTI for CpuTime */
1863         needed_capabilities.can_get_thread_cpu_time              = 1;
1864         needed_capabilities.can_get_current_thread_cpu_time      = 1;
1865         #endif
1866         needed_capabilities.can_get_owned_monitor_info           = 1;
1867         needed_capabilities.can_get_current_contended_monitor    = 1;
1868         needed_capabilities.can_get_monitor_info                 = 1;
1869         needed_capabilities.can_generate_monitor_events          = 1;
1870     }
1871 
1872     /* Get potential capabilities */
1873     getPotentialCapabilities(&potential_capabilities);
1874 
1875     /* Some capabilities would be nicer to have */
1876     needed_capabilities.can_get_source_file_name        =
1877         potential_capabilities.can_get_source_file_name;
1878     needed_capabilities.can_get_line_numbers    =
1879         potential_capabilities.can_get_line_numbers;
1880 
1881     /* Add the capabilities */
1882     addCapabilities(&needed_capabilities);
1883 
1884 }
1885 
1886 /* Dynamic library loading */
1887 static void *
1888 load_library(char *name)
1889 {
1890     char  lname[FILENAME_MAX+1];
1891     char  err_buf[256+FILENAME_MAX+1];
1892     char *boot_path;
1893     void *handle;
1894 
1895     handle = NULL;
1896 
1897     /* The library may be located in different ways, try both, but
1898      *   if it comes from outside the SDK/jre it isn't ours.
1899      */
1900     getSystemProperty("sun.boot.library.path", &boot_path);
1901     md_build_library_name(lname, FILENAME_MAX, boot_path, name);
1902     if ( strlen(lname) == 0 ) {
1903         HPROF_ERROR(JNI_TRUE, "Could not find library");
1904     }
1905     jvmtiDeallocate(boot_path);
1906     handle = md_load_library(lname, err_buf, (int)sizeof(err_buf));
1907     if ( handle == NULL ) {
1908         /* This may be necessary on Windows. */
1909         md_build_library_name(lname, FILENAME_MAX, "", name);
1910         if ( strlen(lname) == 0 ) {
1911             HPROF_ERROR(JNI_TRUE, "Could not find library");
1912         }
1913         handle = md_load_library(lname, err_buf, (int)sizeof(err_buf));
1914         if ( handle == NULL ) {
1915             HPROF_ERROR(JNI_TRUE, err_buf);
1916         }
1917     }
1918     return handle;
1919 }
1920 
1921 /* Lookup dynamic function pointer in shared library */
1922 static void *
1923 lookup_library_symbol(void *library, char **symbols, int nsymbols)
1924 {
1925     void *addr;
1926     int   i;
1927 
1928     addr = NULL;
1929     for( i = 0 ; i < nsymbols; i++ ) {
1930         addr = md_find_library_entry(library, symbols[i]);
1931         if ( addr != NULL ) {
1932             break;
1933         }
1934     }
1935     if ( addr == NULL ) {
1936         char errmsg[256];
1937 
1938         (void)md_snprintf(errmsg, sizeof(errmsg),
1939                     "Cannot find library symbol '%s'", symbols[0]);
1940         HPROF_ERROR(JNI_TRUE, errmsg);
1941     }
1942     return addr;
1943 }
1944 
1945 /* ------------------------------------------------------------------- */
1946 /* The OnLoad interface */
1947 
1948 JNIEXPORT jint JNICALL
1949 Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
1950 {
1951     char *boot_path = NULL;
1952     char npt_lib[JVM_MAXPATHLEN];
1953 
1954     /* See if it's already loaded */
1955     if ( gdata!=NULL && gdata->isLoaded==JNI_TRUE ) {
1956         HPROF_ERROR(JNI_TRUE, "Cannot load this JVM TI agent twice, check your java command line for duplicate hprof options.");
1957         return JNI_ERR;
1958     }
1959 
1960     gdata = get_gdata();
1961 
1962     gdata->isLoaded = JNI_TRUE;
1963 
1964     error_setup();
1965 
1966     LOG2("Agent_OnLoad", "gdata setup");
1967 
1968     gdata->jvm = vm;
1969 
1970     /* Get the JVMTI environment */
1971     getJvmti();
1972 
1973 #ifndef SKIP_NPT
1974     getSystemProperty("sun.boot.library.path", &boot_path);
1975     /* Load in NPT library for character conversions */
1976     md_build_library_name(npt_lib, sizeof(npt_lib), boot_path, NPT_LIBNAME);
1977     if ( strlen(npt_lib) == 0 ) {
1978         HPROF_ERROR(JNI_TRUE, "Could not find npt library");
1979     }
1980     jvmtiDeallocate(boot_path);
1981     NPT_INITIALIZE(npt_lib, &(gdata->npt), NPT_VERSION, NULL);
1982     if ( gdata->npt == NULL ) {
1983         HPROF_ERROR(JNI_TRUE, "Cannot load npt library");
1984     }
1985     gdata->npt->utf = (gdata->npt->utfInitialize)(NULL);
1986     if ( gdata->npt->utf == NULL ) {
1987         HPROF_ERROR(JNI_TRUE, "Cannot initialize npt utf functions");
1988     }
1989 #endif
1990 
1991     /* Lock needed to protect debug_malloc() code, which is not MT safe */
1992     #ifdef DEBUG
1993         gdata->debug_malloc_lock = createRawMonitor("HPROF debug_malloc lock");
1994     #endif
1995 
1996     parse_options(options);
1997 
1998     LOG2("Agent_OnLoad", "Has jvmtiEnv and options parsed");
1999 
2000     /* Initialize machine dependent code (micro state accounting) */
2001     md_init();
2002 
2003     string_init();      /* Table index values look like: 0x10000000 */
2004 
2005     class_init();       /* Table index values look like: 0x20000000 */
2006     tls_init();         /* Table index values look like: 0x30000000 */
2007     trace_init();       /* Table index values look like: 0x40000000 */
2008     object_init();      /* Table index values look like: 0x50000000 */
2009 
2010     site_init();        /* Table index values look like: 0x60000000 */
2011     frame_init();       /* Table index values look like: 0x70000000 */
2012     monitor_init();     /* Table index values look like: 0x80000000 */
2013     loader_init();      /* Table index values look like: 0x90000000 */
2014 
2015     LOG2("Agent_OnLoad", "Tables initialized");
2016 
2017     if ( gdata->pause ) {
2018         error_do_pause();
2019     }
2020 
2021     getCapabilities();
2022 
2023     /* Set the JVMTI callback functions  (do this only once)*/
2024     set_callbacks(JNI_TRUE);
2025 
2026     /* Create basic locks */
2027     gdata->dump_lock          = createRawMonitor("HPROF dump lock");
2028     gdata->data_access_lock   = createRawMonitor("HPROF data access lock");
2029     gdata->callbackLock       = createRawMonitor("HPROF callback lock");
2030     gdata->callbackBlock      = createRawMonitor("HPROF callback block");
2031     gdata->object_free_lock   = createRawMonitor("HPROF object free lock");
2032     gdata->gc_finish_lock     = createRawMonitor("HPROF gc_finish lock");
2033 
2034     /* Set Onload events mode. */
2035     setup_event_mode(JNI_TRUE, JVMTI_ENABLE);
2036 
2037     LOG2("Agent_OnLoad", "JVMTI capabilities, callbacks and initial notifications setup");
2038 
2039     /* Used in VM_DEATH to wait for callbacks to complete */
2040     gdata->jvm_initializing             = JNI_FALSE;
2041     gdata->jvm_initialized              = JNI_FALSE;
2042     gdata->vm_death_callback_active     = JNI_FALSE;
2043     gdata->active_callbacks             = 0;
2044 
2045     /* Write the header information */
2046     io_setup();
2047 
2048     /* We sample the start time now so that the time increments can be
2049      *    placed in the various heap dump segments in micro seconds.
2050      */
2051     gdata->micro_sec_ticks = md_get_microsecs();
2052 
2053     /* Load java_crw_demo library and find function "java_crw_demo" */
2054     if ( gdata->bci ) {
2055 
2056         /* Load the library or get the handle to it */
2057         gdata->java_crw_demo_library = load_library("java_crw_demo");
2058 
2059         { /* "java_crw_demo" */
2060             static char *symbols[]  = JAVA_CRW_DEMO_SYMBOLS;
2061             gdata->java_crw_demo_function =
2062                    lookup_library_symbol(gdata->java_crw_demo_library,
2063                               symbols, (int)(sizeof(symbols)/sizeof(char*)));
2064         }
2065         { /* "java_crw_demo_classname" */
2066             static char *symbols[] = JAVA_CRW_DEMO_CLASSNAME_SYMBOLS;
2067             gdata->java_crw_demo_classname_function =
2068                    lookup_library_symbol(gdata->java_crw_demo_library,
2069                               symbols, (int)(sizeof(symbols)/sizeof(char*)));
2070         }
2071     }
2072 
2073     return JNI_OK;
2074 }
2075 
2076 JNIEXPORT void JNICALL
2077 Agent_OnUnload(JavaVM *vm)
2078 {
2079     Stack *stack;
2080 
2081     LOG("Agent_OnUnload");
2082 
2083     gdata->isLoaded = JNI_FALSE;
2084 
2085     stack = gdata->object_free_stack;
2086     gdata->object_free_stack = NULL;
2087     if ( stack != NULL ) {
2088         stack_term(stack);
2089     }
2090 
2091     io_cleanup();
2092     loader_cleanup();
2093     tls_cleanup();
2094     monitor_cleanup();
2095     trace_cleanup();
2096     site_cleanup();
2097     object_cleanup();
2098     frame_cleanup();
2099     class_cleanup();
2100     string_cleanup();
2101 
2102     /* Deallocate any memory in gdata */
2103     if ( gdata->net_hostname != NULL ) {
2104         HPROF_FREE(gdata->net_hostname);
2105     }
2106     if ( gdata->utf8_output_filename != NULL ) {
2107         HPROF_FREE(gdata->utf8_output_filename);
2108     }
2109     if ( gdata->output_filename != NULL ) {
2110         HPROF_FREE(gdata->output_filename);
2111     }
2112     if ( gdata->heapfilename != NULL ) {
2113         HPROF_FREE(gdata->heapfilename);
2114     }
2115     if ( gdata->checkfilename != NULL ) {
2116         HPROF_FREE(gdata->checkfilename);
2117     }
2118     if ( gdata->options != NULL ) {
2119         HPROF_FREE(gdata->options);
2120     }
2121 
2122     /* Verify all allocated memory has been taken care of. */
2123     malloc_police();
2124 
2125     /* Cleanup is hard to do when other threads might still be running
2126      *  so we skip destroying some raw monitors which still might be in use
2127      *  and we skip disposal of the jvmtiEnv* which might still be needed.
2128      *  Only raw monitors that could be held by other threads are left
2129      *  alone. So we explicitly do NOT do this:
2130      *      destroyRawMonitor(gdata->callbackLock);
2131      *      destroyRawMonitor(gdata->callbackBlock);
2132      *      destroyRawMonitor(gdata->gc_finish_lock);
2133      *      destroyRawMonitor(gdata->object_free_lock);
2134      *      destroyRawMonitor(gdata->listener_loop_lock);
2135      *      destroyRawMonitor(gdata->cpu_loop_lock);
2136      *      disposeEnvironment();
2137      *      gdata->jvmti = NULL;
2138      */
2139 
2140     /* Destroy basic locks */
2141     destroyRawMonitor(gdata->dump_lock);
2142     gdata->dump_lock = NULL;
2143     destroyRawMonitor(gdata->data_access_lock);
2144     gdata->data_access_lock = NULL;
2145     if ( gdata->cpu_sample_lock != NULL ) {
2146         destroyRawMonitor(gdata->cpu_sample_lock);
2147         gdata->cpu_sample_lock = NULL;
2148     }
2149     #ifdef DEBUG
2150         destroyRawMonitor(gdata->debug_malloc_lock);
2151         gdata->debug_malloc_lock = NULL;
2152     #endif
2153 
2154     /* Unload java_crw_demo library */
2155     if ( gdata->bci && gdata->java_crw_demo_library != NULL ) {
2156         md_unload_library(gdata->java_crw_demo_library);
2157         gdata->java_crw_demo_library = NULL;
2158     }
2159 
2160     /* You would think you could clear out gdata and set it to NULL, but
2161      *   turns out that isn't a good idea.  Some of the threads could be
2162      *   blocked inside the CALLBACK*() macros, where they got blocked up
2163      *   waiting for the VM_DEATH callback to complete. They only have
2164      *   some raw monitor actions to do, but they need access to gdata to do it.
2165      *   So do not do this:
2166      *       (void)memset(gdata, 0, sizeof(GlobalData));
2167      *       gdata = NULL;
2168      */
2169 }