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