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/minst/minst.c
38829 views
1
/*
2
* Copyright (c) 2006, 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 "minst.h"
44
#include "java_crw_demo.h"
45
46
47
/* ------------------------------------------------------------------- */
48
/* Some constant maximum sizes */
49
50
#define MAX_TOKEN_LENGTH 80
51
#define MAX_METHOD_NAME_LENGTH 256
52
53
/* Some constant names that tie to Java class/method names.
54
* We assume the Java class whose static methods we will be calling
55
* looks like:
56
*
57
* public class Minst {
58
* private static int engaged;
59
* private static native void _method_entry(Object thr, int cnum, int mnum);
60
* public static void method_entry(int cnum, int mnum)
61
* {
62
* ...
63
* }
64
* }
65
*
66
*/
67
68
#define MINST_class Minst /* Name of class we are using */
69
#define MINST_entry method_entry /* Name of java entry method */
70
#define MINST_engaged engaged /* Name of java static field */
71
72
/* C macros to create strings from tokens */
73
#define _STRING(s) #s
74
#define STRING(s) _STRING(s)
75
76
/* ------------------------------------------------------------------- */
77
78
/* Global agent data structure */
79
80
typedef struct {
81
/* JVMTI Environment */
82
jvmtiEnv *jvmti;
83
jboolean vm_is_dead;
84
jboolean vm_is_started;
85
/* Data access Lock */
86
jrawMonitorID lock;
87
/* Options */
88
char *include;
89
char *exclude;
90
/* Class Count/ID */
91
jint ccount;
92
} GlobalAgentData;
93
94
static GlobalAgentData *gdata;
95
96
/* Enter a critical section by doing a JVMTI Raw Monitor Enter */
97
static void
98
enter_critical_section(jvmtiEnv *jvmti)
99
{
100
jvmtiError error;
101
102
error = (*jvmti)->RawMonitorEnter(jvmti, gdata->lock);
103
check_jvmti_error(jvmti, error, "Cannot enter with raw monitor");
104
}
105
106
/* Exit a critical section by doing a JVMTI Raw Monitor Exit */
107
static void
108
exit_critical_section(jvmtiEnv *jvmti)
109
{
110
jvmtiError error;
111
112
error = (*jvmti)->RawMonitorExit(jvmti, gdata->lock);
113
check_jvmti_error(jvmti, error, "Cannot exit with raw monitor");
114
}
115
116
/* Callback for JVMTI_EVENT_VM_START */
117
static void JNICALL
118
cbVMStart(jvmtiEnv *jvmti, JNIEnv *env)
119
{
120
enter_critical_section(jvmti); {
121
/* Indicate VM has started */
122
gdata->vm_is_started = JNI_TRUE;
123
} exit_critical_section(jvmti);
124
}
125
126
/* Callback for JVMTI_EVENT_VM_INIT */
127
static void JNICALL
128
cbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
129
{
130
enter_critical_section(jvmti); {
131
jclass klass;
132
jfieldID field;
133
134
/* Register Natives for class whose methods we use */
135
klass = (*env)->FindClass(env, STRING(MINST_class));
136
if ( klass == NULL ) {
137
fatal_error("ERROR: JNI: Cannot find %s with FindClass\n",
138
STRING(MINST_class));
139
}
140
141
/* Engage calls. */
142
field = (*env)->GetStaticFieldID(env, klass, STRING(MINST_engaged), "I");
143
if ( field == NULL ) {
144
fatal_error("ERROR: JNI: Cannot get field from %s\n",
145
STRING(MINST_class));
146
}
147
(*env)->SetStaticIntField(env, klass, field, 1);
148
} exit_critical_section(jvmti);
149
}
150
151
/* Callback for JVMTI_EVENT_VM_DEATH */
152
static void JNICALL
153
cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env)
154
{
155
enter_critical_section(jvmti); {
156
jclass klass;
157
jfieldID field;
158
159
/* The VM has died. */
160
stdout_message("VMDeath\n");
161
162
/* Disengage calls in MINST_class. */
163
klass = (*env)->FindClass(env, STRING(MINST_class));
164
if ( klass == NULL ) {
165
fatal_error("ERROR: JNI: Cannot find %s with FindClass\n",
166
STRING(MINST_class));
167
}
168
field = (*env)->GetStaticFieldID(env, klass, STRING(MINST_engaged), "I");
169
if ( field == NULL ) {
170
fatal_error("ERROR: JNI: Cannot get field from %s\n",
171
STRING(MINST_class));
172
}
173
(*env)->SetStaticIntField(env, klass, field, -1);
174
175
/* The critical section here is important to hold back the VM death
176
* until all other callbacks have completed.
177
*/
178
179
/* Since this critical section could be holding up other threads
180
* in other event callbacks, we need to indicate that the VM is
181
* dead so that the other callbacks can short circuit their work.
182
* We don't expect any further events after VmDeath but we do need
183
* to be careful that existing threads might be in our own agent
184
* callback code.
185
*/
186
gdata->vm_is_dead = JNI_TRUE;
187
188
} exit_critical_section(jvmti);
189
190
}
191
192
/* Callback for JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */
193
static void JNICALL
194
cbClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv* env,
195
jclass class_being_redefined, jobject loader,
196
const char* name, jobject protection_domain,
197
jint class_data_len, const unsigned char* class_data,
198
jint* new_class_data_len, unsigned char** new_class_data)
199
{
200
enter_critical_section(jvmti); {
201
/* It's possible we get here right after VmDeath event, be careful */
202
if ( !gdata->vm_is_dead ) {
203
204
const char *classname;
205
206
/* Name could be NULL */
207
if ( name == NULL ) {
208
classname = java_crw_demo_classname(class_data, class_data_len,
209
NULL);
210
if ( classname == NULL ) {
211
fatal_error("ERROR: No classname inside classfile\n");
212
}
213
} else {
214
classname = strdup(name);
215
if ( classname == NULL ) {
216
fatal_error("ERROR: Out of malloc memory\n");
217
}
218
}
219
220
*new_class_data_len = 0;
221
*new_class_data = NULL;
222
223
/* The tracker class itself? */
224
if ( interested((char*)classname, "", gdata->include, gdata->exclude)
225
&& strcmp(classname, STRING(MINST_class)) != 0 ) {
226
jint cnum;
227
int system_class;
228
unsigned char *new_image;
229
long new_length;
230
231
/* Get unique number for every class file image loaded */
232
cnum = gdata->ccount++;
233
234
/* Is it a system class? If the class load is before VmStart
235
* then we will consider it a system class that should
236
* be treated carefully. (See java_crw_demo)
237
*/
238
system_class = 0;
239
if ( !gdata->vm_is_started ) {
240
system_class = 1;
241
}
242
243
new_image = NULL;
244
new_length = 0;
245
246
/* Call the class file reader/write demo code */
247
java_crw_demo(cnum,
248
classname,
249
class_data,
250
class_data_len,
251
system_class,
252
STRING(MINST_class), "L" STRING(MINST_class) ";",
253
STRING(MINST_entry), "(II)V",
254
NULL, NULL,
255
NULL, NULL,
256
NULL, NULL,
257
&new_image,
258
&new_length,
259
NULL,
260
NULL);
261
262
/* If we got back a new class image, return it back as "the"
263
* new class image. This must be JVMTI Allocate space.
264
*/
265
if ( new_length > 0 ) {
266
unsigned char *jvmti_space;
267
268
jvmti_space = (unsigned char *)allocate(jvmti, (jint)new_length);
269
(void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length);
270
*new_class_data_len = (jint)new_length;
271
*new_class_data = jvmti_space; /* VM will deallocate */
272
}
273
274
/* Always free up the space we get from java_crw_demo() */
275
if ( new_image != NULL ) {
276
(void)free((void*)new_image); /* Free malloc() space with free() */
277
}
278
}
279
(void)free((void*)classname);
280
}
281
} exit_critical_section(jvmti);
282
}
283
284
/* Parse the options for this minst agent */
285
static void
286
parse_agent_options(char *options)
287
{
288
char token[MAX_TOKEN_LENGTH];
289
char *next;
290
291
/* Parse options and set flags in gdata */
292
if ( options==NULL ) {
293
return;
294
}
295
296
/* Get the first token from the options string. */
297
next = get_token(options, ",=", token, sizeof(token));
298
299
/* While not at the end of the options string, process this option. */
300
while ( next != NULL ) {
301
if ( strcmp(token,"help")==0 ) {
302
stdout_message("The minst JVMTI demo agent\n");
303
stdout_message("\n");
304
stdout_message(" java -agent:minst[=options] ...\n");
305
stdout_message("\n");
306
stdout_message("The options are comma separated:\n");
307
stdout_message("\t help\t\t\t Print help information\n");
308
stdout_message("\t include=item\t\t Only these classes/methods\n");
309
stdout_message("\t exclude=item\t\t Exclude these classes/methods\n");
310
stdout_message("\n");
311
stdout_message("item\t Qualified class and/or method names\n");
312
stdout_message("\t\t e.g. (*.<init>;Foobar.method;sun.*)\n");
313
stdout_message("\n");
314
exit(0);
315
} else if ( strcmp(token,"include")==0 ) {
316
int used;
317
int maxlen;
318
319
maxlen = MAX_METHOD_NAME_LENGTH;
320
if ( gdata->include == NULL ) {
321
gdata->include = (char*)calloc(maxlen+1, 1);
322
used = 0;
323
} else {
324
used = (int)strlen(gdata->include);
325
gdata->include[used++] = ',';
326
gdata->include[used] = 0;
327
gdata->include = (char*)
328
realloc((void*)gdata->include, used+maxlen+1);
329
}
330
if ( gdata->include == NULL ) {
331
fatal_error("ERROR: Out of malloc memory\n");
332
}
333
/* Add this item to the list */
334
next = get_token(next, ",=", gdata->include+used, maxlen);
335
/* Check for token scan error */
336
if ( next==NULL ) {
337
fatal_error("ERROR: include option error\n");
338
}
339
} else if ( strcmp(token,"exclude")==0 ) {
340
int used;
341
int maxlen;
342
343
maxlen = MAX_METHOD_NAME_LENGTH;
344
if ( gdata->exclude == NULL ) {
345
gdata->exclude = (char*)calloc(maxlen+1, 1);
346
used = 0;
347
} else {
348
used = (int)strlen(gdata->exclude);
349
gdata->exclude[used++] = ',';
350
gdata->exclude[used] = 0;
351
gdata->exclude = (char*)
352
realloc((void*)gdata->exclude, used+maxlen+1);
353
}
354
if ( gdata->exclude == NULL ) {
355
fatal_error("ERROR: Out of malloc memory\n");
356
}
357
/* Add this item to the list */
358
next = get_token(next, ",=", gdata->exclude+used, maxlen);
359
/* Check for token scan error */
360
if ( next==NULL ) {
361
fatal_error("ERROR: exclude option error\n");
362
}
363
} else if ( token[0]!=0 ) {
364
/* We got a non-empty token and we don't know what it is. */
365
fatal_error("ERROR: Unknown option: %s\n", token);
366
}
367
/* Get the next token (returns NULL if there are no more) */
368
next = get_token(next, ",=", token, sizeof(token));
369
}
370
}
371
372
/* Agent_OnLoad: This is called immediately after the shared library is
373
* loaded. This is the first code executed.
374
*/
375
JNIEXPORT jint JNICALL
376
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
377
{
378
static GlobalAgentData data;
379
jvmtiEnv *jvmti;
380
jvmtiError error;
381
jint res;
382
jvmtiCapabilities capabilities;
383
jvmtiEventCallbacks callbacks;
384
385
/* Setup initial global agent data area
386
* Use of static/extern data should be handled carefully here.
387
* We need to make sure that we are able to cleanup after ourselves
388
* so anything allocated in this library needs to be freed in
389
* the Agent_OnUnload() function.
390
*/
391
(void)memset((void*)&data, 0, sizeof(data));
392
gdata = &data;
393
394
/* First thing we need to do is get the jvmtiEnv* or JVMTI environment */
395
res = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1);
396
if (res != JNI_OK) {
397
/* This means that the VM was unable to obtain this version of the
398
* JVMTI interface, this is a fatal error.
399
*/
400
fatal_error("ERROR: Unable to access JVMTI Version 1 (0x%x),"
401
" is your JDK a 5.0 or newer version?"
402
" JNIEnv's GetEnv() returned %d\n",
403
JVMTI_VERSION_1, res);
404
}
405
406
/* Here we save the jvmtiEnv* for Agent_OnUnload(). */
407
gdata->jvmti = jvmti;
408
409
/* Parse any options supplied on java command line */
410
parse_agent_options(options);
411
412
/* Immediately after getting the jvmtiEnv* we need to ask for the
413
* capabilities this agent will need. In this case we need to make
414
* sure that we can get all class load hooks.
415
*/
416
(void)memset(&capabilities,0, sizeof(capabilities));
417
capabilities.can_generate_all_class_hook_events = 1;
418
error = (*jvmti)->AddCapabilities(jvmti, &capabilities);
419
check_jvmti_error(jvmti, error, "Unable to get necessary JVMTI capabilities.");
420
421
/* Next we need to provide the pointers to the callback functions to
422
* to this jvmtiEnv*
423
*/
424
(void)memset(&callbacks,0, sizeof(callbacks));
425
/* JVMTI_EVENT_VM_START */
426
callbacks.VMStart = &cbVMStart;
427
/* JVMTI_EVENT_VM_INIT */
428
callbacks.VMInit = &cbVMInit;
429
/* JVMTI_EVENT_VM_DEATH */
430
callbacks.VMDeath = &cbVMDeath;
431
/* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */
432
callbacks.ClassFileLoadHook = &cbClassFileLoadHook;
433
error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks));
434
check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks");
435
436
/* At first the only initial events we are interested in are VM
437
* initialization, VM death, and Class File Loads.
438
* Once the VM is initialized we will request more events.
439
*/
440
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
441
JVMTI_EVENT_VM_START, (jthread)NULL);
442
check_jvmti_error(jvmti, error, "Cannot set event notification");
443
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
444
JVMTI_EVENT_VM_INIT, (jthread)NULL);
445
check_jvmti_error(jvmti, error, "Cannot set event notification");
446
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
447
JVMTI_EVENT_VM_DEATH, (jthread)NULL);
448
check_jvmti_error(jvmti, error, "Cannot set event notification");
449
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
450
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, (jthread)NULL);
451
check_jvmti_error(jvmti, error, "Cannot set event notification");
452
453
/* Here we create a raw monitor for our use in this agent to
454
* protect critical sections of code.
455
*/
456
error = (*jvmti)->CreateRawMonitor(jvmti, "agent data", &(gdata->lock));
457
check_jvmti_error(jvmti, error, "Cannot create raw monitor");
458
459
/* Add demo jar file to boot classpath */
460
add_demo_jar_to_bootclasspath(jvmti, "minst");
461
462
/* We return JNI_OK to signify success */
463
return JNI_OK;
464
}
465
466
/* Agent_OnUnload: This is called immediately before the shared library is
467
* unloaded. This is the last code executed.
468
*/
469
JNIEXPORT void JNICALL
470
Agent_OnUnload(JavaVM *vm)
471
{
472
/* Make sure all malloc/calloc/strdup space is freed */
473
if ( gdata->include != NULL ) {
474
(void)free((void*)gdata->include);
475
gdata->include = NULL;
476
}
477
if ( gdata->exclude != NULL ) {
478
(void)free((void*)gdata->exclude);
479
gdata->exclude = NULL;
480
}
481
}
482
483