1/*
2 * Copyright (c) 1998, 2017, 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
26package com.sun.tools.jdi;
27
28import java.io.ByteArrayOutputStream;
29import java.util.ArrayList;
30import java.util.List;
31
32import com.sun.jdi.BooleanValue;
33import com.sun.jdi.ByteValue;
34import com.sun.jdi.CharValue;
35import com.sun.jdi.ClassType;
36import com.sun.jdi.DoubleValue;
37import com.sun.jdi.Field;
38import com.sun.jdi.FloatValue;
39import com.sun.jdi.IntegerValue;
40import com.sun.jdi.InterfaceType;
41import com.sun.jdi.InternalException;
42import com.sun.jdi.InvalidTypeException;
43import com.sun.jdi.Location;
44import com.sun.jdi.LongValue;
45import com.sun.jdi.ObjectReference;
46import com.sun.jdi.PrimitiveValue;
47import com.sun.jdi.ShortValue;
48import com.sun.jdi.Value;
49
50class PacketStream {
51    final VirtualMachineImpl vm;
52    private int inCursor = 0;
53    final Packet pkt;
54    private ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
55    private boolean isCommitted = false;
56
57    PacketStream(VirtualMachineImpl vm, int cmdSet, int cmd) {
58        this.vm = vm;
59        this.pkt = new Packet();
60        pkt.cmdSet = (short)cmdSet;
61        pkt.cmd = (short)cmd;
62    }
63
64    PacketStream(VirtualMachineImpl vm, Packet pkt) {
65        this.vm = vm;
66        this.pkt = pkt;
67        this.isCommitted = true; /* read only stream */
68    }
69
70    int id() {
71        return pkt.id;
72    }
73
74    void send() {
75        if (!isCommitted) {
76            pkt.data = dataStream.toByteArray();
77            vm.sendToTarget(pkt);
78            isCommitted = true;
79        }
80    }
81
82    void waitForReply() throws JDWPException {
83        if (!isCommitted) {
84            throw new InternalException("waitForReply without send");
85        }
86
87        vm.waitForTargetReply(pkt);
88
89        if (pkt.errorCode != Packet.ReplyNoError) {
90            throw new JDWPException(pkt.errorCode);
91        }
92    }
93
94    void writeBoolean(boolean data) {
95        if(data) {
96            dataStream.write( 1 );
97        } else {
98            dataStream.write( 0 );
99        }
100    }
101
102    void writeByte(byte data) {
103        dataStream.write( data );
104    }
105
106    void writeChar(char data) {
107        dataStream.write( (byte)((data >>> 8) & 0xFF) );
108        dataStream.write( (byte)((data >>> 0) & 0xFF) );
109    }
110
111    void writeShort(short data) {
112        dataStream.write( (byte)((data >>> 8) & 0xFF) );
113        dataStream.write( (byte)((data >>> 0) & 0xFF) );
114    }
115
116    void writeInt(int data) {
117        dataStream.write( (byte)((data >>> 24) & 0xFF) );
118        dataStream.write( (byte)((data >>> 16) & 0xFF) );
119        dataStream.write( (byte)((data >>> 8) & 0xFF) );
120        dataStream.write( (byte)((data >>> 0) & 0xFF) );
121    }
122
123    void writeLong(long data) {
124        dataStream.write( (byte)((data >>> 56) & 0xFF) );
125        dataStream.write( (byte)((data >>> 48) & 0xFF) );
126        dataStream.write( (byte)((data >>> 40) & 0xFF) );
127        dataStream.write( (byte)((data >>> 32) & 0xFF) );
128
129        dataStream.write( (byte)((data >>> 24) & 0xFF) );
130        dataStream.write( (byte)((data >>> 16) & 0xFF) );
131        dataStream.write( (byte)((data >>> 8) & 0xFF) );
132        dataStream.write( (byte)((data >>> 0) & 0xFF) );
133    }
134
135    void writeFloat(float data) {
136        writeInt(Float.floatToIntBits(data));
137    }
138
139    void writeDouble(double data) {
140        writeLong(Double.doubleToLongBits(data));
141    }
142
143    void writeID(int size, long data) {
144        switch (size) {
145            case 8:
146                writeLong(data);
147                break;
148            case 4:
149                writeInt((int)data);
150                break;
151            case 2:
152                writeShort((short)data);
153                break;
154            default:
155                throw new UnsupportedOperationException("JDWP: ID size not supported: " + size);
156        }
157    }
158
159    void writeNullObjectRef() {
160        writeObjectRef(0);
161    }
162
163    void writeObjectRef(long data) {
164        writeID(vm.sizeofObjectRef, data);
165    }
166
167    void writeClassRef(long data) {
168        writeID(vm.sizeofClassRef, data);
169    }
170
171    void writeMethodRef(long data) {
172        writeID(vm.sizeofMethodRef, data);
173    }
174
175    void writeModuleRef(long data) {
176        writeID(vm.sizeofModuleRef, data);
177    }
178
179    void writeFieldRef(long data) {
180        writeID(vm.sizeofFieldRef, data);
181    }
182
183    void writeFrameRef(long data) {
184        writeID(vm.sizeofFrameRef, data);
185    }
186
187    void writeByteArray(byte[] data) {
188        dataStream.write(data, 0, data.length);
189    }
190
191    void writeString(String string) {
192        try {
193            byte[] stringBytes = string.getBytes("UTF8");
194            writeInt(stringBytes.length);
195            writeByteArray(stringBytes);
196        } catch (java.io.UnsupportedEncodingException e) {
197            throw new InternalException("Cannot convert string to UTF8 bytes");
198        }
199    }
200
201    void writeLocation(Location location) {
202        ReferenceTypeImpl refType = (ReferenceTypeImpl)location.declaringType();
203        byte tag;
204        if (refType instanceof ClassType) {
205            tag = JDWP.TypeTag.CLASS;
206        } else if (refType instanceof InterfaceType) {
207            // It's possible to have executable code in an interface
208            tag = JDWP.TypeTag.INTERFACE;
209        } else {
210            throw new InternalException("Invalid Location");
211        }
212        writeByte(tag);
213        writeClassRef(refType.ref());
214        writeMethodRef(((MethodImpl)location.method()).ref());
215        writeLong(location.codeIndex());
216    }
217
218    void writeValue(Value val) {
219        try {
220            writeValueChecked(val);
221        } catch (InvalidTypeException exc) {  // should never happen
222            throw new RuntimeException(
223                "Internal error: Invalid Tag/Type pair");
224        }
225    }
226
227    void writeValueChecked(Value val) throws InvalidTypeException {
228        writeByte(ValueImpl.typeValueKey(val));
229        writeUntaggedValue(val);
230    }
231
232    void writeUntaggedValue(Value val) {
233        try {
234            writeUntaggedValueChecked(val);
235        } catch (InvalidTypeException exc) {  // should never happen
236            throw new RuntimeException(
237                "Internal error: Invalid Tag/Type pair");
238        }
239    }
240
241    void writeUntaggedValueChecked(Value val) throws InvalidTypeException {
242        byte tag = ValueImpl.typeValueKey(val);
243        if (isObjectTag(tag)) {
244            if (val == null) {
245                 writeObjectRef(0);
246            } else {
247                if (!(val instanceof ObjectReference)) {
248                    throw new InvalidTypeException();
249                }
250                writeObjectRef(((ObjectReferenceImpl)val).ref());
251            }
252        } else {
253            switch (tag) {
254                case JDWP.Tag.BYTE:
255                    if(!(val instanceof ByteValue))
256                        throw new InvalidTypeException();
257
258                    writeByte(((PrimitiveValue)val).byteValue());
259                    break;
260
261                case JDWP.Tag.CHAR:
262                    if(!(val instanceof CharValue))
263                        throw new InvalidTypeException();
264
265                    writeChar(((PrimitiveValue)val).charValue());
266                    break;
267
268                case JDWP.Tag.FLOAT:
269                    if(!(val instanceof FloatValue))
270                        throw new InvalidTypeException();
271
272                    writeFloat(((PrimitiveValue)val).floatValue());
273                    break;
274
275                case JDWP.Tag.DOUBLE:
276                    if(!(val instanceof DoubleValue))
277                        throw new InvalidTypeException();
278
279                    writeDouble(((PrimitiveValue)val).doubleValue());
280                    break;
281
282                case JDWP.Tag.INT:
283                    if(!(val instanceof IntegerValue))
284                        throw new InvalidTypeException();
285
286                    writeInt(((PrimitiveValue)val).intValue());
287                    break;
288
289                case JDWP.Tag.LONG:
290                    if(!(val instanceof LongValue))
291                        throw new InvalidTypeException();
292
293                    writeLong(((PrimitiveValue)val).longValue());
294                    break;
295
296                case JDWP.Tag.SHORT:
297                    if(!(val instanceof ShortValue))
298                        throw new InvalidTypeException();
299
300                    writeShort(((PrimitiveValue)val).shortValue());
301                    break;
302
303                case JDWP.Tag.BOOLEAN:
304                    if(!(val instanceof BooleanValue))
305                        throw new InvalidTypeException();
306
307                    writeBoolean(((PrimitiveValue)val).booleanValue());
308                    break;
309            }
310        }
311    }
312
313    /**
314     * Read byte represented as one bytes.
315     */
316    byte readByte() {
317        byte ret = pkt.data[inCursor];
318        inCursor += 1;
319        return ret;
320    }
321
322    /**
323     * Read boolean represented as one byte.
324     */
325    boolean readBoolean() {
326        byte ret = readByte();
327        return (ret != 0);
328    }
329
330    /**
331     * Read char represented as two bytes.
332     */
333    char readChar() {
334        int b1, b2;
335
336        b1 = pkt.data[inCursor++] & 0xff;
337        b2 = pkt.data[inCursor++] & 0xff;
338
339        return (char)((b1 << 8) + b2);
340    }
341
342    /**
343     * Read short represented as two bytes.
344     */
345    short readShort() {
346        int b1, b2;
347
348        b1 = pkt.data[inCursor++] & 0xff;
349        b2 = pkt.data[inCursor++] & 0xff;
350
351        return (short)((b1 << 8) + b2);
352    }
353
354    /**
355     * Read int represented as four bytes.
356     */
357    int readInt() {
358        int b1,b2,b3,b4;
359
360        b1 = pkt.data[inCursor++] & 0xff;
361        b2 = pkt.data[inCursor++] & 0xff;
362        b3 = pkt.data[inCursor++] & 0xff;
363        b4 = pkt.data[inCursor++] & 0xff;
364
365        return ((b1 << 24) + (b2 << 16) + (b3 << 8) + b4);
366    }
367
368    /**
369     * Read long represented as eight bytes.
370     */
371    long readLong() {
372        long b1,b2,b3,b4;
373        long b5,b6,b7,b8;
374
375        b1 = pkt.data[inCursor++] & 0xff;
376        b2 = pkt.data[inCursor++] & 0xff;
377        b3 = pkt.data[inCursor++] & 0xff;
378        b4 = pkt.data[inCursor++] & 0xff;
379
380        b5 = pkt.data[inCursor++] & 0xff;
381        b6 = pkt.data[inCursor++] & 0xff;
382        b7 = pkt.data[inCursor++] & 0xff;
383        b8 = pkt.data[inCursor++] & 0xff;
384
385        return ((b1 << 56) + (b2 << 48) + (b3 << 40) + (b4 << 32)
386                + (b5 << 24) + (b6 << 16) + (b7 << 8) + b8);
387    }
388
389    /**
390     * Read float represented as four bytes.
391     */
392    float readFloat() {
393        return Float.intBitsToFloat(readInt());
394    }
395
396    /**
397     * Read double represented as eight bytes.
398     */
399    double readDouble() {
400        return Double.longBitsToDouble(readLong());
401    }
402
403    /**
404     * Read string represented as four byte length followed by
405     * characters of the string.
406     */
407    String readString() {
408        String ret;
409        int len = readInt();
410
411        try {
412            ret = new String(pkt.data, inCursor, len, "UTF8");
413        } catch(java.io.UnsupportedEncodingException e) {
414            System.err.println(e);
415            ret = "Conversion error!";
416        }
417        inCursor += len;
418        return ret;
419    }
420
421    private long readID(int size) {
422        switch (size) {
423          case 8:
424              return readLong();
425          case 4:
426              return readInt();
427          case 2:
428              return readShort();
429          default:
430              throw new UnsupportedOperationException("JDWP: ID size not supported: " + size);
431        }
432    }
433
434    /**
435     * Read object represented as vm specific byte sequence.
436     */
437    long readObjectRef() {
438        return readID(vm.sizeofObjectRef);
439    }
440
441    long readClassRef() {
442        return readID(vm.sizeofClassRef);
443    }
444
445    ObjectReferenceImpl readTaggedObjectReference() {
446        byte typeKey = readByte();
447        return vm.objectMirror(readObjectRef(), typeKey);
448    }
449
450    ObjectReferenceImpl readObjectReference() {
451        return vm.objectMirror(readObjectRef());
452    }
453
454    StringReferenceImpl readStringReference() {
455        long ref = readObjectRef();
456        return vm.stringMirror(ref);
457    }
458
459    ArrayReferenceImpl readArrayReference() {
460        long ref = readObjectRef();
461        return vm.arrayMirror(ref);
462    }
463
464    ThreadReferenceImpl readThreadReference() {
465        long ref = readObjectRef();
466        return vm.threadMirror(ref);
467    }
468
469    ThreadGroupReferenceImpl readThreadGroupReference() {
470        long ref = readObjectRef();
471        return vm.threadGroupMirror(ref);
472    }
473
474    ClassLoaderReferenceImpl readClassLoaderReference() {
475        long ref = readObjectRef();
476        return vm.classLoaderMirror(ref);
477    }
478
479    ClassObjectReferenceImpl readClassObjectReference() {
480        long ref = readObjectRef();
481        return vm.classObjectMirror(ref);
482    }
483
484    ReferenceTypeImpl readReferenceType() {
485        byte tag = readByte();
486        long ref = readObjectRef();
487        return vm.referenceType(ref, tag);
488    }
489
490    ModuleReferenceImpl readModule() {
491        long ref = readModuleRef();
492        return vm.moduleMirror(ref);
493    }
494
495    /**
496     * Read method reference represented as vm specific byte sequence.
497     */
498    long readMethodRef() {
499        return readID(vm.sizeofMethodRef);
500    }
501
502    /**
503     * Read module reference represented as vm specific byte sequence.
504     */
505    long readModuleRef() {
506        return readID(vm.sizeofModuleRef);
507    }
508
509    /**
510     * Read field reference represented as vm specific byte sequence.
511     */
512    long readFieldRef() {
513        return readID(vm.sizeofFieldRef);
514    }
515
516    /**
517     * Read field represented as vm specific byte sequence.
518     */
519    Field readField() {
520        ReferenceTypeImpl refType = readReferenceType();
521        long fieldRef = readFieldRef();
522        return refType.getFieldMirror(fieldRef);
523    }
524
525    /**
526     * Read frame represented as vm specific byte sequence.
527     */
528    long readFrameRef() {
529        return readID(vm.sizeofFrameRef);
530    }
531
532    /**
533     * Read a value, first byte describes type of value to read.
534     */
535    ValueImpl readValue() {
536        byte typeKey = readByte();
537        return readUntaggedValue(typeKey);
538    }
539
540    ValueImpl readUntaggedValue(byte typeKey) {
541        ValueImpl val = null;
542
543        if (isObjectTag(typeKey)) {
544            val = vm.objectMirror(readObjectRef(), typeKey);
545        } else {
546            switch(typeKey) {
547                case JDWP.Tag.BYTE:
548                    val = new ByteValueImpl(vm, readByte());
549                    break;
550
551                case JDWP.Tag.CHAR:
552                    val = new CharValueImpl(vm, readChar());
553                    break;
554
555                case JDWP.Tag.FLOAT:
556                    val = new FloatValueImpl(vm, readFloat());
557                    break;
558
559                case JDWP.Tag.DOUBLE:
560                    val = new DoubleValueImpl(vm, readDouble());
561                    break;
562
563                case JDWP.Tag.INT:
564                    val = new IntegerValueImpl(vm, readInt());
565                    break;
566
567                case JDWP.Tag.LONG:
568                    val = new LongValueImpl(vm, readLong());
569                    break;
570
571                case JDWP.Tag.SHORT:
572                    val = new ShortValueImpl(vm, readShort());
573                    break;
574
575                case JDWP.Tag.BOOLEAN:
576                    val = new BooleanValueImpl(vm, readBoolean());
577                    break;
578
579                case JDWP.Tag.VOID:
580                    val = new VoidValueImpl(vm);
581                    break;
582            }
583        }
584        return val;
585    }
586
587    /**
588     * Read location represented as vm specific byte sequence.
589     */
590    Location readLocation() {
591        byte tag = readByte();
592        long classRef = readObjectRef();
593        long methodRef = readMethodRef();
594        long codeIndex = readLong();
595        if (classRef != 0) {
596            /* Valid location */
597            ReferenceTypeImpl refType = vm.referenceType(classRef, tag);
598            return new LocationImpl(vm, refType, methodRef, codeIndex);
599        } else {
600            /* Null location (example: uncaught exception) */
601           return null;
602        }
603    }
604
605    byte[] readByteArray(int length) {
606        byte[] array = new byte[length];
607        System.arraycopy(pkt.data, inCursor, array, 0, length);
608        inCursor += length;
609        return array;
610    }
611
612    List<Value> readArrayRegion() {
613        byte typeKey = readByte();
614        int length = readInt();
615        List<Value> list = new ArrayList<>(length);
616        boolean gettingObjects = isObjectTag(typeKey);
617        for (int i = 0; i < length; i++) {
618            /*
619             * Each object comes back with a type key which might
620             * identify a more specific type than the type key we
621             * passed in, so we use it in the decodeValue call.
622             * (For primitives, we just use the original one)
623             */
624            if (gettingObjects) {
625                typeKey = readByte();
626            }
627            Value value = readUntaggedValue(typeKey);
628            list.add(value);
629        }
630
631        return list;
632    }
633
634    void writeArrayRegion(List<Value> srcValues) {
635        writeInt(srcValues.size());
636        for (int i = 0; i < srcValues.size(); i++) {
637            Value value = srcValues.get(i);
638            writeUntaggedValue(value);
639        }
640    }
641
642    int skipBytes(int n) {
643        inCursor += n;
644        return n;
645    }
646
647    byte command() {
648        return (byte)pkt.cmd;
649    }
650
651    static boolean isObjectTag(byte tag) {
652        return (tag == JDWP.Tag.OBJECT) ||
653               (tag == JDWP.Tag.ARRAY) ||
654               (tag == JDWP.Tag.STRING) ||
655               (tag == JDWP.Tag.THREAD) ||
656               (tag == JDWP.Tag.THREAD_GROUP) ||
657               (tag == JDWP.Tag.CLASS_LOADER) ||
658               (tag == JDWP.Tag.CLASS_OBJECT);
659    }
660}
661