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