Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/jvmti/mtrace/mtrace.c
38829 views
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
835