Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c
66646 views
1
/*
2
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
#include <stdio.h>
25
#include <string.h>
26
#include <stdlib.h>
27
#include "jvmti.h"
28
#include "jni.h"
29
30
#ifdef __cplusplus
31
extern "C" {
32
#endif
33
34
35
static jvmtiEnv *jvmti = NULL;
36
37
// valid while a test is executed
38
static jobject testResultObject = NULL;
39
static jclass testResultClass = NULL;
40
static jthread testThread = NULL;
41
42
43
static void reportError(const char *msg, int err) {
44
printf("%s, error: %d\n", msg, err);
45
}
46
47
48
// logs the notification and updates currentTestResult
49
static void handleNotification(JNIEnv *jni_env,
50
jthread thread,
51
jmethodID method,
52
jfieldID field,
53
jclass field_klass,
54
int modified,
55
jlocation location)
56
{
57
jvmtiError err;
58
char *name = NULL;
59
char *mname = NULL;
60
char *mgensig = NULL;
61
jclass methodClass = NULL;
62
char *csig = NULL;
63
64
if (testResultObject == NULL) {
65
// we are out of test
66
return;
67
}
68
69
if (!(*jni_env)->IsSameObject(jni_env, thread, testThread)) {
70
return; // skip events from unexpected threads
71
}
72
73
err = (*jvmti)->GetFieldName(jvmti, field_klass, field, &name, NULL, NULL);
74
if (err != JVMTI_ERROR_NONE) {
75
reportError("GetFieldName failed", err);
76
return;
77
}
78
79
err = (*jvmti)->GetMethodName(jvmti, method, &mname, NULL, &mgensig);
80
if (err != JVMTI_ERROR_NONE) {
81
reportError("GetMethodName failed", err);
82
return;
83
}
84
85
err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &methodClass);
86
if (err != JVMTI_ERROR_NONE) {
87
reportError("GetMethodDeclaringClass failed", err);
88
return;
89
}
90
91
err = (*jvmti)->GetClassSignature(jvmti, methodClass, &csig, NULL);
92
if (err != JVMTI_ERROR_NONE) {
93
reportError("GetClassSignature failed", err);
94
return;
95
}
96
97
printf("\"class: %s method: %s%s\" %s field: \"%s\", location: %d\n",
98
csig, mname, mgensig, modified ? "modified" : "accessed", name, (int)location);
99
100
// set TestResult
101
if (testResultObject != NULL && testResultClass != NULL) {
102
jfieldID fieldID;
103
// field names in TestResult are "<field_name>_access"/"<field_name>_modify"
104
char *fieldName = (char *)malloc(strlen(name) + 16);
105
strcpy(fieldName, name);
106
strcat(fieldName, modified ? "_modify" : "_access");
107
108
fieldID = (*jni_env)->GetFieldID(jni_env, testResultClass, fieldName, "Z");
109
if (fieldID != NULL) {
110
(*jni_env)->SetBooleanField(jni_env, testResultObject, fieldID, JNI_TRUE);
111
} else {
112
// the field is not interesting for the test
113
}
114
// clear any possible exception
115
(*jni_env)->ExceptionClear(jni_env);
116
117
free(fieldName);
118
}
119
120
(*jvmti)->Deallocate(jvmti, (unsigned char*)csig);
121
(*jvmti)->Deallocate(jvmti, (unsigned char*)mname);
122
(*jvmti)->Deallocate(jvmti, (unsigned char*)mgensig);
123
(*jvmti)->Deallocate(jvmti, (unsigned char*)name);
124
}
125
126
// recursively sets access and modification watchers for all
127
// fields of the object specified.
128
void setWatchers(JNIEnv *jni_env, const jobject obj)
129
{
130
jclass klass;
131
132
if (obj == NULL) {
133
return;
134
}
135
136
klass = (*jni_env)->GetObjectClass(jni_env, obj);
137
do {
138
jfieldID* klassFields = NULL;
139
jint fieldCount = 0;
140
int i;
141
jvmtiError err = (*jvmti)->GetClassFields(jvmti, klass, &fieldCount, &klassFields);
142
if (err != JVMTI_ERROR_NONE) {
143
reportError("Failed to get class fields", err);
144
return;
145
}
146
147
for (i = 0; i < fieldCount; ++i) {
148
char *sig = NULL;
149
err = (*jvmti)->SetFieldModificationWatch(jvmti, klass, klassFields[i]);
150
if (err != JVMTI_ERROR_NONE && err != JVMTI_ERROR_DUPLICATE) {
151
reportError("Failed to set field modification", err);
152
return;
153
}
154
155
err = (*jvmti)->SetFieldAccessWatch(jvmti, klass, klassFields[i]);
156
if (err != JVMTI_ERROR_NONE && err != JVMTI_ERROR_DUPLICATE) {
157
reportError("Failed to set field access", err);
158
return;
159
}
160
161
err = (*jvmti)->GetFieldName(jvmti, klass, klassFields[i], NULL, &sig, NULL);
162
if (sig) {
163
if (sig[0] == 'L') {
164
jobject fieldVal = (*jni_env)->GetObjectField(jni_env, obj, klassFields[i]);
165
setWatchers(jni_env, fieldVal);
166
}
167
(*jvmti)->Deallocate(jvmti, (unsigned char*)sig);
168
}
169
}
170
171
(*jvmti)->Deallocate(jvmti, (unsigned char*)klassFields);
172
173
klass = (*jni_env)->GetSuperclass(jni_env, klass);
174
} while (klass != NULL);
175
}
176
177
178
static void JNICALL
179
onFieldAccess(jvmtiEnv *jvmti_env,
180
JNIEnv* jni_env,
181
jthread thread,
182
jmethodID method,
183
jlocation location,
184
jclass field_klass,
185
jobject object,
186
jfieldID field)
187
{
188
handleNotification(jni_env, thread, method, field, field_klass, 0, location);
189
}
190
191
192
static void JNICALL
193
onFieldModification(jvmtiEnv *jvmti_env,
194
JNIEnv* jni_env,
195
jthread thread,
196
jmethodID method,
197
jlocation location,
198
jclass field_klass,
199
jobject object,
200
jfieldID field,
201
char signature_type,
202
jvalue new_value)
203
{
204
handleNotification(jni_env, thread, method, field, field_klass, 1, location);
205
206
if (signature_type == 'L') {
207
jobject newObject = new_value.l;
208
setWatchers(jni_env, newObject);
209
}
210
}
211
212
213
JNIEXPORT jint JNICALL
214
Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
215
{
216
jvmtiError err;
217
jvmtiCapabilities caps;
218
jvmtiEventCallbacks callbacks;
219
jint res = (*jvm)->GetEnv(jvm, (void **) &jvmti, JVMTI_VERSION_1_1);
220
if (res != JNI_OK || jvmti == NULL) {
221
reportError("GetEnv failed", res);
222
return JNI_ERR;
223
}
224
225
memset(&caps, 0, sizeof(caps));
226
caps.can_generate_field_modification_events = 1;
227
caps.can_generate_field_access_events = 1;
228
caps.can_tag_objects = 1;
229
err = (*jvmti)->AddCapabilities(jvmti, &caps);
230
if (err != JVMTI_ERROR_NONE) {
231
reportError("Failed to set capabilities", err);
232
return JNI_ERR;
233
}
234
235
memset(&callbacks, 0, sizeof(callbacks));
236
callbacks.FieldModification = &onFieldModification;
237
callbacks.FieldAccess = &onFieldAccess;
238
239
err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
240
if (err != JVMTI_ERROR_NONE) {
241
reportError("Failed to set event callbacks", err);
242
return JNI_ERR;
243
}
244
245
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_ACCESS, NULL);
246
if (err != JVMTI_ERROR_NONE) {
247
reportError("Failed to set access notifications", err);
248
return JNI_ERR;
249
}
250
251
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_MODIFICATION, NULL);
252
if (err != JVMTI_ERROR_NONE) {
253
reportError("Failed to set modification notifications", err);
254
return JNI_ERR;
255
}
256
setbuf(stdout, NULL);
257
return JNI_OK;
258
}
259
260
261
JNIEXPORT jboolean JNICALL
262
Java_FieldAccessWatch_initWatchers(JNIEnv *env, jclass thisClass, jclass cls, jobject field, jthread thread)
263
{
264
jfieldID fieldId;
265
jvmtiError err;
266
267
if (jvmti == NULL) {
268
reportError("jvmti is NULL", 0);
269
return JNI_FALSE;
270
}
271
272
fieldId = (*env)->FromReflectedField(env, field);
273
274
err = (*jvmti)->SetFieldModificationWatch(jvmti, cls, fieldId);
275
if (err != JVMTI_ERROR_NONE) {
276
reportError("SetFieldModificationWatch failed", err);
277
return JNI_FALSE;
278
}
279
280
err = (*jvmti)->SetFieldAccessWatch(jvmti, cls, fieldId);
281
if (err != JVMTI_ERROR_NONE) {
282
reportError("SetFieldAccessWatch failed", err);
283
return JNI_FALSE;
284
}
285
286
testThread = (jthread)(*env)->NewGlobalRef(env, thread);
287
288
return JNI_TRUE;
289
}
290
291
292
JNIEXPORT jboolean JNICALL
293
Java_FieldAccessWatch_startTest(JNIEnv *env, jclass thisClass, jobject testResults)
294
{
295
testResultObject = (*env)->NewGlobalRef(env, testResults);
296
testResultClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, testResultObject));
297
298
return JNI_TRUE;
299
}
300
301
JNIEXPORT void JNICALL
302
Java_FieldAccessWatch_stopTest(JNIEnv *env, jclass thisClass)
303
{
304
if (testResultObject != NULL) {
305
(*env)->DeleteGlobalRef(env, testResultObject);
306
testResultObject = NULL;
307
}
308
if (testResultClass != NULL) {
309
(*env)->DeleteGlobalRef(env, testResultClass);
310
testResultClass = NULL;
311
}
312
}
313
314
315
#ifdef __cplusplus
316
}
317
#endif
318
319
320