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 jvmtiDeallocate(boot_path); 1903 handle = md_load_library(lname, err_buf, (int)sizeof(err_buf)); 1904 if ( handle == NULL ) { 1905 /* This may be necessary on Windows. */ 1906 md_build_library_name(lname, FILENAME_MAX, "", name); 1907 handle = md_load_library(lname, err_buf, (int)sizeof(err_buf)); 1908 if ( handle == NULL ) { 1909 HPROF_ERROR(JNI_TRUE, err_buf); 1910 } 1911 } 1912 return handle; 1913 } 1914 1915 /* Lookup dynamic function pointer in shared library */ 1916 static void * 1917 lookup_library_symbol(void *library, char **symbols, int nsymbols) 1918 { 1919 void *addr; 1920 int i; 1921 1922 addr = NULL; 1923 for( i = 0 ; i < nsymbols; i++ ) { 1924 addr = md_find_library_entry(library, symbols[i]); 1925 if ( addr != NULL ) { 1926 break; 1927 } 1928 } 1929 if ( addr == NULL ) { 1930 char errmsg[256]; 1931 1932 (void)md_snprintf(errmsg, sizeof(errmsg), 1933 "Cannot find library symbol '%s'", symbols[0]); 1934 HPROF_ERROR(JNI_TRUE, errmsg); 1935 } 1936 return addr; 1937 } 1938 1939 /* ------------------------------------------------------------------- */ 1940 /* The OnLoad interface */ 1941 1942 JNIEXPORT jint JNICALL 1943 Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 1944 { 1945 char *boot_path = NULL; 1946 char npt_lib[JVM_MAXPATHLEN]; 1947 1948 /* See if it's already loaded */ 1949 if ( gdata!=NULL && gdata->isLoaded==JNI_TRUE ) { 1950 HPROF_ERROR(JNI_TRUE, "Cannot load this JVM TI agent twice, check your java command line for duplicate hprof options."); 1951 return JNI_ERR; 1952 } 1953 1954 gdata = get_gdata(); 1955 1956 gdata->isLoaded = JNI_TRUE; 1957 1958 error_setup(); 1959 1960 LOG2("Agent_OnLoad", "gdata setup"); 1961 1962 gdata->jvm = vm; 1963 1964 /* Get the JVMTI environment */ 1965 getJvmti(); 1966 1967 #ifndef SKIP_NPT 1968 getSystemProperty("sun.boot.library.path", &boot_path); 1969 /* Load in NPT library for character conversions */ 1970 md_build_library_name(npt_lib, sizeof(npt_lib), boot_path, NPT_LIBNAME); 1971 jvmtiDeallocate(boot_path); 1972 NPT_INITIALIZE(npt_lib, &(gdata->npt), NPT_VERSION, NULL); 1973 if ( gdata->npt == NULL ) { 1974 HPROF_ERROR(JNI_TRUE, "Cannot load npt library"); 1975 } 1976 gdata->npt->utf = (gdata->npt->utfInitialize)(NULL); 1977 if ( gdata->npt->utf == NULL ) { 1978 HPROF_ERROR(JNI_TRUE, "Cannot initialize npt utf functions"); 1979 } 1980 #endif 1981 1982 /* Lock needed to protect debug_malloc() code, which is not MT safe */ 1983 #ifdef DEBUG 1984 gdata->debug_malloc_lock = createRawMonitor("HPROF debug_malloc lock"); 1985 #endif 1986 1987 parse_options(options); 1988 1989 LOG2("Agent_OnLoad", "Has jvmtiEnv and options parsed"); 1990 1991 /* Initialize machine dependent code (micro state accounting) */ 1992 md_init(); 1993 1994 string_init(); /* Table index values look like: 0x10000000 */ 1995 1996 class_init(); /* Table index values look like: 0x20000000 */ 1997 tls_init(); /* Table index values look like: 0x30000000 */ 1998 trace_init(); /* Table index values look like: 0x40000000 */ 1999 object_init(); /* Table index values look like: 0x50000000 */ 2000 2001 site_init(); /* Table index values look like: 0x60000000 */ 2002 frame_init(); /* Table index values look like: 0x70000000 */ 2003 monitor_init(); /* Table index values look like: 0x80000000 */ 2004 loader_init(); /* Table index values look like: 0x90000000 */ 2005 2006 LOG2("Agent_OnLoad", "Tables initialized"); 2007 2008 if ( gdata->pause ) { 2009 error_do_pause(); 2010 } 2011 2012 getCapabilities(); 2013 2014 /* Set the JVMTI callback functions (do this only once)*/ 2015 set_callbacks(JNI_TRUE); 2016 2017 /* Create basic locks */ 2018 gdata->dump_lock = createRawMonitor("HPROF dump lock"); 2019 gdata->data_access_lock = createRawMonitor("HPROF data access lock"); 2020 gdata->callbackLock = createRawMonitor("HPROF callback lock"); 2021 gdata->callbackBlock = createRawMonitor("HPROF callback block"); 2022 gdata->object_free_lock = createRawMonitor("HPROF object free lock"); 2023 gdata->gc_finish_lock = createRawMonitor("HPROF gc_finish lock"); 2024 2025 /* Set Onload events mode. */ 2026 setup_event_mode(JNI_TRUE, JVMTI_ENABLE); 2027 2028 LOG2("Agent_OnLoad", "JVMTI capabilities, callbacks and initial notifications setup"); 2029 2030 /* Used in VM_DEATH to wait for callbacks to complete */ 2031 gdata->jvm_initializing = JNI_FALSE; 2032 gdata->jvm_initialized = JNI_FALSE; 2033 gdata->vm_death_callback_active = JNI_FALSE; 2034 gdata->active_callbacks = 0; 2035 2036 /* Write the header information */ 2037 io_setup(); 2038 2039 /* We sample the start time now so that the time increments can be 2040 * placed in the various heap dump segments in micro seconds. 2041 */ 2042 gdata->micro_sec_ticks = md_get_microsecs(); 2043 2044 /* Load java_crw_demo library and find function "java_crw_demo" */ 2045 if ( gdata->bci ) { 2046 2047 /* Load the library or get the handle to it */ 2048 gdata->java_crw_demo_library = load_library("java_crw_demo"); 2049 2050 { /* "java_crw_demo" */ 2051 static char *symbols[] = JAVA_CRW_DEMO_SYMBOLS; 2052 gdata->java_crw_demo_function = 2053 lookup_library_symbol(gdata->java_crw_demo_library, 2054 symbols, (int)(sizeof(symbols)/sizeof(char*))); 2055 } 2056 { /* "java_crw_demo_classname" */ 2057 static char *symbols[] = JAVA_CRW_DEMO_CLASSNAME_SYMBOLS; 2058 gdata->java_crw_demo_classname_function = 2059 lookup_library_symbol(gdata->java_crw_demo_library, 2060 symbols, (int)(sizeof(symbols)/sizeof(char*))); 2061 } 2062 } 2063 2064 return JNI_OK; 2065 } 2066 2067 JNIEXPORT void JNICALL 2068 Agent_OnUnload(JavaVM *vm) 2069 { 2070 Stack *stack; 2071 2072 LOG("Agent_OnUnload"); 2073 2074 gdata->isLoaded = JNI_FALSE; 2075 2076 stack = gdata->object_free_stack; 2077 gdata->object_free_stack = NULL; 2078 if ( stack != NULL ) { 2079 stack_term(stack); 2080 } 2081 2082 io_cleanup(); 2083 loader_cleanup(); 2084 tls_cleanup(); 2085 monitor_cleanup(); 2086 trace_cleanup(); 2087 site_cleanup(); 2088 object_cleanup(); 2089 frame_cleanup(); 2090 class_cleanup(); 2091 string_cleanup(); 2092 2093 /* Deallocate any memory in gdata */ 2094 if ( gdata->net_hostname != NULL ) { 2095 HPROF_FREE(gdata->net_hostname); 2096 } 2097 if ( gdata->utf8_output_filename != NULL ) { 2098 HPROF_FREE(gdata->utf8_output_filename); 2099 } 2100 if ( gdata->output_filename != NULL ) { 2101 HPROF_FREE(gdata->output_filename); 2102 } 2103 if ( gdata->heapfilename != NULL ) { 2104 HPROF_FREE(gdata->heapfilename); 2105 } 2106 if ( gdata->checkfilename != NULL ) { 2107 HPROF_FREE(gdata->checkfilename); 2108 } 2109 if ( gdata->options != NULL ) { 2110 HPROF_FREE(gdata->options); 2111 } 2112 2113 /* Verify all allocated memory has been taken care of. */ 2114 malloc_police(); 2115 2116 /* Cleanup is hard to do when other threads might still be running 2117 * so we skip destroying some raw monitors which still might be in use 2118 * and we skip disposal of the jvmtiEnv* which might still be needed. 2119 * Only raw monitors that could be held by other threads are left 2120 * alone. So we explicitly do NOT do this: 2121 * destroyRawMonitor(gdata->callbackLock); 2122 * destroyRawMonitor(gdata->callbackBlock); 2123 * destroyRawMonitor(gdata->gc_finish_lock); 2124 * destroyRawMonitor(gdata->object_free_lock); 2125 * destroyRawMonitor(gdata->listener_loop_lock); 2126 * destroyRawMonitor(gdata->cpu_loop_lock); 2127 * disposeEnvironment(); 2128 * gdata->jvmti = NULL; 2129 */ 2130 2131 /* Destroy basic locks */ 2132 destroyRawMonitor(gdata->dump_lock); 2133 gdata->dump_lock = NULL; 2134 destroyRawMonitor(gdata->data_access_lock); 2135 gdata->data_access_lock = NULL; 2136 if ( gdata->cpu_sample_lock != NULL ) { 2137 destroyRawMonitor(gdata->cpu_sample_lock); 2138 gdata->cpu_sample_lock = NULL; 2139 } 2140 #ifdef DEBUG 2141 destroyRawMonitor(gdata->debug_malloc_lock); 2142 gdata->debug_malloc_lock = NULL; 2143 #endif 2144 2145 /* Unload java_crw_demo library */ 2146 if ( gdata->bci && gdata->java_crw_demo_library != NULL ) { 2147 md_unload_library(gdata->java_crw_demo_library); 2148 gdata->java_crw_demo_library = NULL; 2149 } 2150 2151 /* You would think you could clear out gdata and set it to NULL, but 2152 * turns out that isn't a good idea. Some of the threads could be 2153 * blocked inside the CALLBACK*() macros, where they got blocked up 2154 * waiting for the VM_DEATH callback to complete. They only have 2155 * some raw monitor actions to do, but they need access to gdata to do it. 2156 * So do not do this: 2157 * (void)memset(gdata, 0, sizeof(GlobalData)); 2158 * gdata = NULL; 2159 */ 2160 }