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