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