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 
  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 writeFieldRef(long data) {
 158         writeID(vm.sizeofFieldRef, data);
 159     }
 160 
 161     void writeFrameRef(long data) {
 162         writeID(vm.sizeofFrameRef, data);
 163     }
 164 
 165     void writeByteArray(byte[] data) {
 166         dataStream.write(data, 0, data.length);
 167     }
 168 
 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 
 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 
 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 
 205     void writeValueChecked(Value val) throws InvalidTypeException {
 206         writeByte(ValueImpl.typeValueKey(val));
 207         writeUntaggedValue(val);
 208     }
 209 
 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 
 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      */
 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      */
 305     boolean readBoolean() {
 306         byte ret = readByte();
 307         return (ret != 0);
 308     }
 309 
 310     /**
 311      * Read char represented as two bytes.
 312      */
 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      */
 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      */
 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      */
 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      */
 372     float readFloat() {
 373         return Float.intBitsToFloat(readInt());
 374     }
 375 
 376     /**
 377      * Read double represented as eight bytes.
 378      */
 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      */
 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 
 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      */
 417     long readObjectRef() {
 418         return readID(vm.sizeofObjectRef);
 419     }
 420 
 421     long readClassRef() {
 422         return readID(vm.sizeofClassRef);
 423     }
 424 
 425     ObjectReferenceImpl readTaggedObjectReference() {
 426         byte typeKey = readByte();
 427         return vm.objectMirror(readObjectRef(), typeKey);
 428     }
 429 
 430     ObjectReferenceImpl readObjectReference() {
 431         return vm.objectMirror(readObjectRef());
 432     }
 433 
 434     StringReferenceImpl readStringReference() {
 435         long ref = readObjectRef();
 436         return vm.stringMirror(ref);
 437     }
 438 
 439     ArrayReferenceImpl readArrayReference() {
 440         long ref = readObjectRef();
 441         return vm.arrayMirror(ref);
 442     }
 443 
 444     ThreadReferenceImpl readThreadReference() {
 445         long ref = readObjectRef();
 446         return vm.threadMirror(ref);
 447     }
 448 
 449     ThreadGroupReferenceImpl readThreadGroupReference() {
 450         long ref = readObjectRef();
 451         return vm.threadGroupMirror(ref);
 452     }
 453 
 454     ClassLoaderReferenceImpl readClassLoaderReference() {
 455         long ref = readObjectRef();
 456         return vm.classLoaderMirror(ref);
 457     }
 458 
 459     ClassObjectReferenceImpl readClassObjectReference() {
 460         long ref = readObjectRef();
 461         return vm.classObjectMirror(ref);
 462     }
 463 
 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      */
 473     long readMethodRef() {
 474         return readID(vm.sizeofMethodRef);
 475     }
 476 
 477     /**
 478      * Read field reference represented as vm specific byte sequence.
 479      */
 480     long readFieldRef() {
 481         return readID(vm.sizeofFieldRef);
 482     }
 483 
 484     /**
 485      * Read field represented as vm specific byte sequence.
 486      */
 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      */
 496     long readFrameRef() {
 497         return readID(vm.sizeofFrameRef);
 498     }
 499 
 500     /**
 501      * Read a value, first byte describes type of value to read.
 502      */
 503     ValueImpl readValue() {
 504         byte typeKey = readByte();
 505         return readUntaggedValue(typeKey);
 506     }
 507 
 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      */
 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 
 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 
 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 
 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 
 610     int skipBytes(int n) {
 611         inCursor += n;
 612         return n;
 613     }
 614 
 615     byte command() {
 616         return (byte)pkt.cmd;
 617     }
 618 
 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 }