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 
  26 package com.sun.tools.jdi;
  27 
  28 import java.io.ByteArrayOutputStream;
  29 import java.util.ArrayList;
  30 import java.util.List;
  31 
  32 import com.sun.jdi.BooleanValue;
  33 import com.sun.jdi.ByteValue;
  34 import com.sun.jdi.CharValue;
  35 import com.sun.jdi.ClassType;
  36 import com.sun.jdi.DoubleValue;
  37 import com.sun.jdi.Field;
  38 import com.sun.jdi.FloatValue;
  39 import com.sun.jdi.IntegerValue;
  40 import com.sun.jdi.InterfaceType;
  41 import com.sun.jdi.InternalException;
  42 import com.sun.jdi.InvalidTypeException;
  43 import com.sun.jdi.Location;
  44 import com.sun.jdi.LongValue;
  45 import com.sun.jdi.ObjectReference;
  46 import com.sun.jdi.PrimitiveValue;
  47 import com.sun.jdi.ShortValue;
  48 import com.sun.jdi.Value;
  49 
  50 class 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 }