1 /*
2 * Copyright (c) 1998, 2024, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include "util.h"
27 #include "ObjectReferenceImpl.h"
28 #include "commonRef.h"
29 #include "inStream.h"
30 #include "outStream.h"
31 #include "signature.h"
32
33 static jboolean
34 referenceType(PacketInputStream *in, PacketOutputStream *out)
35 {
36 JNIEnv *env;
37 jobject object;
38
39 env = getEnv();
40
41 object = inStream_readObjectRef(env, in);
42 if (inStream_error(in)) {
43 return JNI_TRUE;
44 }
45
46 WITH_LOCAL_REFS(env, 1) {
47
48 jbyte tag;
49 jclass clazz;
50
51 clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, object);
52 tag = referenceTypeTag(clazz);
53
54 (void)outStream_writeByte(out, tag);
55 (void)outStream_writeObjectRef(env, out, clazz);
56
57 } END_WITH_LOCAL_REFS(env);
58
59 return JNI_TRUE;
60 }
61
62 static jboolean
63 getValues(PacketInputStream *in, PacketOutputStream *out)
64 {
65 sharedGetFieldValues(in, out, JNI_FALSE);
66 return JNI_TRUE;
67 }
68
69 static jvmtiError
70 readFieldValue(JNIEnv *env, PacketInputStream *in, jclass clazz,
71 jobject object, jfieldID field, char *signature)
72 {
73 jvalue value;
74
75 jbyte typeKey = jdwpTag(signature);
76 if (isReferenceTag(typeKey)) {
77 value.l = inStream_readObjectRef(env, in);
78 JNI_FUNC_PTR(env,SetObjectField)(env, object, field, value.l);
79 if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) {
80 return AGENT_ERROR_JNI_EXCEPTION;
81 }
82 return JVMTI_ERROR_NONE;
83 }
84 switch (typeKey) {
85 case JDWP_TAG(BYTE):
86 value.b = inStream_readByte(in);
87 JNI_FUNC_PTR(env,SetByteField)(env, object, field, value.b);
88 break;
89
90 case JDWP_TAG(CHAR):
91 value.c = inStream_readChar(in);
92 JNI_FUNC_PTR(env,SetCharField)(env, object, field, value.c);
93 break;
94
95 case JDWP_TAG(FLOAT):
96 value.f = inStream_readFloat(in);
97 JNI_FUNC_PTR(env,SetFloatField)(env, object, field, value.f);
98 break;
99
100 case JDWP_TAG(DOUBLE):
101 value.d = inStream_readDouble(in);
102 JNI_FUNC_PTR(env,SetDoubleField)(env, object, field, value.d);
103 break;
104
105 case JDWP_TAG(INT):
106 value.i = inStream_readInt(in);
107 JNI_FUNC_PTR(env,SetIntField)(env, object, field, value.i);
108 break;
109
110 case JDWP_TAG(LONG):
111 value.j = inStream_readLong(in);
112 JNI_FUNC_PTR(env,SetLongField)(env, object, field, value.j);
113 break;
114
115 case JDWP_TAG(SHORT):
116 value.s = inStream_readShort(in);
117 JNI_FUNC_PTR(env,SetShortField)(env, object, field, value.s);
118 break;
119
120 case JDWP_TAG(BOOLEAN):
121 value.z = inStream_readBoolean(in);
122 JNI_FUNC_PTR(env,SetBooleanField)(env, object, field, value.z);
123 break;
124 }
125
126 if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) {
127 return AGENT_ERROR_JNI_EXCEPTION;
128 }
129 return JVMTI_ERROR_NONE;
130 }
131
132 static jboolean
133 setValues(PacketInputStream *in, PacketOutputStream *out)
134 {
135 JNIEnv *env;
136 jint count;
137 jvmtiError error;
138 jobject object;
139
140 env = getEnv();
141
142 object = inStream_readObjectRef(env, in);
143 if (inStream_error(in)) {
144 return JNI_TRUE;
145 }
146 count = inStream_readInt(in);
147 if (inStream_error(in)) {
148 return JNI_TRUE;
149 }
150
151 error = JVMTI_ERROR_NONE;
152
153 WITH_LOCAL_REFS(env, count + 1) {
154
155 jclass clazz;
156
157 clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, object);
158
159 if (clazz != NULL ) {
160
161 int i;
162
163 for (i = 0; (i < count) && !inStream_error(in); i++) {
164
165 jfieldID field;
166 char *signature = NULL;
167
168 field = inStream_readFieldID(in);
169 if (inStream_error(in))
170 break;
171
172 error = fieldSignature(clazz, field, NULL, &signature, NULL);
173 if (error != JVMTI_ERROR_NONE) {
174 break;
175 }
176
177 error = readFieldValue(env, in, clazz, object, field, signature);
178 jvmtiDeallocate(signature);
179
180 if (error != JVMTI_ERROR_NONE) {
181 break;
182 }
183 }
184 }
185
186 if (error != JVMTI_ERROR_NONE) {
187 outStream_setError(out, map2jdwpError(error));
188 }
189
190 } END_WITH_LOCAL_REFS(env);
191
192 return JNI_TRUE;
193 }
194
195 static jboolean
196 monitorInfo(PacketInputStream *in, PacketOutputStream *out)
197 {
198 JNIEnv *env;
199 jobject object;
200
201 env = getEnv();
202
203 object = inStream_readObjectRef(env, in);
204 if (inStream_error(in)) {
205 return JNI_TRUE;
206 }
207
208 WITH_LOCAL_REFS(env, 1) {
209
210 jvmtiError error;
211 jvmtiMonitorUsage info;
212
213 (void)memset(&info, 0, sizeof(info));
214 error = JVMTI_FUNC_PTR(gdata->jvmti,GetObjectMonitorUsage)
215 (gdata->jvmti, object, &info);
216 if (error != JVMTI_ERROR_NONE) {
217 outStream_setError(out, map2jdwpError(error));
218 } else {
219 int i;
220 (void)outStream_writeObjectRef(env, out, info.owner);
221 (void)outStream_writeInt(out, info.entry_count);
222 (void)outStream_writeInt(out, info.waiter_count + info.notify_waiter_count);
223 for (i = 0; i < info.waiter_count; i++) {
224 (void)outStream_writeObjectRef(env, out, info.waiters[i]);
225 }
226 for (i = 0; i < info.notify_waiter_count; i++) {
227 (void)outStream_writeObjectRef(env, out, info.notify_waiters[i]);
228 }
229 }
230
231 if (info.waiters != NULL )
232 jvmtiDeallocate(info.waiters);
233 if (info.notify_waiters != NULL )
234 jvmtiDeallocate(info.notify_waiters);
235
236 } END_WITH_LOCAL_REFS(env);
237
238 return JNI_TRUE;
239 }
240
241 static jboolean
242 invokeInstance(PacketInputStream *in, PacketOutputStream *out)
243 {
244 return sharedInvoke(in, out);
245 }
246
247 static jboolean
248 disableCollection(PacketInputStream *in, PacketOutputStream *out)
249 {
250 jlong id;
251 jvmtiError error;
252
253 id = inStream_readObjectID(in);
254 if (inStream_error(in)) {
255 return JNI_TRUE;
256 }
257
258 error = commonRef_pin(id);
259 if (error != JVMTI_ERROR_NONE) {
260 outStream_setError(out, map2jdwpError(error));
261 }
262
263 return JNI_TRUE;
264 }
265
266 static jboolean
267 enableCollection(PacketInputStream *in, PacketOutputStream *out)
268 {
269 jvmtiError error;
270 jlong id;
271
272 id = inStream_readObjectID(in);
273 if (inStream_error(in)) {
274 return JNI_TRUE;
275 }
276
277 error = commonRef_unpin(id);
278 if (error != JVMTI_ERROR_NONE) {
279 outStream_setError(out, map2jdwpError(error));
280 }
281
282 return JNI_TRUE;
283 }
284
285 static jboolean
286 isCollected(PacketInputStream *in, PacketOutputStream *out)
287 {
288 jobject ref;
289 jlong id;
290 JNIEnv *env;
291
292 env = getEnv();
293 id = inStream_readObjectID(in);
294 if (inStream_error(in)) {
295 return JNI_TRUE;
296 }
297
298 if (id == NULL_OBJECT_ID) {
299 outStream_setError(out, JDWP_ERROR(INVALID_OBJECT));
300 return JNI_TRUE;
301 }
302
303 ref = commonRef_idToRef(env, id);
304 (void)outStream_writeBoolean(out, (jboolean)(ref == NULL));
305
306 commonRef_idToRef_delete(env, ref);
307
308 return JNI_TRUE;
309 }
310
311
312 static jboolean
313 referringObjects(PacketInputStream *in, PacketOutputStream *out)
314 {
315 jobject object;
316 jint maxReferrers;
317 JNIEnv *env;
318
319 env = getEnv();
320
321 if (gdata->vmDead) {
322 outStream_setError(out, JDWP_ERROR(VM_DEAD));
323 return JNI_TRUE;
324 }
325
326 object = inStream_readObjectRef(env,in);
327 if (inStream_error(in)) {
328 return JNI_TRUE;
329 }
330
331 maxReferrers = inStream_readInt(in);
332 if (inStream_error(in)) {
333 return JNI_TRUE;
334 }
335
336 WITH_LOCAL_REFS(env, 1) {
337 jvmtiError error;
338 ObjectBatch referrerBatch;
339
340 error = objectReferrers(object, &referrerBatch, maxReferrers);
341 if (error != JVMTI_ERROR_NONE) {
342 outStream_setError(out, map2jdwpError(error));
343 } else {
344 int kk;
345
346 (void)outStream_writeInt(out, referrerBatch.count);
347 for (kk = 0; kk < referrerBatch.count; kk++) {
348 jobject ref;
349
350 ref = referrerBatch.objects[kk];
351 (void)outStream_writeByte(out, specificTypeKey(env, ref));
352 (void)outStream_writeObjectRef(env, out, ref);
353 }
354 jvmtiDeallocate(referrerBatch.objects);
355 }
356 } END_WITH_LOCAL_REFS(env);
357 return JNI_TRUE;
358 }
359
360 static jboolean
361 isSameObjectImpl(PacketInputStream *in, PacketOutputStream *out)
362 {
363 jlong id1;
364 jlong id2;
365 jobject ref1;
366 jobject ref2;
367 JNIEnv *env;
368
369 env = getEnv();
370 id1 = inStream_readObjectID(in);
371 id2 = inStream_readObjectID(in);
372 if (inStream_error(in)) {
373 return JNI_TRUE;
374 }
375
376 if (id1 == NULL_OBJECT_ID || id2 == NULL_OBJECT_ID) {
377 outStream_setError(out, JDWP_ERROR(INVALID_OBJECT));
378 return JNI_TRUE;
379 }
380
381 ref1 = commonRef_idToRef(env, id1);
382 ref2 = commonRef_idToRef(env, id2);
383 (void)outStream_writeBoolean(out, isSameObject(env, ref1, ref2));
384
385 commonRef_idToRef_delete(env, ref1);
386 commonRef_idToRef_delete(env, ref2);
387
388 return JNI_TRUE;
389 }
390
391 static jboolean
392 objectHashCodeImpl(PacketInputStream *in, PacketOutputStream *out)
393 {
394 jlong id;
395 jobject ref;
396 JNIEnv *env;
397
398 env = getEnv();
399 id = inStream_readObjectID(in);
400 if (inStream_error(in)) {
401 return JNI_TRUE;
402 }
403
404 if (id == NULL_OBJECT_ID) {
405 outStream_setError(out, JDWP_ERROR(INVALID_OBJECT));
406 return JNI_TRUE;
407 }
408
409 ref = commonRef_idToRef(env, id);
410 (void)outStream_writeInt(out, objectHashCode(ref));
411
412 commonRef_idToRef_delete(env, ref);
413
414 return JNI_TRUE;
415 }
416
417 Command ObjectReference_Commands[] = {
418 {referenceType, "ReferenceType"},
419 {getValues, "GetValues"},
420 {setValues, "SetValues"},
421 {NULL, "<unused>"},
422 {monitorInfo, "MonitorInfo"},
423 {invokeInstance, "InvokeInstance"},
424 {disableCollection, "DisableCollection"},
425 {enableCollection, "EnableCollection"},
426 {isCollected, "IsCollected"},
427 {referringObjects, "ReferringObjects"},
428 {isSameObjectImpl, "IsSameObject"},
429 {objectHashCodeImpl, "ObjectHashCode"}
430 };
431
432 DEBUG_DISPATCH_DEFINE_CMDSET(ObjectReference)