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