Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c
41153 views
1
/*
2
* Copyright (c) 2018, 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
41
42
static void reportError(const char *msg, int err) {
43
printf("%s, error: %d\n", msg, err);
44
}
45
46
47
// logs the notification and updates currentTestResult
48
static void handleNotification(JNIEnv *jni_env,
49
jmethodID method,
50
jfieldID field,
51
jclass field_klass,
52
int modified,
53
jlocation location)
54
{
55
jvmtiError err;
56
char *name = NULL;
57
char *mname = NULL;
58
char *mgensig = NULL;
59
jclass methodClass = NULL;
60
char *csig = NULL;
61
62
if (testResultObject == NULL) {
63
// we are out of test
64
return;
65
}
66
67
err = (*jvmti)->GetFieldName(jvmti, field_klass, field, &name, NULL, NULL);
68
if (err != JVMTI_ERROR_NONE) {
69
reportError("GetFieldName failed", err);
70
return;
71
}
72
73
err = (*jvmti)->GetMethodName(jvmti, method, &mname, NULL, &mgensig);
74
if (err != JVMTI_ERROR_NONE) {
75
reportError("GetMethodName failed", err);
76
return;
77
}
78
79
err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &methodClass);
80
if (err != JVMTI_ERROR_NONE) {
81
reportError("GetMethodDeclaringClass failed", err);
82
return;
83
}
84
85
err = (*jvmti)->GetClassSignature(jvmti, methodClass, &csig, NULL);
86
if (err != JVMTI_ERROR_NONE) {
87
reportError("GetClassSignature failed", err);
88
return;
89
}
90
91
printf("\"class: %s method: %s%s\" %s field: \"%s\", location: %d\n",
92
csig, mname, mgensig, modified ? "modified" : "accessed", name, (int)location);
93
94
// set TestResult
95
if (testResultObject != NULL && testResultClass != NULL) {
96
jfieldID fieldID;
97
// field names in TestResult are "<field_name>_access"/"<field_name>_modify"
98
char *fieldName = (char *)malloc(strlen(name) + 16);
99
strcpy(fieldName, name);
100
strcat(fieldName, modified ? "_modify" : "_access");
101
102
fieldID = (*jni_env)->GetFieldID(jni_env, testResultClass, fieldName, "Z");
103
if (fieldID != NULL) {
104
(*jni_env)->SetBooleanField(jni_env, testResultObject, fieldID, JNI_TRUE);
105
} else {
106
// the field is not interesting for the test
107
}
108
// clear any possible exception
109
(*jni_env)->ExceptionClear(jni_env);
110
111
free(fieldName);
112
}
113
114
(*jvmti)->Deallocate(jvmti, (unsigned char*)csig);
115
(*jvmti)->Deallocate(jvmti, (unsigned char*)mname);
116
(*jvmti)->Deallocate(jvmti, (unsigned char*)mgensig);
117
(*jvmti)->Deallocate(jvmti, (unsigned char*)name);
118
}
119
120
// recursively sets access and modification watchers for all
121
// fields of the object specified.
122
void setWatchers(JNIEnv *jni_env, const jobject obj)
123
{
124
jclass klass;
125
126
if (obj == NULL) {
127
return;
128
}
129
130
klass = (*jni_env)->GetObjectClass(jni_env, obj);
131
do {
132
jfieldID* klassFields = NULL;
133
jint fieldCount = 0;
134
int i;
135
jvmtiError err = (*jvmti)->GetClassFields(jvmti, klass, &fieldCount, &klassFields);
136
if (err != JVMTI_ERROR_NONE) {
137
reportError("Failed to get class fields", err);
138
return;
139
}
140
141
for (i = 0; i < fieldCount; ++i) {
142
char *sig = NULL;
143
err = (*jvmti)->SetFieldModificationWatch(jvmti, klass, klassFields[i]);
144
if (err != JVMTI_ERROR_NONE && err != JVMTI_ERROR_DUPLICATE) {
145
reportError("Failed to set field modification", err);
146
return;
147
}
148
149
err = (*jvmti)->SetFieldAccessWatch(jvmti, klass, klassFields[i]);
150
if (err != JVMTI_ERROR_NONE && err != JVMTI_ERROR_DUPLICATE) {
151
reportError("Failed to set field access", err);
152
return;
153
}
154
155
err = (*jvmti)->GetFieldName(jvmti, klass, klassFields[i], NULL, &sig, NULL);
156
if (sig) {
157
if (sig[0] == 'L') {
158
jobject fieldVal = (*jni_env)->GetObjectField(jni_env, obj, klassFields[i]);
159
setWatchers(jni_env, fieldVal);
160
}
161
(*jvmti)->Deallocate(jvmti, (unsigned char*)sig);
162
}
163
}
164
165
(*jvmti)->Deallocate(jvmti, (unsigned char*)klassFields);
166
167
klass = (*jni_env)->GetSuperclass(jni_env, klass);
168
} while (klass != NULL);
169
}
170
171
172
static void JNICALL
173
onFieldAccess(jvmtiEnv *jvmti_env,
174
JNIEnv* jni_env,
175
jthread thread,
176
jmethodID method,
177
jlocation location,
178
jclass field_klass,
179
jobject object,
180
jfieldID field)
181
{
182
handleNotification(jni_env, method, field, field_klass, 0, location);
183
}
184
185
186
static void JNICALL
187
onFieldModification(jvmtiEnv *jvmti_env,
188
JNIEnv* jni_env,
189
jthread thread,
190
jmethodID method,
191
jlocation location,
192
jclass field_klass,
193
jobject object,
194
jfieldID field,
195
char signature_type,
196
jvalue new_value)
197
{
198
handleNotification(jni_env, method, field, field_klass, 1, location);
199
200
if (signature_type == 'L') {
201
jobject newObject = new_value.l;
202
setWatchers(jni_env, newObject);
203
}
204
}
205
206
207
JNIEXPORT jint JNICALL
208
Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
209
{
210
jvmtiError err;
211
jvmtiCapabilities caps = {0};
212
jvmtiEventCallbacks callbacks = {0};
213
jint res = (*jvm)->GetEnv(jvm, (void **) &jvmti, JVMTI_VERSION_1_1);
214
if (res != JNI_OK || jvmti == NULL) {
215
reportError("GetEnv failed", res);
216
return JNI_ERR;
217
}
218
219
caps.can_generate_field_modification_events = 1;
220
caps.can_generate_field_access_events = 1;
221
caps.can_tag_objects = 1;
222
err = (*jvmti)->AddCapabilities(jvmti, &caps);
223
if (err != JVMTI_ERROR_NONE) {
224
reportError("Failed to set capabilities", err);
225
return JNI_ERR;
226
}
227
228
callbacks.FieldModification = &onFieldModification;
229
callbacks.FieldAccess = &onFieldAccess;
230
231
err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
232
if (err != JVMTI_ERROR_NONE) {
233
reportError("Failed to set event callbacks", err);
234
return JNI_ERR;
235
}
236
237
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_ACCESS, NULL);
238
if (err != JVMTI_ERROR_NONE) {
239
reportError("Failed to set access notifications", err);
240
return JNI_ERR;
241
}
242
243
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_MODIFICATION, NULL);
244
if (err != JVMTI_ERROR_NONE) {
245
reportError("Failed to set modification notifications", err);
246
return JNI_ERR;
247
}
248
setbuf(stdout, NULL);
249
return JNI_OK;
250
}
251
252
253
JNIEXPORT jboolean JNICALL
254
Java_FieldAccessWatch_initWatchers(JNIEnv *env, jclass thisClass, jclass cls, jobject field)
255
{
256
jfieldID fieldId;
257
jvmtiError err;
258
259
if (jvmti == NULL) {
260
reportError("jvmti is NULL", 0);
261
return JNI_FALSE;
262
}
263
264
fieldId = (*env)->FromReflectedField(env, field);
265
266
err = (*jvmti)->SetFieldModificationWatch(jvmti, cls, fieldId);
267
if (err != JVMTI_ERROR_NONE) {
268
reportError("SetFieldModificationWatch failed", err);
269
return JNI_FALSE;
270
}
271
272
err = (*jvmti)->SetFieldAccessWatch(jvmti, cls, fieldId);
273
if (err != JVMTI_ERROR_NONE) {
274
reportError("SetFieldAccessWatch failed", err);
275
return JNI_FALSE;
276
}
277
278
return JNI_TRUE;
279
}
280
281
282
JNIEXPORT jboolean JNICALL
283
Java_FieldAccessWatch_startTest(JNIEnv *env, jclass thisClass, jobject testResults)
284
{
285
testResultObject = (*env)->NewGlobalRef(env, testResults);
286
testResultClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, testResultObject));
287
288
return JNI_TRUE;
289
}
290
291
JNIEXPORT void JNICALL
292
Java_FieldAccessWatch_stopTest(JNIEnv *env, jclass thisClass)
293
{
294
if (testResultObject != NULL) {
295
(*env)->DeleteGlobalRef(env, testResultObject);
296
testResultObject = NULL;
297
}
298
if (testResultClass != NULL) {
299
(*env)->DeleteGlobalRef(env, testResultClass);
300
testResultClass = NULL;
301
}
302
}
303
304
305
#ifdef __cplusplus
306
}
307
#endif
308
309
310