1 /*
2 * Copyright (c) 1998, 2005, 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 "ReferenceTypeImpl.h"
28 #include "inStream.h"
29 #include "outStream.h"
30
31
32 static jboolean
signature(PacketInputStream * in,PacketOutputStream * out)33 signature(PacketInputStream *in, PacketOutputStream *out)
34 {
35 char *signature = NULL;
36 jclass clazz;
37 jvmtiError error;
38
39 clazz = inStream_readClassRef(getEnv(), in);
40 if (inStream_error(in)) {
41 return JNI_TRUE;
42 }
43
44 error = classSignature(clazz, &signature, NULL);
45 if (error != JVMTI_ERROR_NONE) {
46 outStream_setError(out, map2jdwpError(error));
47 return JNI_TRUE;
48 }
49
50 (void)outStream_writeString(out, signature);
51 jvmtiDeallocate(signature);
52
53 return JNI_TRUE;
54 }
55
56 static jboolean
signatureWithGeneric(PacketInputStream * in,PacketOutputStream * out)57 signatureWithGeneric(PacketInputStream *in, PacketOutputStream *out)
58 {
59 /* Returns both the signature and the generic signature */
60 char *signature = NULL;
61 char *genericSignature = NULL;
62 jclass clazz;
63 jvmtiError error;
64
65 clazz = inStream_readClassRef(getEnv(), in);
66 if (inStream_error(in)) {
67 return JNI_TRUE;
68 }
69 error = classSignature(clazz, &signature, &genericSignature);
70 if (error != JVMTI_ERROR_NONE) {
71 outStream_setError(out, map2jdwpError(error));
72 return JNI_TRUE;
73 }
74
75 (void)outStream_writeString(out, signature);
76 writeGenericSignature(out, genericSignature);
77 jvmtiDeallocate(signature);
78 if (genericSignature != NULL) {
79 jvmtiDeallocate(genericSignature);
80 }
81
82
83 return JNI_TRUE;
84 }
85
86 static jboolean
getClassLoader(PacketInputStream * in,PacketOutputStream * out)87 getClassLoader(PacketInputStream *in, PacketOutputStream *out)
88 {
89 jclass clazz;
90 jobject loader;
91 jvmtiError error;
92 JNIEnv *env;
93
94 env = getEnv();
95
96 clazz = inStream_readClassRef(env, in);
97 if (inStream_error(in)) {
98 return JNI_TRUE;
99 }
100
101 error = classLoader(clazz, &loader);
102 if (error != JVMTI_ERROR_NONE) {
103 outStream_setError(out, map2jdwpError(error));
104 return JNI_TRUE;
105 }
106
107 (void)outStream_writeObjectRef(env, out, loader);
108 return JNI_TRUE;
109 }
110
111 static jboolean
modifiers(PacketInputStream * in,PacketOutputStream * out)112 modifiers(PacketInputStream *in, PacketOutputStream *out)
113 {
114 jint modifiers;
115 jclass clazz;
116 jvmtiError error;
117
118 clazz = inStream_readClassRef(getEnv(), in);
119 if (inStream_error(in)) {
120 return JNI_TRUE;
121 }
122
123 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassModifiers)
124 (gdata->jvmti, clazz, &modifiers);
125 if (error != JVMTI_ERROR_NONE) {
126 outStream_setError(out, map2jdwpError(error));
127 return JNI_TRUE;
128 }
129
130 (void)outStream_writeInt(out, modifiers);
131
132 return JNI_TRUE;
133 }
134
135 static void
writeMethodInfo(PacketOutputStream * out,jclass clazz,jmethodID method,int outputGenerics)136 writeMethodInfo(PacketOutputStream *out, jclass clazz, jmethodID method,
137 int outputGenerics)
138 {
139 char *name = NULL;
140 char *signature = NULL;
141 char *genericSignature = NULL;
142 jint modifiers;
143 jvmtiError error;
144 jboolean isSynthetic;
145
146 error = isMethodSynthetic(method, &isSynthetic);
147 if (error != JVMTI_ERROR_NONE) {
148 outStream_setError(out, map2jdwpError(error));
149 return;
150 }
151
152 error = methodModifiers(method, &modifiers);
153 if (error != JVMTI_ERROR_NONE) {
154 outStream_setError(out, map2jdwpError(error));
155 return;
156 }
157
158 error = methodSignature(method, &name, &signature, &genericSignature);
159 if (error != JVMTI_ERROR_NONE) {
160 outStream_setError(out, map2jdwpError(error));
161 return;
162 }
163
164 if (isSynthetic) {
165 modifiers |= MOD_SYNTHETIC;
166 }
167 (void)outStream_writeMethodID(out, method);
168 (void)outStream_writeString(out, name);
169 (void)outStream_writeString(out, signature);
170 if (outputGenerics == 1) {
171 writeGenericSignature(out, genericSignature);
172 }
173 (void)outStream_writeInt(out, modifiers);
174 jvmtiDeallocate(name);
175 jvmtiDeallocate(signature);
176 if (genericSignature != NULL) {
177 jvmtiDeallocate(genericSignature);
178 }
179 }
180
181 static jboolean
methods1(PacketInputStream * in,PacketOutputStream * out,int outputGenerics)182 methods1(PacketInputStream *in, PacketOutputStream *out,
183 int outputGenerics)
184 {
185 int i;
186 jclass clazz;
187 jint methodCount = 0;
188 jmethodID *methods = NULL;
189 jvmtiError error;
190
191 clazz = inStream_readClassRef(getEnv(), in);
192 if (inStream_error(in)) {
193 return JNI_TRUE;
194 }
195
196 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassMethods)
197 (gdata->jvmti, clazz, &methodCount, &methods);
198 if (error != JVMTI_ERROR_NONE) {
199 outStream_setError(out, map2jdwpError(error));
200 return JNI_TRUE;
201 }
202
203 (void)outStream_writeInt(out, methodCount);
204 for (i = 0; (i < methodCount) && !outStream_error(out); i++) {
205 writeMethodInfo(out, clazz, methods[i], outputGenerics);
206 }
207
208 /* Free methods array */
209 if ( methods != NULL ) {
210 jvmtiDeallocate(methods);
211 }
212 return JNI_TRUE;
213 }
214
215 static jboolean
methods(PacketInputStream * in,PacketOutputStream * out,int outputGenerics)216 methods(PacketInputStream *in, PacketOutputStream *out,
217 int outputGenerics)
218 {
219 return methods1(in, out, 0);
220 }
221
222 static jboolean
methodsWithGeneric(PacketInputStream * in,PacketOutputStream * out)223 methodsWithGeneric(PacketInputStream *in, PacketOutputStream *out)
224 {
225 return methods1(in, out, 1);
226 }
227
228
229
230 static jboolean
instances(PacketInputStream * in,PacketOutputStream * out)231 instances(PacketInputStream *in, PacketOutputStream *out)
232 {
233 jint maxInstances;
234 jclass clazz;
235 JNIEnv *env;
236
237 if (gdata->vmDead) {
238 outStream_setError(out, JDWP_ERROR(VM_DEAD));
239 return JNI_TRUE;
240 }
241
242 env = getEnv();
243 clazz = inStream_readClassRef(env, in);
244 maxInstances = inStream_readInt(in);
245 if (inStream_error(in)) {
246 return JNI_TRUE;
247 }
248
249 WITH_LOCAL_REFS(env, 1) {
250 jvmtiError error;
251 ObjectBatch batch;
252
253 error = classInstances(clazz, &batch, maxInstances);
254 if (error != JVMTI_ERROR_NONE) {
255 outStream_setError(out, map2jdwpError(error));
256 } else {
257 int kk;
258 jbyte typeKey;
259
260 (void)outStream_writeInt(out, batch.count);
261 if (batch.count > 0) {
262 /*
263 * They are all instances of this class and will all have
264 * the same typeKey, so just compute it once.
265 */
266 typeKey = specificTypeKey(env, batch.objects[0]);
267
268 for (kk = 0; kk < batch.count; kk++) {
269 jobject inst;
270
271 inst = batch.objects[kk];
272 (void)outStream_writeByte(out, typeKey);
273 (void)outStream_writeObjectRef(env, out, inst);
274 }
275 }
276 jvmtiDeallocate(batch.objects);
277 }
278 } END_WITH_LOCAL_REFS(env);
279
280 return JNI_TRUE;
281 }
282
283 static jboolean
getClassVersion(PacketInputStream * in,PacketOutputStream * out)284 getClassVersion(PacketInputStream *in, PacketOutputStream *out)
285 {
286 jclass clazz;
287 jvmtiError error;
288 jint majorVersion;
289 jint minorVersion;
290
291 clazz = inStream_readClassRef(getEnv(), in);
292 if (inStream_error(in)) {
293 return JNI_TRUE;
294 }
295
296 error = JVMTI_FUNC_PTR(gdata->jvmti, GetClassVersionNumbers)
297 (gdata->jvmti, clazz, &minorVersion, &majorVersion);
298 if (error != JVMTI_ERROR_NONE) {
299 outStream_setError(out, map2jdwpError(error));
300 return JNI_TRUE;
301 }
302
303 (void)outStream_writeInt(out, majorVersion);
304 (void)outStream_writeInt(out, minorVersion);
305
306 return JNI_TRUE;
307 }
308
309 static jboolean
getConstantPool(PacketInputStream * in,PacketOutputStream * out)310 getConstantPool(PacketInputStream *in, PacketOutputStream *out)
311 {
312
313 jclass clazz;
314 jvmtiError error;
315 jint cpCount;
316 jint cpByteCount;
317 unsigned char* cpBytesPtr;
318
319
320 clazz = inStream_readClassRef(getEnv(), in);
321 if (inStream_error(in)) {
322 return JNI_TRUE;
323 }
324
325 /* Initialize assuming no bytecodes and no error */
326 error = JVMTI_ERROR_NONE;
327 cpCount = 0;
328 cpByteCount = 0;
329 cpBytesPtr = NULL;
330
331
332 error = JVMTI_FUNC_PTR(gdata->jvmti,GetConstantPool)
333 (gdata->jvmti, clazz, &cpCount, &cpByteCount, &cpBytesPtr);
334 if (error != JVMTI_ERROR_NONE) {
335 outStream_setError(out, map2jdwpError(error));
336 } else {
337 (void)outStream_writeInt(out, cpCount);
338 (void)outStream_writeByteArray(out, cpByteCount, (jbyte *)cpBytesPtr);
339 jvmtiDeallocate(cpBytesPtr);
340 }
341
342 return JNI_TRUE;
343 }
344
345 static void
writeFieldInfo(PacketOutputStream * out,jclass clazz,jfieldID fieldID,int outputGenerics)346 writeFieldInfo(PacketOutputStream *out, jclass clazz, jfieldID fieldID,
347 int outputGenerics)
348 {
349 char *name;
350 char *signature = NULL;
351 char *genericSignature = NULL;
352 jint modifiers;
353 jboolean isSynthetic;
354 jvmtiError error;
355
356 error = isFieldSynthetic(clazz, fieldID, &isSynthetic);
357 if (error != JVMTI_ERROR_NONE) {
358 outStream_setError(out, map2jdwpError(error));
359 return;
360 }
361
362 error = fieldModifiers(clazz, fieldID, &modifiers);
363 if (error != JVMTI_ERROR_NONE) {
364 outStream_setError(out, map2jdwpError(error));
365 return;
366 }
367
368 error = fieldSignature(clazz, fieldID, &name, &signature, &genericSignature);
369 if (error != JVMTI_ERROR_NONE) {
370 outStream_setError(out, map2jdwpError(error));
371 return;
372 }
373 if (isSynthetic) {
374 modifiers |= MOD_SYNTHETIC;
375 }
376 (void)outStream_writeFieldID(out, fieldID);
377 (void)outStream_writeString(out, name);
378 (void)outStream_writeString(out, signature);
379 if (outputGenerics == 1) {
380 writeGenericSignature(out, genericSignature);
381 }
382 (void)outStream_writeInt(out, modifiers);
383 jvmtiDeallocate(name);
384 jvmtiDeallocate(signature);
385 if (genericSignature != NULL) {
386 jvmtiDeallocate(genericSignature);
387 }
388 }
389
390 static jboolean
fields1(PacketInputStream * in,PacketOutputStream * out,int outputGenerics)391 fields1(PacketInputStream *in, PacketOutputStream *out, int outputGenerics)
392 {
393 int i;
394 jclass clazz;
395 jint fieldCount = 0;
396 jfieldID *fields = NULL;
397 jvmtiError error;
398
399 clazz = inStream_readClassRef(getEnv(), in);
400 if (inStream_error(in)) {
401 return JNI_TRUE;
402 }
403
404 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassFields)
405 (gdata->jvmti, clazz, &fieldCount, &fields);
406 if (error != JVMTI_ERROR_NONE) {
407 outStream_setError(out, map2jdwpError(error));
408 return JNI_TRUE;
409 }
410
411 (void)outStream_writeInt(out, fieldCount);
412 for (i = 0; (i < fieldCount) && !outStream_error(out); i++) {
413 writeFieldInfo(out, clazz, fields[i], outputGenerics);
414 }
415
416 /* Free fields array */
417 if ( fields != NULL ) {
418 jvmtiDeallocate(fields);
419 }
420 return JNI_TRUE;
421 }
422
423
424 static jboolean
fields(PacketInputStream * in,PacketOutputStream * out)425 fields(PacketInputStream *in, PacketOutputStream *out)
426 {
427 return fields1(in, out, 0);
428 }
429
430 static jboolean
fieldsWithGeneric(PacketInputStream * in,PacketOutputStream * out)431 fieldsWithGeneric(PacketInputStream *in, PacketOutputStream *out)
432 {
433 return fields1(in, out, 1);
434
435 }
436
437 static jboolean
getValues(PacketInputStream * in,PacketOutputStream * out)438 getValues(PacketInputStream *in, PacketOutputStream *out)
439 {
440 sharedGetFieldValues(in, out, JNI_TRUE);
441 return JNI_TRUE;
442 }
443
444 static jboolean
sourceFile(PacketInputStream * in,PacketOutputStream * out)445 sourceFile(PacketInputStream *in, PacketOutputStream *out)
446 {
447 char *fileName;
448 jvmtiError error;
449 jclass clazz;
450
451 clazz = inStream_readClassRef(getEnv(), in);
452 if (inStream_error(in)) {
453 return JNI_TRUE;
454 }
455
456 error = JVMTI_FUNC_PTR(gdata->jvmti,GetSourceFileName)
457 (gdata->jvmti, clazz, &fileName);
458 if (error != JVMTI_ERROR_NONE) {
459 outStream_setError(out, map2jdwpError(error));
460 return JNI_TRUE;
461 }
462
463 (void)outStream_writeString(out, fileName);
464 jvmtiDeallocate(fileName);
465 return JNI_TRUE;
466 }
467
468 static jboolean
sourceDebugExtension(PacketInputStream * in,PacketOutputStream * out)469 sourceDebugExtension(PacketInputStream *in, PacketOutputStream *out)
470 {
471 char *extension;
472 jvmtiError error;
473 jclass clazz;
474
475 clazz = inStream_readClassRef(getEnv(), in);
476 if (inStream_error(in)) {
477 return JNI_TRUE;
478 }
479
480 error = getSourceDebugExtension(clazz, &extension);
481 if (error != JVMTI_ERROR_NONE) {
482 outStream_setError(out, map2jdwpError(error));
483 return JNI_TRUE;
484 }
485
486 (void)outStream_writeString(out, extension);
487 jvmtiDeallocate(extension);
488 return JNI_TRUE;
489 }
490
491 static jboolean
nestedTypes(PacketInputStream * in,PacketOutputStream * out)492 nestedTypes(PacketInputStream *in, PacketOutputStream *out)
493 {
494 JNIEnv *env;
495 jclass clazz;
496
497 env = getEnv();
498
499 clazz = inStream_readClassRef(env, in);
500 if (inStream_error(in)) {
501 return JNI_TRUE;
502 }
503
504 WITH_LOCAL_REFS(env, 1) {
505
506 jvmtiError error;
507 jint count;
508 jclass *nested;
509
510 error = allNestedClasses(clazz, &nested, &count);
511 if (error != JVMTI_ERROR_NONE) {
512 outStream_setError(out, map2jdwpError(error));
513 } else {
514 int i;
515 (void)outStream_writeInt(out, count);
516 for (i = 0; i < count; i++) {
517 (void)outStream_writeByte(out, referenceTypeTag(nested[i]));
518 (void)outStream_writeObjectRef(env, out, nested[i]);
519 }
520 if ( nested != NULL ) {
521 jvmtiDeallocate(nested);
522 }
523 }
524
525 } END_WITH_LOCAL_REFS(env);
526
527 return JNI_TRUE;
528 }
529
530 static jboolean
getClassStatus(PacketInputStream * in,PacketOutputStream * out)531 getClassStatus(PacketInputStream *in, PacketOutputStream *out)
532 {
533 jint status;
534 jclass clazz;
535
536 clazz = inStream_readClassRef(getEnv(), in);
537 if (inStream_error(in)) {
538 return JNI_TRUE;
539 }
540
541 status = classStatus(clazz);
542 (void)outStream_writeInt(out, map2jdwpClassStatus(status));
543 return JNI_TRUE;
544 }
545
546 static jboolean
interfaces(PacketInputStream * in,PacketOutputStream * out)547 interfaces(PacketInputStream *in, PacketOutputStream *out)
548 {
549 JNIEnv *env;
550 jclass clazz;
551
552 env = getEnv();
553
554 clazz = inStream_readClassRef(env, in);
555 if (inStream_error(in)) {
556 return JNI_TRUE;
557 }
558
559 WITH_LOCAL_REFS(env, 1) {
560
561 jvmtiError error;
562 jint interfaceCount;
563 jclass *interfaces;
564
565 error = allInterfaces(clazz, &interfaces, &interfaceCount);
566 if (error != JVMTI_ERROR_NONE) {
567 outStream_setError(out, map2jdwpError(error));
568 } else {
569 int i;
570
571 (void)outStream_writeInt(out, interfaceCount);
572 for (i = 0; i < interfaceCount; i++) {
573 (void)outStream_writeObjectRef(env, out, interfaces[i]);
574 }
575 if ( interfaces != NULL ) {
576 jvmtiDeallocate(interfaces);
577 }
578 }
579
580 } END_WITH_LOCAL_REFS(env);
581
582 return JNI_TRUE;
583 }
584
585 static jboolean
classObject(PacketInputStream * in,PacketOutputStream * out)586 classObject(PacketInputStream *in, PacketOutputStream *out)
587 {
588 jclass clazz;
589 JNIEnv *env;
590
591 env = getEnv();
592 clazz = inStream_readClassRef(env, in);
593 if (inStream_error(in)) {
594 return JNI_TRUE;
595 }
596
597 /*
598 * In our implementation, the reference type id is the same as the
599 * class object id, so we bounce it right back.
600 *
601 */
602
603 (void)outStream_writeObjectRef(env, out, clazz);
604
605 return JNI_TRUE;
606 }
607
608 void *ReferenceType_Cmds[] = { (void *)18
609 ,(void *)signature
610 ,(void *)getClassLoader
611 ,(void *)modifiers
612 ,(void *)fields
613 ,(void *)methods
614 ,(void *)getValues
615 ,(void *)sourceFile
616 ,(void *)nestedTypes
617 ,(void *)getClassStatus
618 ,(void *)interfaces
619 ,(void *)classObject
620 ,(void *)sourceDebugExtension
621 ,(void *)signatureWithGeneric
622 ,(void *)fieldsWithGeneric
623 ,(void *)methodsWithGeneric
624 ,(void *)instances
625 ,(void *)getClassVersion
626 ,(void *)getConstantPool
627 };
628