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