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