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 } 629