1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 /** 20 * @author Vitaly A. Provodin 21 */ 22 23 package org.apache.harmony.jpda.tests.framework.jdwp; 24 25 import java.io.IOException; 26 import java.util.ArrayList; 27 import java.util.Iterator; 28 import java.util.List; 29 30 import org.apache.harmony.jpda.tests.framework.Breakpoint; 31 import org.apache.harmony.jpda.tests.framework.LogWriter; 32 import org.apache.harmony.jpda.tests.framework.TestErrorException; 33 import org.apache.harmony.jpda.tests.framework.TestOptions; 34 import org.apache.harmony.jpda.tests.framework.jdwp.Capabilities; 35 import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket; 36 import org.apache.harmony.jpda.tests.framework.jdwp.Event; 37 import org.apache.harmony.jpda.tests.framework.jdwp.EventMod; 38 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants; 39 import org.apache.harmony.jpda.tests.framework.jdwp.Location; 40 import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket; 41 import org.apache.harmony.jpda.tests.framework.jdwp.TransportWrapper; 42 import org.apache.harmony.jpda.tests.framework.jdwp.TypesLengths; 43 import org.apache.harmony.jpda.tests.framework.jdwp.Frame.Variable; 44 import org.apache.harmony.jpda.tests.framework.jdwp.exceptions.ReplyErrorCodeException; 45 import org.apache.harmony.jpda.tests.framework.jdwp.exceptions.TimeoutException; 46 47 /** 48 * This class provides convenient way for communicating with debuggee VM using 49 * JDWP packets. 50 * <p> 51 * Most methods can throw ReplyErrorCodeException if error occurred in execution 52 * of corresponding JDWP command or TestErrorException if any other error 53 * occurred. 54 */ 55 public class VmMirror { 56 57 /** Target VM Capabilities. */ 58 private Capabilities targetVMCapabilities; 59 60 /** Transport used to sent and receive packets. */ 61 private TransportWrapper connection; 62 63 /** PacketDispatcher thread used for asynchronous reading packets. */ 64 private PacketDispatcher packetDispatcher; 65 66 /** Test run options. */ 67 protected TestOptions config; 68 69 /** Log to write messages. */ 70 protected LogWriter logWriter; 71 72 /** 73 * Creates new VmMirror instance for given test run options. 74 * 75 * @param config 76 * test run options 77 * @param logWriter 78 * log writer 79 */ 80 public VmMirror(TestOptions config, LogWriter logWriter) { 81 connection = null; 82 this.config = config; 83 this.logWriter = logWriter; 84 } 85 86 /** 87 * Checks error code of given reply packet and throws 88 * ReplyErrorCodeException if any error detected. 89 * 90 * @param reply 91 * reply packet to check 92 * @return ReplyPacket unchanged reply packet 93 */ 94 public ReplyPacket checkReply(ReplyPacket reply) { 95 if (reply.getErrorCode() != JDWPConstants.Error.NONE) 96 throw new ReplyErrorCodeException(reply.getErrorCode()); 97 return reply; 98 } 99 100 /** 101 * Sets breakpoint to given location with suspend policy ALL. 102 * 103 * @param location 104 * Location of breakpoint 105 * @return ReplyPacket for corresponding command 106 */ 107 public ReplyPacket setBreakpoint(Location location) { 108 return setBreakpoint(location, JDWPConstants.SuspendPolicy.ALL); 109 } 110 111 /** 112 * Sets breakpoint to given location 113 * 114 * @param location 115 * Location of breakpoint 116 * @param suspendPolicy 117 * Suspend policy for a breakpoint being created 118 * @return ReplyPacket for corresponding command 119 */ 120 public ReplyPacket setBreakpoint(Location location, byte suspendPolicy) { 121 Event event = Event.builder(JDWPConstants.EventKind.BREAKPOINT, suspendPolicy) 122 .setLocationOnly(location) 123 .build(); 124 return setEvent(event); 125 } 126 127 /** 128 * Sets breakpoint that triggers only on a certain occurrence to a given 129 * location 130 * 131 * @param typeTag 132 * @param breakpoint 133 * @param suspendPolicy 134 * Suspend policy for a breakpoint being created 135 * @param count 136 * Limit the requested event to be reported at most once after a 137 * given number of occurrences 138 * @return ReplyPacket for corresponding command 139 */ 140 public ReplyPacket setCountableBreakpoint(byte typeTag, 141 Breakpoint breakpoint, byte suspendPolicy, int count) { 142 long typeID = getTypeID(breakpoint.className, typeTag); 143 long methodID = getMethodID(typeID, breakpoint.methodName); 144 145 Event event = Event.builder(JDWPConstants.EventKind.BREAKPOINT, suspendPolicy) 146 .setLocationOnly(new Location(typeTag, typeID, methodID, breakpoint.index)) 147 .setCount(count) 148 .build(); 149 return setEvent(event); 150 } 151 152 /** 153 * Sets breakpoint at the beginning of method with name <i>methodName</i> with suspend policy 154 * ALL. 155 * 156 * @param classID 157 * id of class with required method 158 * @param methodName 159 * name of required method 160 * @return requestID id of request 161 */ 162 public int setBreakpointAtMethodBegin(long classID, String methodName) { 163 return setBreakpointAtMethodBegin(classID, methodName, JDWPConstants.SuspendPolicy.ALL); 164 } 165 166 /** 167 * Sets breakpoint at the beginning of method with name <i>methodName</i>. 168 * 169 * @param classID 170 * id of class with required method 171 * @param methodName 172 * name of required method 173 * @return requestID id of request 174 */ 175 public int setBreakpointAtMethodBegin(long classID, String methodName, byte suspendPolicy) { 176 long methodID = getMethodID(classID, methodName); 177 178 ReplyPacket lineTableReply = getLineTable(classID, methodID); 179 if (lineTableReply.getErrorCode() != JDWPConstants.Error.NONE) { 180 throw new TestErrorException( 181 "Command getLineTable returned error code: " 182 + lineTableReply.getErrorCode() 183 + " - " 184 + JDWPConstants.Error.getName(lineTableReply 185 .getErrorCode())); 186 } 187 188 lineTableReply.getNextValueAsLong(); 189 // Lowest valid code index for the method 190 191 lineTableReply.getNextValueAsLong(); 192 // Highest valid code index for the method 193 194 // int numberOfLines = 195 lineTableReply.getNextValueAsInt(); 196 197 long lineCodeIndex = lineTableReply.getNextValueAsLong(); 198 199 // set breakpoint inside checked method 200 Location breakpointLocation = new Location(JDWPConstants.TypeTag.CLASS, 201 classID, methodID, lineCodeIndex); 202 203 ReplyPacket reply = setBreakpoint(breakpointLocation, suspendPolicy); 204 checkReply(reply); 205 206 return reply.getNextValueAsInt(); 207 } 208 209 /** 210 * Waits for stop on breakpoint and gets id of thread where it stopped. 211 * 212 * @param requestID 213 * id of request for breakpoint 214 * @return threadID id of thread, where we stop on breakpoint 215 */ 216 public long waitForBreakpoint(int requestID) { 217 // receive event 218 CommandPacket event = null; 219 event = receiveEvent(); 220 221 event.getNextValueAsByte(); 222 // suspendPolicy - is not used here 223 224 // int numberOfEvents = 225 event.getNextValueAsInt(); 226 227 long breakpointThreadID = 0; 228 ParsedEvent[] eventParsed = ParsedEvent.parseEventPacket(event); 229 230 if (eventParsed.length != 1) { 231 throw new TestErrorException("Received " + eventParsed.length 232 + " events instead of 1 BREAKPOINT_EVENT"); 233 } 234 235 // check if received event is for breakpoint 236 if (eventParsed[0].getEventKind() == JDWPConstants.EventKind.BREAKPOINT) { 237 breakpointThreadID = ((ParsedEvent.Event_BREAKPOINT) eventParsed[0]) 238 .getThreadID(); 239 240 } else { 241 throw new TestErrorException( 242 "Kind of received event is not BREAKPOINT_EVENT: " 243 + eventParsed[0].getEventKind()); 244 245 } 246 247 if (eventParsed[0].getRequestID() != requestID) { 248 throw new TestErrorException( 249 "Received BREAKPOINT_EVENT with another requestID: " 250 + eventParsed[0].getRequestID()); 251 } 252 253 return breakpointThreadID; 254 } 255 256 /** 257 * Removes breakpoint according to specified requestID. 258 * 259 * @param requestID 260 * for given breakpoint 261 * @return ReplyPacket for corresponding command 262 */ 263 public ReplyPacket clearBreakpoint(int requestID) { 264 265 // Create new command packet 266 CommandPacket commandPacket = new CommandPacket(); 267 268 // Set command. "2" - is ID of Clear command in EventRequest Command Set 269 commandPacket 270 .setCommand(JDWPCommands.EventRequestCommandSet.ClearCommand); 271 272 // Set command set. "15" - is ID of EventRequest Command Set 273 commandPacket 274 .setCommandSet(JDWPCommands.EventRequestCommandSet.CommandSetID); 275 276 // Set outgoing data 277 // Set eventKind 278 commandPacket.setNextValueAsByte(JDWPConstants.EventKind.BREAKPOINT); 279 280 // Set suspendPolicy 281 commandPacket.setNextValueAsInt(requestID); 282 283 // Send packet 284 return checkReply(performCommand(commandPacket)); 285 } 286 287 /** 288 * Removes all breakpoints. 289 * 290 * @return ReplyPacket for corresponding command 291 */ 292 public ReplyPacket ClearAllBreakpoints() { 293 294 // Create new command packet 295 CommandPacket commandPacket = new CommandPacket(); 296 297 // Set command. "3" - is ID of ClearAllBreakpoints command in 298 // EventRequest Command Set 299 commandPacket 300 .setCommand(JDWPCommands.EventRequestCommandSet.ClearAllBreakpointsCommand); 301 302 // Set command set. "15" - is ID of EventRequest Command Set 303 commandPacket 304 .setCommandSet(JDWPCommands.EventRequestCommandSet.CommandSetID); 305 306 // Send packet 307 return checkReply(performCommand(commandPacket)); 308 } 309 310 /** 311 * Requests debuggee VM capabilities. Function parses reply packet of 312 * VirtualMachine::CapabilitiesNew command, creates and fills class 313 * Capabilities with returned info. 314 * 315 * @return ReplyPacket useless, already parsed reply packet. 316 */ 317 public ReplyPacket capabilities() { 318 319 // Create new command packet 320 CommandPacket commandPacket = new CommandPacket(); 321 322 // Set command. "17" - is ID of CapabilitiesNew command in 323 // VirtualMachine Command Set 324 commandPacket 325 .setCommand(JDWPCommands.VirtualMachineCommandSet.CapabilitiesNewCommand); 326 327 // Set command set. "1" - is ID of VirtualMachine Command Set 328 commandPacket 329 .setCommandSet(JDWPCommands.VirtualMachineCommandSet.CommandSetID); 330 331 // Send packet 332 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 333 334 targetVMCapabilities = new Capabilities(); 335 336 // Set capabilities 337 targetVMCapabilities.canWatchFieldModification = replyPacket 338 .getNextValueAsBoolean(); 339 targetVMCapabilities.canWatchFieldAccess = replyPacket 340 .getNextValueAsBoolean(); 341 targetVMCapabilities.canGetBytecodes = replyPacket 342 .getNextValueAsBoolean(); 343 targetVMCapabilities.canGetSyntheticAttribute = replyPacket 344 .getNextValueAsBoolean(); 345 targetVMCapabilities.canGetOwnedMonitorInfo = replyPacket 346 .getNextValueAsBoolean(); 347 targetVMCapabilities.canGetCurrentContendedMonitor = replyPacket 348 .getNextValueAsBoolean(); 349 targetVMCapabilities.canGetMonitorInfo = replyPacket 350 .getNextValueAsBoolean(); 351 targetVMCapabilities.canRedefineClasses = replyPacket 352 .getNextValueAsBoolean(); 353 targetVMCapabilities.canAddMethod = replyPacket.getNextValueAsBoolean(); 354 targetVMCapabilities.canUnrestrictedlyRedefineClasses = replyPacket 355 .getNextValueAsBoolean(); 356 targetVMCapabilities.canPopFrames = replyPacket.getNextValueAsBoolean(); 357 targetVMCapabilities.canUseInstanceFilters = replyPacket 358 .getNextValueAsBoolean(); 359 targetVMCapabilities.canGetSourceDebugExtension = replyPacket 360 .getNextValueAsBoolean(); 361 targetVMCapabilities.canRequestVMDeathEvent = replyPacket 362 .getNextValueAsBoolean(); 363 targetVMCapabilities.canSetDefaultStratum = replyPacket 364 .getNextValueAsBoolean(); 365 targetVMCapabilities.canGetInstanceInfo = replyPacket 366 .getNextValueAsBoolean(); 367 targetVMCapabilities.reserved17 = replyPacket.getNextValueAsBoolean(); 368 targetVMCapabilities.canGetMonitorFrameInfo = replyPacket 369 .getNextValueAsBoolean(); 370 targetVMCapabilities.canUseSourceNameFilters = replyPacket.getNextValueAsBoolean(); 371 targetVMCapabilities.canGetConstantPool = replyPacket 372 .getNextValueAsBoolean(); 373 targetVMCapabilities.canForceEarlyReturn = replyPacket 374 .getNextValueAsBoolean(); 375 targetVMCapabilities.reserved22 = replyPacket.getNextValueAsBoolean(); 376 targetVMCapabilities.reserved23 = replyPacket.getNextValueAsBoolean(); 377 targetVMCapabilities.reserved24 = replyPacket.getNextValueAsBoolean(); 378 targetVMCapabilities.reserved25 = replyPacket.getNextValueAsBoolean(); 379 targetVMCapabilities.reserved26 = replyPacket.getNextValueAsBoolean(); 380 targetVMCapabilities.reserved27 = replyPacket.getNextValueAsBoolean(); 381 targetVMCapabilities.reserved28 = replyPacket.getNextValueAsBoolean(); 382 targetVMCapabilities.reserved29 = replyPacket.getNextValueAsBoolean(); 383 targetVMCapabilities.reserved30 = replyPacket.getNextValueAsBoolean(); 384 targetVMCapabilities.reserved31 = replyPacket.getNextValueAsBoolean(); 385 targetVMCapabilities.reserved32 = replyPacket.getNextValueAsBoolean(); 386 387 return replyPacket; 388 } 389 390 /** 391 * Indicates whether the capability <i>canRedefineClasses</i> is supported. 392 * 393 * @return true if supported, false otherwise. 394 */ 395 public boolean canRedefineClasses() { 396 capabilities(); 397 return targetVMCapabilities.canRedefineClasses; 398 } 399 400 /** 401 * Indicates whether the capability <i>canPopFrames</i> is supported. 402 * 403 * @return true if supported, false otherwise. 404 */ 405 public boolean canPopFrames() { 406 capabilities(); 407 return targetVMCapabilities.canPopFrames; 408 } 409 410 /** 411 * Indicates whether the capability <i>canGetSourceDebugExtension</i> is supported. 412 * 413 * @return true if supported, false otherwise. 414 */ 415 public boolean canGetSourceDebugExtension() { 416 capabilities(); 417 return targetVMCapabilities.canGetSourceDebugExtension; 418 } 419 420 /** 421 * Indicates whether the capability <i>canRequestVMDeathEvent</i> is supported. 422 * 423 * @return true if supported, false otherwise. 424 */ 425 public boolean canRequestVMDeathEvent() { 426 capabilities(); 427 return targetVMCapabilities.canRequestVMDeathEvent; 428 } 429 430 /** 431 * Indicates whether the capability <i>canSetDefaultStratum</i> is supported. 432 * 433 * @return true if supported, false otherwise. 434 */ 435 public boolean canSetDefaultStratum() { 436 capabilities(); 437 return targetVMCapabilities.canSetDefaultStratum; 438 } 439 440 /** 441 * Indicates whether the capability <i>canUseSourceNameFilters</i> is supported. 442 * 443 * @return true if supported, false otherwise. 444 */ 445 public boolean canUseSourceNameFilters() { 446 capabilities(); 447 return targetVMCapabilities.canUseSourceNameFilters; 448 } 449 450 /** 451 * Indicates whether the capability <i>canGetConstantPool</i> is supported. 452 * 453 * @return true if supported, false otherwise. 454 */ 455 public boolean canGetConstantPool() { 456 capabilities(); 457 return targetVMCapabilities.canGetConstantPool; 458 } 459 460 /** 461 * Indicates whether the capability <i>canForceEarlyReturn</i> is supported. 462 * 463 * @return true if supported, false otherwise. 464 */ 465 public boolean canForceEarlyReturn() { 466 capabilities(); 467 return targetVMCapabilities.canForceEarlyReturn; 468 } 469 470 /** 471 * Resumes debuggee VM. 472 * 473 * @return ReplyPacket for corresponding command 474 */ 475 public ReplyPacket resume() { 476 CommandPacket commandPacket = new CommandPacket( 477 JDWPCommands.VirtualMachineCommandSet.CommandSetID, 478 JDWPCommands.VirtualMachineCommandSet.ResumeCommand); 479 480 return checkReply(performCommand(commandPacket)); 481 } 482 483 /** 484 * Resumes specified thread on target Virtual Machine 485 * 486 * @return ReplyPacket for corresponding command 487 */ 488 public ReplyPacket resumeThread(long threadID) { 489 CommandPacket commandPacket = new CommandPacket( 490 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 491 JDWPCommands.ThreadReferenceCommandSet.ResumeCommand); 492 493 commandPacket.setNextValueAsThreadID(threadID); 494 return checkReply(performCommand(commandPacket)); 495 } 496 497 /** 498 * Suspends debuggee VM. 499 * 500 * @return ReplyPacket for corresponding command 501 */ 502 public ReplyPacket suspend() { 503 CommandPacket commandPacket = new CommandPacket( 504 JDWPCommands.VirtualMachineCommandSet.CommandSetID, 505 JDWPCommands.VirtualMachineCommandSet.SuspendCommand); 506 507 return checkReply(performCommand(commandPacket)); 508 } 509 510 /** 511 * Suspends specified thread in debuggee VM. 512 * 513 * @return ReplyPacket for corresponding command 514 */ 515 public ReplyPacket suspendThread(long threadID) { 516 CommandPacket commandPacket = new CommandPacket( 517 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 518 JDWPCommands.ThreadReferenceCommandSet.SuspendCommand); 519 520 commandPacket.setNextValueAsThreadID(threadID); 521 return checkReply(performCommand(commandPacket)); 522 } 523 524 /** 525 * Disposes connection to debuggee VM. 526 * 527 * @return ReplyPacket for corresponding command 528 */ 529 public ReplyPacket dispose() { 530 // Create new command packet 531 CommandPacket commandPacket = new CommandPacket(); 532 commandPacket 533 .setCommand(JDWPCommands.VirtualMachineCommandSet.DisposeCommand); 534 commandPacket 535 .setCommandSet(JDWPCommands.VirtualMachineCommandSet.CommandSetID); 536 537 // Send packet 538 return checkReply(performCommand(commandPacket)); 539 } 540 541 /** 542 * Exits debuggee VM process. 543 * 544 * @return ReplyPacket for corresponding command 545 */ 546 public ReplyPacket exit(int exitCode) { 547 // Create new command packet 548 CommandPacket commandPacket = new CommandPacket(); 549 commandPacket 550 .setCommand(JDWPCommands.VirtualMachineCommandSet.ExitCommand); 551 commandPacket 552 .setCommandSet(JDWPCommands.VirtualMachineCommandSet.CommandSetID); 553 commandPacket.setNextValueAsInt(exitCode); 554 555 // Send packet 556 return checkReply(performCommand(commandPacket)); 557 } 558 559 /** 560 * Adjusts lengths for all VM-specific types. 561 * 562 * @return ReplyPacket for corresponding command 563 */ 564 public ReplyPacket adjustTypeLength() { 565 // Create new command packet 566 CommandPacket commandPacket = new CommandPacket(); 567 commandPacket 568 .setCommand(JDWPCommands.VirtualMachineCommandSet.IDSizesCommand); 569 commandPacket 570 .setCommandSet(JDWPCommands.VirtualMachineCommandSet.CommandSetID); 571 572 // Send packet 573 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 574 575 // Get FieldIDSize from ReplyPacket 576 TypesLengths.setTypeLength(TypesLengths.FIELD_ID, replyPacket 577 .getNextValueAsInt()); 578 579 // Get MethodIDSize from ReplyPacket 580 TypesLengths.setTypeLength(TypesLengths.METHOD_ID, replyPacket 581 .getNextValueAsInt()); 582 583 // Get ObjectIDSize from ReplyPacket 584 TypesLengths.setTypeLength(TypesLengths.OBJECT_ID, replyPacket 585 .getNextValueAsInt()); 586 587 // Get ReferenceTypeIDSize from ReplyPacket 588 TypesLengths.setTypeLength(TypesLengths.REFERENCE_TYPE_ID, replyPacket 589 .getNextValueAsInt()); 590 591 // Get FrameIDSize from ReplyPacket 592 TypesLengths.setTypeLength(TypesLengths.FRAME_ID, replyPacket 593 .getNextValueAsInt()); 594 595 // Adjust all other types lengths 596 TypesLengths.setTypeLength(TypesLengths.ARRAY_ID, TypesLengths 597 .getTypeLength(TypesLengths.OBJECT_ID)); 598 TypesLengths.setTypeLength(TypesLengths.STRING_ID, TypesLengths 599 .getTypeLength(TypesLengths.OBJECT_ID)); 600 TypesLengths.setTypeLength(TypesLengths.THREAD_ID, TypesLengths 601 .getTypeLength(TypesLengths.OBJECT_ID)); 602 TypesLengths.setTypeLength(TypesLengths.THREADGROUP_ID, TypesLengths 603 .getTypeLength(TypesLengths.OBJECT_ID)); 604 TypesLengths.setTypeLength(TypesLengths.LOCATION_ID, TypesLengths 605 .getTypeLength(TypesLengths.OBJECT_ID)); 606 TypesLengths.setTypeLength(TypesLengths.CLASS_ID, TypesLengths 607 .getTypeLength(TypesLengths.OBJECT_ID)); 608 TypesLengths.setTypeLength(TypesLengths.CLASSLOADER_ID, TypesLengths 609 .getTypeLength(TypesLengths.OBJECT_ID)); 610 TypesLengths.setTypeLength(TypesLengths.CLASSOBJECT_ID, TypesLengths 611 .getTypeLength(TypesLengths.OBJECT_ID)); 612 return replyPacket; 613 } 614 615 /** 616 * Gets TypeID for specified type signature and type tag. 617 * 618 * @param typeSignature 619 * type signature 620 * @param classTypeTag 621 * type tag 622 * @return received TypeID 623 */ 624 public long getTypeID(String typeSignature, byte classTypeTag) { 625 int classes = 0; 626 byte refTypeTag = 0; 627 long typeID = -1; 628 629 // Request referenceTypeID for exception 630 ReplyPacket classReference = getClassBySignature(typeSignature); 631 632 // Get referenceTypeID from received packet 633 classes = classReference.getNextValueAsInt(); 634 for (int i = 0; i < classes; i++) { 635 refTypeTag = classReference.getNextValueAsByte(); 636 if (refTypeTag == classTypeTag) { 637 typeID = classReference.getNextValueAsReferenceTypeID(); 638 classReference.getNextValueAsInt(); 639 break; 640 } else { 641 classReference.getNextValueAsReferenceTypeID(); 642 classReference.getNextValueAsInt(); 643 refTypeTag = 0; 644 } 645 } 646 return typeID; 647 } 648 649 /** 650 * Gets ClassID for specified class signature. 651 * 652 * @param classSignature 653 * class signature 654 * @return received ClassID 655 */ 656 public long getClassID(String classSignature) { 657 return getTypeID(classSignature, JDWPConstants.TypeTag.CLASS); 658 } 659 660 /** 661 * Gets ThreadID for specified thread name. 662 * 663 * @param threadName 664 * thread name 665 * @return received ThreadID 666 */ 667 public long getThreadID(String threadName) { 668 ReplyPacket request = null; 669 long threadID = -1; 670 long thread = -1; 671 String name = null; 672 int threads = -1; 673 674 // Get All Threads IDs 675 request = getAllThreadID(); 676 677 // Get thread ID for threadName 678 threads = request.getNextValueAsInt(); 679 for (int i = 0; i < threads; i++) { 680 thread = request.getNextValueAsThreadID(); 681 name = getThreadName(thread); 682 if (threadName.equals(name)) { 683 threadID = thread; 684 break; 685 } 686 } 687 688 return threadID; 689 } 690 691 /** 692 * Returns all running thread IDs. 693 * 694 * @return received reply packet 695 */ 696 public ReplyPacket getAllThreadID() { 697 // Create new command packet 698 CommandPacket commandPacket = new CommandPacket( 699 JDWPCommands.VirtualMachineCommandSet.CommandSetID, 700 JDWPCommands.VirtualMachineCommandSet.AllThreadsCommand); 701 702 return checkReply(performCommand(commandPacket)); 703 } 704 705 /** 706 * Gets class signature for specified class ID. 707 * 708 * @param classID 709 * class ID 710 * @return received class signature 711 */ 712 public String getClassSignature(long classID) { 713 // Create new command packet 714 CommandPacket commandPacket = new CommandPacket( 715 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 716 JDWPCommands.ReferenceTypeCommandSet.SignatureCommand); 717 commandPacket.setNextValueAsReferenceTypeID(classID); 718 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 719 return replyPacket.getNextValueAsString(); 720 } 721 722 /** 723 * Returns thread name for specified <code>threadID</code>. 724 * 725 * @param threadID 726 * thread ID 727 * @return thread name 728 */ 729 public String getThreadName(long threadID) { 730 // Create new command packet 731 CommandPacket commandPacket = new CommandPacket( 732 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 733 JDWPCommands.ThreadReferenceCommandSet.NameCommand); 734 commandPacket.setNextValueAsThreadID(threadID); 735 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 736 return replyPacket.getNextValueAsString(); 737 } 738 739 /** 740 * Returns thread status for specified <code>threadID</code>. 741 * 742 * @param threadID 743 * thread ID 744 * @return thread status 745 */ 746 public int getThreadStatus(long threadID) { 747 CommandPacket commandPacket = new CommandPacket( 748 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 749 JDWPCommands.ThreadReferenceCommandSet.StatusCommand); 750 commandPacket.setNextValueAsThreadID(threadID); 751 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 752 return replyPacket.getNextValueAsInt(); 753 } 754 755 /** 756 * Returns suspend count for specified <code>threadID</code>. 757 * 758 * @param threadID 759 * thread ID 760 * @return thread's suspend count 761 */ 762 public int getThreadSuspendCount(long threadID) { 763 CommandPacket commandPacket = new CommandPacket( 764 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 765 JDWPCommands.ThreadReferenceCommandSet.SuspendCountCommand); 766 commandPacket.setNextValueAsThreadID(threadID); 767 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 768 return replyPacket.getNextValueAsInt(); 769 } 770 771 /** 772 * Returns name of thread group for specified <code>groupID</code> 773 * 774 * @param groupID 775 * thread group ID 776 * 777 * @return name of thread group 778 */ 779 public String getThreadGroupName(long groupID) { 780 // Create new command packet 781 CommandPacket commandPacket = new CommandPacket( 782 JDWPCommands.ThreadGroupReferenceCommandSet.CommandSetID, 783 JDWPCommands.ThreadGroupReferenceCommandSet.NameCommand); 784 commandPacket.setNextValueAsReferenceTypeID(groupID); 785 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 786 return replyPacket.getNextValueAsString(); 787 } 788 789 /** 790 * Gets InterfaceID for specified interface signature. 791 * 792 * @param interfaceSignature 793 * interface signature 794 * @return received ClassID 795 */ 796 public long getInterfaceID(String interfaceSignature) { 797 return getTypeID(interfaceSignature, JDWPConstants.TypeTag.INTERFACE); 798 } 799 800 /** 801 * Gets ArrayID for specified array signature. 802 * 803 * @param arraySignature 804 * array signature 805 * @return received ArrayID 806 */ 807 public long getArrayID(String arraySignature) { 808 return getTypeID(arraySignature, JDWPConstants.TypeTag.INTERFACE); 809 } 810 811 /** 812 * Gets RequestID from specified ReplyPacket. 813 * 814 * @param request 815 * ReplyPacket with RequestID 816 * @return received RequestID 817 */ 818 public int getRequestID(ReplyPacket request) { 819 return request.getNextValueAsInt(); 820 } 821 822 /** 823 * Returns FieldID for specified class and field name. 824 * 825 * @param classID 826 * ClassID to find field 827 * @param fieldName 828 * field name 829 * @return received FieldID 830 */ 831 public long getFieldID(long classID, String fieldName) { 832 ReplyPacket reply = getFieldsInClass(classID); 833 return getFieldID(reply, fieldName); 834 } 835 836 /** 837 * Gets FieldID from ReplyPacket. 838 * 839 * @param request 840 * ReplyPacket for request 841 * @param field 842 * field name to get ID for 843 * @return received FieldID 844 */ 845 public long getFieldID(ReplyPacket request, String field) { 846 long fieldID = -1; 847 String fieldName; 848 // Get fieldID from received packet 849 int count = request.getNextValueAsInt(); 850 for (int i = 0; i < count; i++) { 851 fieldID = request.getNextValueAsFieldID(); 852 fieldName = request.getNextValueAsString(); 853 if (field.equals(fieldName)) { 854 request.getNextValueAsString(); 855 request.getNextValueAsInt(); 856 break; 857 } else { 858 request.getNextValueAsString(); 859 request.getNextValueAsInt(); 860 fieldID = 0; 861 fieldName = null; 862 } 863 } 864 return fieldID; 865 } 866 867 /** 868 * Gets Method ID for specified class and method name. 869 * 870 * @param classID 871 * class to find method 872 * @param methodName 873 * method name 874 * @return received MethodID 875 */ 876 public long getMethodID(long classID, String methodName) { 877 ReplyPacket reply; 878 int declared = 0; 879 String method = null; 880 long methodID = -1; 881 882 // Get Method reference ID 883 reply = getMethods(classID); 884 885 // Get methodID from received packet 886 declared = reply.getNextValueAsInt(); 887 for (int i = 0; i < declared; i++) { 888 methodID = reply.getNextValueAsMethodID(); 889 method = reply.getNextValueAsString(); 890 if (methodName.equals(method)) { 891 // If this method name is the same as requested 892 reply.getNextValueAsString(); 893 reply.getNextValueAsInt(); 894 break; 895 } else { 896 // If this method name is not the requested one 897 reply.getNextValueAsString(); 898 reply.getNextValueAsInt(); 899 methodID = -1; 900 method = null; 901 } 902 } 903 return methodID; 904 } 905 906 /** 907 * Returns method name for specified pair of classID and methodID. 908 * 909 * @param classID 910 * @param methodID 911 * @return method name 912 */ 913 public String getMethodName(long classID, long methodID) { 914 CommandPacket packet = new CommandPacket( 915 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 916 JDWPCommands.ReferenceTypeCommandSet.MethodsCommand); 917 packet.setNextValueAsReferenceTypeID(classID); 918 ReplyPacket reply = performCommand(packet); 919 920 int declared = reply.getNextValueAsInt(); 921 long mID; 922 String value = null; 923 String methodName = ""; 924 for (int i = 0; i < declared; i++) { 925 mID = reply.getNextValueAsMethodID(); 926 methodName = reply.getNextValueAsString(); 927 reply.getNextValueAsString(); 928 reply.getNextValueAsInt(); 929 if (mID == methodID) { 930 value = methodName; 931 break; 932 } 933 } 934 return value; 935 } 936 937 /** 938 * Sets ClassPrepare event request for given class name pattern with suspend policy ALL. 939 * 940 * @param classRegexp 941 * Required class pattern. Matches are limited to exact matches 942 * of the given class pattern and matches of patterns that begin 943 * or end with '*'; for example, "*.Foo" or "java.*". 944 * @return ReplyPacket for setting request. 945 */ 946 public ReplyPacket setClassPrepared(String classRegexp) { 947 return setClassMatchEvent(JDWPConstants.EventKind.CLASS_PREPARE, 948 JDWPConstants.SuspendPolicy.ALL, classRegexp); 949 } 950 951 /** 952 * Set ClassPrepare event request for given class ID with suspend policy ALL. 953 * 954 * @param referenceTypeID 955 * class referenceTypeID 956 * @return ReplyPacket for setting request 957 */ 958 public ReplyPacket setClassPrepared(long referenceTypeID) { 959 return setClassOnlyEvent(JDWPConstants.EventKind.CLASS_PREPARE, 960 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 961 } 962 963 /** 964 * Sets ClassPrepare event request for given source name pattern with suspend policy ALL. 965 * 966 * @param sourceNamePattern 967 * Required source name pattern. Matches are limited to exact matches 968 * of the given source name pattern and matches of patterns that begin 969 * or end with '*'; for example, "*.Foo" or "java.*". 970 * @return ReplyPacket for setting request. 971 */ 972 public ReplyPacket setClassPreparedForSourceNameMatch(String sourceNamePattern) { 973 byte eventKind = JDWPConstants.EventKind.CLASS_PREPARE; 974 byte suspendPolicy = JDWPConstants.SuspendPolicy.ALL; 975 Event event = Event.builder(eventKind, suspendPolicy) 976 .setSourceNameMatch(sourceNamePattern) 977 .build(); 978 return setEvent(event); 979 } 980 981 /** 982 * Sets ClassUnload event request for given class name pattern with suspend policy ALL. 983 * 984 * @param classRegexp 985 * class name pattern 986 * @return ReplyPacket for setting request 987 */ 988 public ReplyPacket setClassUnload(String classRegexp) { 989 return setClassMatchEvent(JDWPConstants.EventKind.CLASS_UNLOAD, 990 JDWPConstants.SuspendPolicy.ALL, classRegexp); 991 } 992 993 /** 994 * Set ClassUnload event request for given class ID with suspend policy ALL. 995 * 996 * @param referenceTypeID 997 * class referenceTypeID 998 * @return ReplyPacket for setting request 999 */ 1000 public ReplyPacket setClassUnload(long referenceTypeID) { 1001 return setClassOnlyEvent(JDWPConstants.EventKind.CLASS_UNLOAD, 1002 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1003 } 1004 1005 /** 1006 * Sets ClassLoad event request for given class signature with suspend policy ALL. 1007 * 1008 * @param classSignature 1009 * class signature 1010 * @return ReplyPacket for setting request 1011 */ 1012 public ReplyPacket setClassLoad(String classSignature) { 1013 long typeID; 1014 1015 // Request referenceTypeID for class 1016 typeID = getClassID(classSignature); 1017 1018 // Set corresponding event 1019 return setClassLoad(typeID); 1020 } 1021 1022 /** 1023 * Set ClassLoad event request for given class ID with suspend policy ALL. 1024 * 1025 * @param referenceTypeID 1026 * class referenceTypeID 1027 * @return ReplyPacket for setting request 1028 */ 1029 public ReplyPacket setClassLoad(long referenceTypeID) { 1030 return setClassOnlyEvent(JDWPConstants.EventKind.CLASS_LOAD, 1031 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1032 } 1033 1034 /** 1035 * Set MonitorContendedEnter event request for given class's reference type 1036 * 1037 * @param referenceTypeID 1038 * class referenceTypeID 1039 * @return ReplyPacket for setting request 1040 */ 1041 public ReplyPacket setMonitorContendedEnterForClassOnly(long referenceTypeID) { 1042 return setClassOnlyEvent(JDWPConstants.EventKind.MONITOR_CONTENDED_ENTER, 1043 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1044 } 1045 1046 /** 1047 * Set MonitorContendedEnter event request for given class's name pattern 1048 * 1049 * @param classRegexp 1050 * class name pattern 1051 * @return ReplyPacket for setting request 1052 */ 1053 public ReplyPacket setMonitorContendedEnterForClassMatch(String classRegexp) { 1054 return setClassMatchEvent(JDWPConstants.EventKind.MONITOR_CONTENDED_ENTER, 1055 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1056 } 1057 1058 /** 1059 * Set MonitorContendedEntered event request for given class's reference type 1060 * 1061 * @param referenceTypeID 1062 * class referenceTypeID 1063 * @return ReplyPacket for setting request 1064 */ 1065 public ReplyPacket setMonitorContendedEnteredForClassOnly(long referenceTypeID) { 1066 return setClassOnlyEvent(JDWPConstants.EventKind.MONITOR_CONTENDED_ENTERED, 1067 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1068 } 1069 1070 /** 1071 * Set MonitorContendedEntered event request for given class's name pattern 1072 * 1073 * @param classRegexp 1074 * class name pattern 1075 * @return ReplyPacket for setting request 1076 */ 1077 public ReplyPacket setMonitorContendedEnteredForClassMatch(String classRegexp) { 1078 return setClassMatchEvent(JDWPConstants.EventKind.MONITOR_CONTENDED_ENTERED, 1079 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1080 } 1081 1082 /** 1083 * Set MonitorWait event request for given class's reference type 1084 * 1085 * @param referenceTypeID 1086 * class referenceTypeID 1087 * @return ReplyPacket for setting request 1088 */ 1089 public ReplyPacket setMonitorWaitForClassOnly(long referenceTypeID) { 1090 return setClassOnlyEvent(JDWPConstants.EventKind.MONITOR_WAIT, 1091 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1092 } 1093 1094 /** 1095 * Set MonitorWait event request for given given class name pattern. 1096 * 1097 * @param classRegexp 1098 * Required class pattern. Matches are limited to exact matches 1099 * of the given class pattern and matches of patterns that begin 1100 * or end with '*'; for example, "*.Foo" or "java.*". 1101 * @return ReplyPacket for setting request. 1102 */ 1103 public ReplyPacket setMonitorWaitForClassMatch(String classRegexp) { 1104 return setClassMatchEvent(JDWPConstants.EventKind.MONITOR_WAIT, 1105 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1106 } 1107 1108 /** 1109 * Set MonitorWait event request for classes 1110 * whose name does not match the given restricted regular expression. 1111 * 1112 * @param classRegexp 1113 * Exclude class pattern. Matches are limited to exact matches 1114 * of the given class pattern and matches of patterns that begin 1115 * or end with '*'; for example, "*.Foo" or "java.*". 1116 * @return ReplyPacket for setting request. 1117 */ 1118 public ReplyPacket setMonitorWaitForClassExclude (String classRegexp) { 1119 return setClassExcludeEvent(JDWPConstants.EventKind.MONITOR_WAIT, 1120 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1121 } 1122 1123 /** 1124 * Set MonitorWaited event request for given class's reference type 1125 * 1126 * @param referenceTypeID 1127 * class referenceTypeID 1128 * @return ReplyPacket for setting request 1129 */ 1130 public ReplyPacket setMonitorWaitedForClassOnly(long referenceTypeID) { 1131 return setClassOnlyEvent(JDWPConstants.EventKind.MONITOR_WAITED, 1132 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1133 } 1134 1135 /** 1136 * Set MonitorWaited event request for given given source name pattern. 1137 * 1138 * @param classRegexp 1139 * Required class pattern. Matches are limited to exact matches 1140 * of the given class pattern and matches of patterns that begin 1141 * or end with '*'; for example, "*.Foo" or "java.*". 1142 * @return ReplyPacket for setting request. 1143 */ 1144 public ReplyPacket setMonitorWaitedForClassMatch(String classRegexp) { 1145 return setClassMatchEvent(JDWPConstants.EventKind.MONITOR_WAITED, 1146 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1147 } 1148 1149 /** 1150 * Set MonitorWaited event request for classes 1151 * whose name does not match the given restricted regular expression. 1152 * 1153 * @param classRegexp 1154 * Required class pattern. Matches are limited to exact matches 1155 * of the given class pattern and matches of patterns that begin 1156 * or end with '*'; for example, "*.Foo" or "java.*". 1157 * @return ReplyPacket for setting request. 1158 */ 1159 public ReplyPacket setMonitorWaitedForClassExclude (String classRegexp) { 1160 return setClassExcludeEvent(JDWPConstants.EventKind.MONITOR_WAITED, 1161 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1162 } 1163 1164 /** 1165 * Set event request for given event. 1166 * 1167 * @param event 1168 * event to set request for 1169 * @return ReplyPacket for setting request 1170 */ 1171 public ReplyPacket setEvent(Event event) { 1172 // Create new command packet 1173 CommandPacket commandPacket = new CommandPacket( 1174 JDWPCommands.EventRequestCommandSet.CommandSetID, 1175 JDWPCommands.EventRequestCommandSet.SetCommand); 1176 1177 // Set eventKind 1178 commandPacket.setNextValueAsByte(event.eventKind); 1179 // Set suspendPolicy 1180 commandPacket.setNextValueAsByte(event.suspendPolicy); 1181 1182 // Set modifiers 1183 commandPacket.setNextValueAsInt(event.mods.size()); 1184 1185 for (EventMod eventModifier : event.mods) { 1186 1187 commandPacket.setNextValueAsByte(eventModifier.modKind); 1188 1189 switch (eventModifier.modKind) { 1190 case EventMod.ModKind.Count: { 1191 // Case Count 1192 commandPacket.setNextValueAsInt(eventModifier.count); 1193 break; 1194 } 1195 case EventMod.ModKind.Conditional: { 1196 // Case Conditional 1197 commandPacket.setNextValueAsInt(eventModifier.exprID); 1198 break; 1199 } 1200 case EventMod.ModKind.ThreadOnly: { 1201 // Case ThreadOnly 1202 commandPacket.setNextValueAsThreadID(eventModifier.thread); 1203 break; 1204 } 1205 case EventMod.ModKind.ClassOnly: { 1206 // Case ClassOnly 1207 commandPacket 1208 .setNextValueAsReferenceTypeID(eventModifier.clazz); 1209 break; 1210 } 1211 case EventMod.ModKind.ClassMatch: { 1212 // Case ClassMatch 1213 commandPacket.setNextValueAsString(eventModifier.classPattern); 1214 break; 1215 } 1216 case EventMod.ModKind.ClassExclude: { 1217 // Case ClassExclude 1218 commandPacket.setNextValueAsString(eventModifier.classPattern); 1219 break; 1220 } 1221 case EventMod.ModKind.LocationOnly: { 1222 // Case LocationOnly 1223 commandPacket.setNextValueAsLocation(eventModifier.loc); 1224 break; 1225 } 1226 case EventMod.ModKind.ExceptionOnly: 1227 // Case ExceptionOnly 1228 commandPacket 1229 .setNextValueAsReferenceTypeID(eventModifier.exceptionOrNull); 1230 commandPacket.setNextValueAsBoolean(eventModifier.caught); 1231 commandPacket.setNextValueAsBoolean(eventModifier.uncaught); 1232 break; 1233 case EventMod.ModKind.FieldOnly: { 1234 // Case FieldOnly 1235 commandPacket 1236 .setNextValueAsReferenceTypeID(eventModifier.declaring); 1237 commandPacket.setNextValueAsFieldID(eventModifier.fieldID); 1238 break; 1239 } 1240 case EventMod.ModKind.Step: { 1241 // Case Step 1242 commandPacket.setNextValueAsThreadID(eventModifier.thread); 1243 commandPacket.setNextValueAsInt(eventModifier.size); 1244 commandPacket.setNextValueAsInt(eventModifier.depth); 1245 break; 1246 } 1247 case EventMod.ModKind.InstanceOnly: { 1248 // Case InstanceOnly 1249 commandPacket.setNextValueAsObjectID(eventModifier.instance); 1250 break; 1251 } 1252 case EventMod.ModKind.SourceNameMatch: { 1253 // Case SourceNameMatch 1254 commandPacket.setNextValueAsString(eventModifier.sourceNamePattern); 1255 } 1256 } 1257 } 1258 1259 // Send packet 1260 return checkReply(performCommand(commandPacket)); 1261 } 1262 1263 /** 1264 * Gets method reference by signature. 1265 * 1266 * @param classReferenceTypeID 1267 * class referenceTypeID. 1268 * @return ReplyPacket for corresponding command 1269 */ 1270 public ReplyPacket getMethods(long classReferenceTypeID) { 1271 // Create new command packet 1272 CommandPacket commandPacket = new CommandPacket(); 1273 1274 // Set command. "5" - is ID of Methods command in ReferenceType Command 1275 // Set 1276 commandPacket 1277 .setCommand(JDWPCommands.ReferenceTypeCommandSet.MethodsCommand); 1278 1279 // Set command set. "2" - is ID of ReferenceType Command Set 1280 commandPacket 1281 .setCommandSet(JDWPCommands.ReferenceTypeCommandSet.CommandSetID); 1282 1283 // Set outgoing data 1284 // Set referenceTypeID 1285 commandPacket.setNextValueAsObjectID(classReferenceTypeID); 1286 1287 // Send packet 1288 return checkReply(performCommand(commandPacket)); 1289 } 1290 1291 /** 1292 * Gets class reference by signature. 1293 * 1294 * @param classSignature 1295 * class signature. 1296 * @return ReplyPacket for corresponding command 1297 */ 1298 public ReplyPacket getClassBySignature(String classSignature) { 1299 CommandPacket commandPacket = new CommandPacket( 1300 JDWPCommands.VirtualMachineCommandSet.CommandSetID, 1301 JDWPCommands.VirtualMachineCommandSet.ClassesBySignatureCommand); 1302 commandPacket.setNextValueAsString(classSignature); 1303 return checkReply(performCommand(commandPacket)); 1304 } 1305 1306 /** 1307 * Gets class fields by class referenceTypeID. 1308 * 1309 * @param referenceTypeID 1310 * class referenceTypeID. 1311 * @return ReplyPacket for corresponding command 1312 */ 1313 public ReplyPacket getFieldsInClass(long referenceTypeID) { 1314 CommandPacket commandPacket = new CommandPacket( 1315 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 1316 JDWPCommands.ReferenceTypeCommandSet.FieldsCommand); 1317 commandPacket.setNextValueAsReferenceTypeID(referenceTypeID); 1318 return checkReply(performCommand(commandPacket)); 1319 } 1320 1321 /** 1322 * Sets exception event request for given exception class signature. 1323 * 1324 * @param exceptionSignature 1325 * exception signature. 1326 * @param caught 1327 * is exception caught 1328 * @param uncaught 1329 * is exception uncaught 1330 * @return ReplyPacket for corresponding command 1331 */ 1332 public ReplyPacket setException(String exceptionSignature, boolean caught, 1333 boolean uncaught) { 1334 // Request referenceTypeID for exception 1335 long typeID = getClassID(exceptionSignature); 1336 return setException(typeID, caught, uncaught); 1337 } 1338 1339 /** 1340 * Sets exception event request for given exception class ID. 1341 * 1342 * @param exceptionID 1343 * exception referenceTypeID. 1344 * @param caught 1345 * is exception caught 1346 * @param uncaught 1347 * is exception uncaught 1348 * @return ReplyPacket for corresponding command 1349 */ 1350 public ReplyPacket setException(long exceptionID, boolean caught, 1351 boolean uncaught) { 1352 byte eventKind = JDWPConstants.EventKind.EXCEPTION; 1353 byte suspendPolicy = JDWPConstants.SuspendPolicy.ALL; 1354 Event event = Event.builder(eventKind, suspendPolicy) 1355 .setExceptionOnly(exceptionID, caught, uncaught) 1356 .build(); 1357 return setEvent(event); 1358 } 1359 1360 /** 1361 * Sets METHOD_ENTRY event request for specified class name pattern. 1362 * 1363 * @param classRegexp 1364 * class name pattern or null for no pattern 1365 * 1366 * @return ReplyPacket for corresponding command 1367 */ 1368 public ReplyPacket setMethodEntry(String classRegexp) { 1369 byte eventKind = JDWPConstants.EventKind.METHOD_ENTRY; 1370 byte suspendPolicy = JDWPConstants.SuspendPolicy.ALL; 1371 EventBuilder builder = Event.builder(eventKind, suspendPolicy); 1372 if (classRegexp != null) { 1373 builder = builder.setClassMatch(classRegexp); 1374 } 1375 Event event = builder.build(); 1376 return setEvent(event); 1377 } 1378 1379 /** 1380 * Sets METHOD_EXIT event request for specified class name pattern. 1381 * 1382 * @param classRegexp 1383 * class name pattern or null for no pattern 1384 * 1385 * @return ReplyPacket for corresponding command 1386 */ 1387 public ReplyPacket setMethodExit(String classRegexp) { 1388 byte eventKind = JDWPConstants.EventKind.METHOD_EXIT; 1389 byte suspendPolicy = JDWPConstants.SuspendPolicy.ALL; 1390 EventBuilder builder = Event.builder(eventKind, suspendPolicy); 1391 if (classRegexp != null) { 1392 builder = builder.setClassMatch(classRegexp); 1393 } 1394 Event event = builder.build(); 1395 return setEvent(event); 1396 } 1397 1398 /** 1399 * Sets METHOD_EXIT_WITH_RETURN_VALUE event request for specified class name pattern. 1400 * 1401 * @param classRegexp 1402 * class name pattern or null for no pattern 1403 * 1404 * @return ReplyPacket for corresponding command 1405 */ 1406 public ReplyPacket setMethodExitWithReturnValue(String classRegexp) { 1407 byte eventKind = JDWPConstants.EventKind.METHOD_EXIT_WITH_RETURN_VALUE; 1408 byte suspendPolicy = JDWPConstants.SuspendPolicy.ALL; 1409 EventBuilder builder = Event.builder(eventKind, suspendPolicy); 1410 if (classRegexp != null) { 1411 builder = builder.setClassMatch(classRegexp); 1412 } 1413 Event event = builder.build(); 1414 return setEvent(event); 1415 } 1416 1417 /** 1418 * Sets field access event request for specified class signature and field 1419 * name. 1420 * 1421 * @param classTypeTag 1422 * class Type Tag (class/interface/array) 1423 * @param classSignature 1424 * class signature 1425 * @param fieldName 1426 * field name 1427 * @return ReplyPacket if breakpoint is set 1428 */ 1429 public ReplyPacket setFieldAccess(String classSignature, byte classTypeTag, 1430 String fieldName) { 1431 // Request referenceTypeID for class 1432 long typeID = getClassID(classSignature); 1433 1434 // Get fieldID from received packet 1435 long fieldID = getFieldID(typeID, fieldName); 1436 1437 byte eventKind = JDWPConstants.EventKind.FIELD_ACCESS; 1438 byte suspendPolicy = JDWPConstants.SuspendPolicy.ALL; 1439 Event event = Event.builder(eventKind, suspendPolicy) 1440 .setFieldOnly(typeID, fieldID) 1441 .build(); 1442 return setEvent(event); 1443 } 1444 1445 /** 1446 * Sets field modification event request for specified class signature and 1447 * field name. 1448 * 1449 * @param classTypeTag 1450 * class Type Tag (class/interface/array) 1451 * @param classSignature 1452 * class signature 1453 * @param fieldName 1454 * field name 1455 * @return ReplyPacket for corresponding command 1456 */ 1457 public ReplyPacket setFieldModification(String classSignature, 1458 byte classTypeTag, String fieldName) { 1459 // Request referenceTypeID for class 1460 long typeID = getClassID(classSignature); 1461 1462 // Get fieldID from received packet 1463 long fieldID = getFieldID(typeID, fieldName); 1464 1465 byte eventKind = JDWPConstants.EventKind.FIELD_MODIFICATION; 1466 byte suspendPolicy = JDWPConstants.SuspendPolicy.ALL; 1467 Event event = Event.builder(eventKind, suspendPolicy) 1468 .setFieldOnly(typeID, fieldID) 1469 .build(); 1470 return setEvent(event); 1471 } 1472 1473 /** 1474 * Sets step event request for given thread ID. 1475 * 1476 * @param threadID 1477 * the ID of the thread 1478 * @param stepSize 1479 * the step size 1480 * @param stepDepth 1481 * the step depth 1482 * @return ReplyPacket for corresponding command 1483 */ 1484 public ReplyPacket setStep(long threadID, int stepSize, int stepDepth) { 1485 byte eventKind = JDWPConstants.EventKind.SINGLE_STEP; 1486 byte suspendPolicy = JDWPConstants.SuspendPolicy.ALL; 1487 Event event = Event.builder(eventKind, suspendPolicy) 1488 .setStep(threadID, stepSize, stepDepth) 1489 .build(); 1490 return setEvent(event); 1491 } 1492 1493 /** 1494 * Sets SINGLE_STEP event request for classes whose name does not match the 1495 * given restricted regular expression 1496 * 1497 * @param classRegexp 1498 * Disallowed class patterns. Matches are limited to exact 1499 * matches of the given class pattern and matches of patterns 1500 * that begin or end with '*'; for example, "*.Foo" or "java.*". 1501 * @param stepSize 1502 * @param stepDepth 1503 * @return ReplyPacket for setting request. 1504 */ 1505 public ReplyPacket setStep(String[] classRegexp, long threadID, 1506 int stepSize, int stepDepth) { 1507 byte eventKind = JDWPConstants.EventKind.SINGLE_STEP; 1508 byte suspendPolicy = JDWPConstants.SuspendPolicy.ALL; 1509 EventBuilder builder = Event.builder(eventKind, suspendPolicy); 1510 for (String pattern : classRegexp) { 1511 builder.setClassExclude(pattern); 1512 } 1513 Event event = builder.setStep(threadID, stepSize, stepDepth).build(); 1514 return setEvent(event); 1515 } 1516 1517 /** 1518 * Sets THREAD_START event request. 1519 * 1520 * @return ReplyPacket for corresponding command 1521 */ 1522 public ReplyPacket setThreadStart(byte suspendPolicy) { 1523 byte eventKind = JDWPConstants.EventKind.THREAD_START; 1524 Event event = Event.builder(eventKind, suspendPolicy).build(); 1525 return setEvent(event); 1526 } 1527 1528 /** 1529 * Sets THREAD_END event request. 1530 * 1531 * @param suspendPolicy the suspend policy 1532 * @return ReplyPacket for corresponding command 1533 */ 1534 public ReplyPacket setThreadEnd(byte suspendPolicy) { 1535 byte eventKind = JDWPConstants.EventKind.THREAD_END; 1536 Event event = Event.builder(eventKind, suspendPolicy).build(); 1537 return setEvent(event); 1538 } 1539 1540 private ReplyPacket setClassOnlyEvent(byte eventKind, byte suspendPolicy, long classId) { 1541 Event event = Event.builder(eventKind, suspendPolicy) 1542 .setClassOnly(classId) 1543 .build(); 1544 return setEvent(event); 1545 } 1546 1547 private ReplyPacket setClassMatchEvent(byte eventKind, byte suspendPolicy, String pattern) { 1548 Event event = Event.builder(eventKind, suspendPolicy) 1549 .setClassMatch(pattern) 1550 .build(); 1551 return setEvent(event); 1552 } 1553 1554 private ReplyPacket setClassExcludeEvent(byte eventKind, byte suspendPolicy, String pattern) { 1555 Event event = Event.builder(eventKind, suspendPolicy) 1556 .setClassExclude(pattern) 1557 .build(); 1558 return setEvent(event); 1559 } 1560 1561 /** 1562 * Clear an event request for specified request ID. 1563 * 1564 * @param eventKind 1565 * event type to clear 1566 * @param requestID 1567 * request ID to clear 1568 * @return ReplyPacket for corresponding command 1569 */ 1570 public ReplyPacket clearEvent(byte eventKind, int requestID) { 1571 // Create new command packet 1572 CommandPacket commandPacket = new CommandPacket(); 1573 1574 // Set command. "2" - is ID of Clear command in EventRequest Command Set 1575 commandPacket 1576 .setCommand(JDWPCommands.EventRequestCommandSet.ClearCommand); 1577 1578 // Set command set. "15" - is ID of EventRequest Command Set 1579 commandPacket 1580 .setCommandSet(JDWPCommands.EventRequestCommandSet.CommandSetID); 1581 1582 // Set outgoing data 1583 // Set event type to clear 1584 commandPacket.setNextValueAsByte(eventKind); 1585 1586 // Set ID of request to clear 1587 commandPacket.setNextValueAsInt(requestID); 1588 1589 // Send packet 1590 return checkReply(performCommand(commandPacket)); 1591 } 1592 1593 /** 1594 * Sends CommandPacket to debuggee VM and waits for ReplyPacket using 1595 * default timeout. All thrown exceptions are wrapped into 1596 * TestErrorException. Consider using checkReply() for checking error code 1597 * in reply packet. 1598 * 1599 * @param command 1600 * Command packet to be sent 1601 * @return received ReplyPacket 1602 */ 1603 public ReplyPacket performCommand(CommandPacket command) 1604 throws TestErrorException { 1605 ReplyPacket replyPacket = null; 1606 try { 1607 replyPacket = packetDispatcher.performCommand(command); 1608 } catch (IOException e) { 1609 throw new TestErrorException(e); 1610 } catch (InterruptedException e) { 1611 throw new TestErrorException(e); 1612 } 1613 1614 return replyPacket; 1615 } 1616 1617 /** 1618 * Sends CommandPacket to debuggee VM and waits for ReplyPacket using 1619 * specified timeout. 1620 * 1621 * @param command 1622 * Command packet to be sent 1623 * @param timeout 1624 * Timeout in milliseconds for waiting reply packet 1625 * @return received ReplyPacket 1626 * @throws InterruptedException 1627 * @throws IOException 1628 * @throws TimeoutException 1629 */ 1630 public ReplyPacket performCommand(CommandPacket command, long timeout) 1631 throws IOException, InterruptedException, TimeoutException { 1632 1633 return packetDispatcher.performCommand(command, timeout); 1634 } 1635 1636 /** 1637 * Sends CommandPacket to debuggee VM without waiting for the reply. This 1638 * method is intended for special cases when there is need to divide 1639 * command's performing into two actions: command's sending and receiving 1640 * reply (e.g. for asynchronous JDWP commands' testing). After this method 1641 * the 'receiveReply()' method must be used latter for receiving reply for 1642 * sent command. It is NOT recommended to use this method for usual cases - 1643 * 'performCommand()' method must be used. 1644 * 1645 * @param command 1646 * Command packet to be sent 1647 * @return command ID of sent command 1648 * @throws IOException 1649 * if any connection error occurred 1650 */ 1651 public int sendCommand(CommandPacket command) throws IOException { 1652 return packetDispatcher.sendCommand(command); 1653 } 1654 1655 /** 1656 * Waits for reply for command which was sent before by 'sendCommand()' 1657 * method. Default timeout is used as time limit for waiting. This method 1658 * (jointly with 'sendCommand()') is intended for special cases when there 1659 * is need to divide command's performing into two actions: command's 1660 * sending and receiving reply (e.g. for asynchronous JDWP commands' 1661 * testing). It is NOT recommended to use 'sendCommand()- receiveReply()' 1662 * pair for usual cases - 'performCommand()' method must be used. 1663 * 1664 * @param commandId 1665 * Command ID of sent before command, reply from which is 1666 * expected to be received 1667 * @return received ReplyPacket 1668 * @throws IOException 1669 * if any connection error occurred 1670 * @throws InterruptedException 1671 * if reply packet's waiting was interrupted 1672 * @throws TimeoutException 1673 * if timeout exceeded 1674 */ 1675 public ReplyPacket receiveReply(int commandId) throws InterruptedException, 1676 IOException, TimeoutException { 1677 return packetDispatcher.receiveReply(commandId, config.getTimeout()); 1678 } 1679 1680 /** 1681 * Waits for reply for command which was sent before by 'sendCommand()' 1682 * method. Specified timeout is used as time limit for waiting. This method 1683 * (jointly with 'sendCommand()') is intended for special cases when there 1684 * is need to divide command's performing into two actions: command's 1685 * sending and receiving reply (e.g. for asynchronous JDWP commands' 1686 * testing). It is NOT recommended to use 'sendCommand()- receiveReply()' 1687 * pair for usual cases - 'performCommand()' method must be used. 1688 * 1689 * @param commandId 1690 * Command ID of sent before command, reply from which is 1691 * expected to be received 1692 * @param timeout 1693 * Specified timeout in milliseconds to wait for reply 1694 * @return received ReplyPacket 1695 * @throws IOException 1696 * if any connection error occurred 1697 * @throws InterruptedException 1698 * if reply packet's waiting was interrupted 1699 * @throws TimeoutException 1700 * if timeout exceeded 1701 */ 1702 public ReplyPacket receiveReply(int commandId, long timeout) 1703 throws InterruptedException, IOException, TimeoutException { 1704 return packetDispatcher.receiveReply(commandId, timeout); 1705 } 1706 1707 /** 1708 * Waits for EventPacket using default timeout. All thrown exceptions are 1709 * wrapped into TestErrorException. 1710 * 1711 * @return received EventPacket 1712 */ 1713 public EventPacket receiveEvent() throws TestErrorException { 1714 try { 1715 return receiveEvent(config.getTimeout()); 1716 } catch (IOException e) { 1717 throw new TestErrorException(e); 1718 } catch (InterruptedException e) { 1719 throw new TestErrorException(e); 1720 } 1721 } 1722 1723 /** 1724 * Waits for EventPacket using specified timeout. 1725 * 1726 * @param timeout 1727 * Timeout in milliseconds to wait for event 1728 * @return received EventPacket 1729 * @throws IOException 1730 * @throws InterruptedException 1731 * @throws TimeoutException 1732 */ 1733 public EventPacket receiveEvent(long timeout) throws IOException, 1734 InterruptedException, TimeoutException { 1735 1736 return packetDispatcher.receiveEvent(timeout); 1737 } 1738 1739 /** 1740 * Waits for expected event kind using default timeout. Throws 1741 * TestErrorException if received event is not of expected kind or not a 1742 * single event in the received event set. 1743 * 1744 * @param eventKind 1745 * Type of expected event - 1746 * @see JDWPConstants.EventKind 1747 * @return received EventPacket 1748 */ 1749 public EventPacket receiveCertainEvent(byte eventKind) 1750 throws TestErrorException { 1751 1752 EventPacket eventPacket = receiveEvent(); 1753 ParsedEvent[] parsedEvents = ParsedEvent.parseEventPacket(eventPacket); 1754 1755 if (parsedEvents.length == 1 1756 && parsedEvents[0].getEventKind() == eventKind) 1757 return eventPacket; 1758 1759 switch (parsedEvents.length) { 1760 case (0): 1761 throw new TestErrorException( 1762 "Unexpected event received: zero length"); 1763 case (1): 1764 throw new TestErrorException("Unexpected event received: " 1765 + "expected " + JDWPConstants.EventKind.getName(eventKind) 1766 + " (" + eventKind + ") but received " 1767 + JDWPConstants.EventKind.getName(parsedEvents[0].getEventKind()) 1768 + " (" + parsedEvents[0].getEventKind() + ")"); 1769 default: 1770 throw new TestErrorException( 1771 "Unexpected event received: Event was grouped in a composite event"); 1772 } 1773 } 1774 1775 /** 1776 * Returns JDWP connection channel used by this VmMirror. 1777 * 1778 * @return connection channel 1779 */ 1780 public TransportWrapper getConnection() { 1781 return connection; 1782 } 1783 1784 /** 1785 * Sets established connection channel to be used with this VmMirror and 1786 * starts reading packets. 1787 * 1788 * @param connection 1789 * connection channel to be set 1790 */ 1791 public void setConnection(TransportWrapper connection) { 1792 this.connection = connection; 1793 packetDispatcher = new PacketDispatcher(connection, config, logWriter); 1794 } 1795 1796 /** 1797 * Closes connection channel used with this VmMirror and stops reading 1798 * packets. 1799 * 1800 */ 1801 public void closeConnection() throws IOException { 1802 if (connection != null && connection.isOpen()) 1803 connection.close(); 1804 1805 // wait for packetDispatcher is closed 1806 if (packetDispatcher != null) { 1807 try { 1808 packetDispatcher.join(); 1809 } catch (InterruptedException e) { 1810 // do nothing but print a stack trace 1811 e.printStackTrace(); 1812 } 1813 } 1814 } 1815 1816 /** 1817 * Returns the count of frames on this thread's stack 1818 * 1819 * @param threadID 1820 * The thread object ID. 1821 * @return The count of frames on this thread's stack 1822 */ 1823 public final int getFrameCount(long threadID) { 1824 CommandPacket command = new CommandPacket( 1825 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 1826 JDWPCommands.ThreadReferenceCommandSet.FrameCountCommand); 1827 command.setNextValueAsThreadID(threadID); 1828 ReplyPacket reply = checkReply(performCommand(command)); 1829 return reply.getNextValueAsInt(); 1830 } 1831 1832 /** 1833 * Returns a list containing all frames of a certain thread 1834 * 1835 * @param threadID 1836 * ID of the thread 1837 * @return A list of frames 1838 */ 1839 public final List<Frame> getAllThreadFrames(long threadID) { 1840 if (!isThreadSuspended(threadID)) { 1841 return new ArrayList<Frame>(0); 1842 } 1843 1844 ReplyPacket reply = getThreadFrames(threadID, 0, -1); 1845 int framesCount = reply.getNextValueAsInt(); 1846 if (framesCount == 0) { 1847 return new ArrayList<Frame>(0); 1848 } 1849 1850 ArrayList<Frame> frames = new ArrayList<Frame>(framesCount); 1851 for (int i = 0; i < framesCount; i++) { 1852 Frame frame = new Frame(); 1853 frame.setThreadID(threadID); 1854 frame.setID(reply.getNextValueAsFrameID()); 1855 frame.setLocation(reply.getNextValueAsLocation()); 1856 frames.add(frame); 1857 } 1858 1859 return frames; 1860 } 1861 1862 /** 1863 * Returns a set of frames of a certain suspended thread 1864 * 1865 * @param threadID 1866 * ID of the thread whose frames to obtain 1867 * @param startIndex 1868 * The index of the first frame to retrieve. 1869 * @param length 1870 * The count of frames to retrieve (-1 means all remaining). 1871 * @return ReplyPacket for corresponding command 1872 */ 1873 public final ReplyPacket getThreadFrames(long threadID, int startIndex, 1874 int length) { 1875 CommandPacket command = new CommandPacket( 1876 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 1877 JDWPCommands.ThreadReferenceCommandSet.FramesCommand); 1878 command.setNextValueAsThreadID(threadID); 1879 command.setNextValueAsInt(startIndex); // start frame's index 1880 command.setNextValueAsInt(length); // get all remaining frames; 1881 return checkReply(performCommand(command)); 1882 } 1883 1884 /** 1885 * Returns variable information for the method 1886 * 1887 * @param classID 1888 * The class ID 1889 * @param methodID 1890 * The method ID 1891 * @return A list containing all variables (arguments and locals) declared 1892 * within the method. 1893 */ 1894 public final List<Variable> getVariableTable(long classID, long methodID) { 1895 CommandPacket command = new CommandPacket( 1896 JDWPCommands.MethodCommandSet.CommandSetID, 1897 JDWPCommands.MethodCommandSet.VariableTableCommand); 1898 command.setNextValueAsReferenceTypeID(classID); 1899 command.setNextValueAsMethodID(methodID); 1900 // ReplyPacket reply = 1901 // debuggeeWrapper.vmMirror.checkReply(debuggeeWrapper.vmMirror.performCommand(command)); 1902 ReplyPacket reply = performCommand(command); 1903 if (reply.getErrorCode() == JDWPConstants.Error.ABSENT_INFORMATION 1904 || reply.getErrorCode() == JDWPConstants.Error.NATIVE_METHOD) { 1905 return null; 1906 } 1907 1908 checkReply(reply); 1909 1910 reply.getNextValueAsInt(); // argCnt, is not used 1911 int slots = reply.getNextValueAsInt(); 1912 if (slots == 0) { 1913 return null; 1914 } 1915 1916 ArrayList<Variable> vars = new ArrayList<Variable>(slots); 1917 for (int i = 0; i < slots; i++) { 1918 Variable var = new Frame().new Variable(); 1919 var.setCodeIndex(reply.getNextValueAsLong()); 1920 var.setName(reply.getNextValueAsString()); 1921 var.setSignature(reply.getNextValueAsString()); 1922 var.setLength(reply.getNextValueAsInt()); 1923 var.setSlot(reply.getNextValueAsInt()); 1924 vars.add(var); 1925 } 1926 1927 return vars; 1928 } 1929 1930 /** 1931 * Returns values of local variables in a given frame 1932 * 1933 * @param frame 1934 * Frame whose variables to get 1935 * @return An array of Value objects 1936 */ 1937 public final Value[] getFrameValues(Frame frame) { 1938 CommandPacket command = new CommandPacket( 1939 JDWPCommands.StackFrameCommandSet.CommandSetID, 1940 JDWPCommands.StackFrameCommandSet.GetValuesCommand); 1941 command.setNextValueAsThreadID(frame.getThreadID()); 1942 command.setNextValueAsFrameID(frame.getID()); 1943 int slots = frame.getVars().size(); 1944 command.setNextValueAsInt(slots); 1945 Iterator<?> it = frame.getVars().iterator(); 1946 while (it.hasNext()) { 1947 Frame.Variable var = (Frame.Variable) it.next(); 1948 command.setNextValueAsInt(var.getSlot()); 1949 command.setNextValueAsByte(var.getTag()); 1950 } 1951 1952 ReplyPacket reply = checkReply(performCommand(command)); 1953 reply.getNextValueAsInt(); // number of values , is not used 1954 Value[] values = new Value[slots]; 1955 for (int i = 0; i < slots; i++) { 1956 values[i] = reply.getNextValueAsValue(); 1957 } 1958 1959 return values; 1960 } 1961 1962 /** 1963 * Returns the immediate superclass of a class 1964 * 1965 * @param classID 1966 * The class ID whose superclass ID is to get 1967 * @return The superclass ID (null if the class ID for java.lang.Object is 1968 * specified). 1969 */ 1970 public final long getSuperclassId(long classID) { 1971 CommandPacket command = new CommandPacket( 1972 JDWPCommands.ClassTypeCommandSet.CommandSetID, 1973 JDWPCommands.ClassTypeCommandSet.SuperclassCommand); 1974 command.setNextValueAsClassID(classID); 1975 ReplyPacket reply = checkReply(performCommand(command)); 1976 return reply.getNextValueAsClassID(); 1977 } 1978 1979 /** 1980 * Returns the runtime type of the object 1981 * 1982 * @param objectID 1983 * The object ID 1984 * @return The runtime reference type. 1985 */ 1986 public final long getReferenceType(long objectID) { 1987 CommandPacket command = new CommandPacket( 1988 JDWPCommands.ObjectReferenceCommandSet.CommandSetID, 1989 JDWPCommands.ObjectReferenceCommandSet.ReferenceTypeCommand); 1990 command.setNextValueAsObjectID(objectID); 1991 ReplyPacket reply = checkReply(performCommand(command)); 1992 reply.getNextValueAsByte(); 1993 return reply.getNextValueAsLong(); 1994 } 1995 1996 /** 1997 * Returns the class object corresponding to this type 1998 * 1999 * @param refType 2000 * The reference type ID. 2001 * @return The class object. 2002 */ 2003 public final long getClassObjectId(long refType) { 2004 CommandPacket command = new CommandPacket( 2005 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 2006 JDWPCommands.ReferenceTypeCommandSet.ClassObjectCommand); 2007 command.setNextValueAsReferenceTypeID(refType); 2008 ReplyPacket reply = checkReply(performCommand(command)); 2009 return reply.getNextValueAsObjectID(); 2010 } 2011 2012 /** 2013 * Returns line number information for the method, if present. 2014 * 2015 * @param refType 2016 * The class ID 2017 * @param methodID 2018 * The method ID 2019 * @return ReplyPacket for corresponding command. 2020 */ 2021 public final ReplyPacket getLineTable(long refType, long methodID) { 2022 CommandPacket command = new CommandPacket( 2023 JDWPCommands.MethodCommandSet.CommandSetID, 2024 JDWPCommands.MethodCommandSet.LineTableCommand); 2025 command.setNextValueAsReferenceTypeID(refType); 2026 command.setNextValueAsMethodID(methodID); 2027 // ReplyPacket reply = 2028 // debuggeeWrapper.vmMirror.checkReply(debuggeeWrapper.vmMirror.performCommand(command)); 2029 // it is impossible to obtain line table information from native 2030 // methods, so reply checking is not performed 2031 ReplyPacket reply = performCommand(command); 2032 if (reply.getErrorCode() != JDWPConstants.Error.NONE) { 2033 if (reply.getErrorCode() == JDWPConstants.Error.NATIVE_METHOD) { 2034 return reply; 2035 } 2036 } 2037 2038 return checkReply(reply); 2039 } 2040 2041 /** 2042 * Returns the value of one or more instance fields. 2043 * 2044 * @param objectID 2045 * The object ID 2046 * @param fieldIDs 2047 * IDs of fields to get 2048 * @return An array of Value objects representing each field's value 2049 */ 2050 public final Value[] getObjectReferenceValues(long objectID, long[] fieldIDs) { 2051 int fieldsCount = fieldIDs.length; 2052 if (fieldsCount == 0) { 2053 return null; 2054 } 2055 2056 CommandPacket command = new CommandPacket( 2057 JDWPCommands.ObjectReferenceCommandSet.CommandSetID, 2058 JDWPCommands.ObjectReferenceCommandSet.GetValuesCommand); 2059 command.setNextValueAsReferenceTypeID(objectID); 2060 command.setNextValueAsInt(fieldsCount); 2061 for (int i = 0; i < fieldsCount; i++) { 2062 command.setNextValueAsFieldID(fieldIDs[i]); 2063 } 2064 2065 ReplyPacket reply = checkReply(performCommand(command)); 2066 reply.getNextValueAsInt(); // fields returned, is not used 2067 Value[] values = new Value[fieldsCount]; 2068 for (int i = 0; i < fieldsCount; i++) { 2069 values[i] = reply.getNextValueAsValue(); 2070 } 2071 2072 return values; 2073 } 2074 2075 /** 2076 * Returns the value of one or more static fields of the reference type 2077 * 2078 * @param refTypeID 2079 * The reference type ID. 2080 * @param fieldIDs 2081 * IDs of fields to get 2082 * @return An array of Value objects representing each field's value 2083 */ 2084 public final Value[] getReferenceTypeValues(long refTypeID, long[] fieldIDs) { 2085 int fieldsCount = fieldIDs.length; 2086 if (fieldsCount == 0) { 2087 return null; 2088 } 2089 2090 CommandPacket command = new CommandPacket( 2091 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 2092 JDWPCommands.ReferenceTypeCommandSet.GetValuesCommand); 2093 command.setNextValueAsReferenceTypeID(refTypeID); 2094 command.setNextValueAsInt(fieldsCount); 2095 for (int i = 0; i < fieldsCount; i++) { 2096 command.setNextValueAsFieldID(fieldIDs[i]); 2097 } 2098 2099 ReplyPacket reply = checkReply(performCommand(command)); 2100 reply.getNextValueAsInt(); // fields returned, is not used 2101 Value[] values = new Value[fieldsCount]; 2102 for (int i = 0; i < fieldsCount; i++) { 2103 values[i] = reply.getNextValueAsValue(); 2104 } 2105 2106 return values; 2107 } 2108 2109 /** 2110 * Returns the value of one static field of the reference type 2111 * 2112 * @param refTypeID 2113 * The reference type ID. 2114 * @param fieldID 2115 * ID of field to get 2116 * @return A Value object representing the field's value 2117 */ 2118 public final Value getReferenceTypeValue(long refTypeID, long fieldID) { 2119 Value[] values = getReferenceTypeValues(refTypeID, new long[]{fieldID}); 2120 return values[0]; 2121 } 2122 2123 /** 2124 * Returns the value of the 'this' reference for this frame 2125 * 2126 * @param threadID 2127 * The frame's thread ID 2128 * @param frameID 2129 * The frame ID. 2130 * @return The 'this' object ID for this frame. 2131 */ 2132 public final long getThisObject(long threadID, long frameID) { 2133 CommandPacket command = new CommandPacket( 2134 JDWPCommands.StackFrameCommandSet.CommandSetID, 2135 JDWPCommands.StackFrameCommandSet.ThisObjectCommand); 2136 command.setNextValueAsThreadID(threadID); 2137 command.setNextValueAsFrameID(frameID); 2138 ReplyPacket reply = checkReply(performCommand(command)); 2139 TaggedObject taggedObject = reply.getNextValueAsTaggedObject(); 2140 return taggedObject.objectID; 2141 } 2142 2143 /** 2144 * Returns information for each field in a reference type including 2145 * inherited fields 2146 * 2147 * @param classID 2148 * The reference type ID 2149 * @return A list of Field objects representing each field of the class 2150 */ 2151 public final List<Field> getAllFields(long classID) { 2152 ArrayList<Field> fields = new ArrayList<Field>(0); 2153 2154 long superID = getSuperclassId(classID); 2155 if (superID != 0) { 2156 List<Field> superClassFields = getAllFields(superID); 2157 for (int i = 0; i < superClassFields.size(); i++) { 2158 fields.add((Field) superClassFields.toArray()[i]); 2159 } 2160 } 2161 2162 ReplyPacket reply = getFieldsInClass(classID); 2163 int fieldsCount = reply.getNextValueAsInt(); 2164 for (int i = 0; i < fieldsCount; i++) { 2165 Field field = new Field(reply.getNextValueAsFieldID(), classID, 2166 reply.getNextValueAsString(), reply.getNextValueAsString(), 2167 reply.getNextValueAsInt()); 2168 fields.add(field); 2169 } 2170 2171 return fields; 2172 } 2173 2174 /** 2175 * Returns the reference type reflected by this class object 2176 * 2177 * @param classObjectID 2178 * The class object ID. 2179 * @return ReplyPacket for corresponding command 2180 */ 2181 public final ReplyPacket getReflectedType(long classObjectID) { 2182 CommandPacket command = new CommandPacket( 2183 JDWPCommands.ClassObjectReferenceCommandSet.CommandSetID, 2184 JDWPCommands.ClassObjectReferenceCommandSet.ReflectedTypeCommand); 2185 command.setNextValueAsClassObjectID(classObjectID); 2186 return checkReply(performCommand(command)); 2187 } 2188 2189 /** 2190 * Returns the JNI signature of a reference type. JNI signature formats are 2191 * described in the Java Native Interface Specification 2192 * 2193 * @param refTypeID 2194 * The reference type ID. 2195 * @return The JNI signature for the reference type. 2196 */ 2197 public final String getReferenceTypeSignature(long refTypeID) { 2198 CommandPacket command = new CommandPacket( 2199 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 2200 JDWPCommands.ReferenceTypeCommandSet.SignatureCommand); 2201 command.setNextValueAsReferenceTypeID(refTypeID); 2202 ReplyPacket reply = checkReply(performCommand(command)); 2203 return reply.getNextValueAsString(); 2204 } 2205 2206 /** 2207 * Returns the thread group that contains a given thread 2208 * 2209 * @param threadID 2210 * The thread object ID. 2211 * @return The thread group ID of this thread. 2212 */ 2213 public final long getThreadGroupID(long threadID) { 2214 CommandPacket command = new CommandPacket( 2215 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 2216 JDWPCommands.ThreadReferenceCommandSet.ThreadGroupCommand); 2217 command.setNextValueAsThreadID(threadID); 2218 ReplyPacket reply = checkReply(performCommand(command)); 2219 return reply.getNextValueAsThreadGroupID(); 2220 } 2221 2222 /** 2223 * Checks whether a given thread is suspended or not 2224 * 2225 * @param threadID 2226 * The thread object ID. 2227 * @return True if a given thread is suspended, false otherwise. 2228 */ 2229 public final boolean isThreadSuspended(long threadID) { 2230 CommandPacket command = new CommandPacket( 2231 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 2232 JDWPCommands.ThreadReferenceCommandSet.StatusCommand); 2233 command.setNextValueAsThreadID(threadID); 2234 ReplyPacket reply = checkReply(performCommand(command)); 2235 reply.getNextValueAsInt(); // the thread's status; is not used 2236 return reply.getNextValueAsInt() == JDWPConstants.SuspendStatus.SUSPEND_STATUS_SUSPENDED; 2237 } 2238 2239 /** 2240 * Returns JNI signature of method. 2241 * 2242 * @param classID 2243 * The reference type ID. 2244 * @param methodID 2245 * The method ID. 2246 * @return JNI signature of method. 2247 */ 2248 public final String getMethodSignature(long classID, long methodID) { 2249 CommandPacket command = new CommandPacket( 2250 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 2251 JDWPCommands.ReferenceTypeCommandSet.MethodsCommand); 2252 command.setNextValueAsReferenceTypeID(classID); 2253 ReplyPacket reply = checkReply(performCommand(command)); 2254 int methods = reply.getNextValueAsInt(); 2255 String value = null; 2256 for (int i = 0; i < methods; i++) { 2257 long mID = reply.getNextValueAsMethodID(); 2258 reply.getNextValueAsString(); // name of the method; is not used 2259 String methodSign = reply.getNextValueAsString(); 2260 reply.getNextValueAsInt(); 2261 if (mID == methodID) { 2262 value = methodSign; 2263 value = value.replaceAll("/", "."); 2264 int lastRoundBracketIndex = value.lastIndexOf(")"); 2265 value = value.substring(0, lastRoundBracketIndex + 1); 2266 break; 2267 } 2268 } 2269 2270 return value; 2271 } 2272 2273 /** 2274 * Returns the characters contained in the string 2275 * 2276 * @param objectID 2277 * The String object ID. 2278 * @return A string value. 2279 */ 2280 public final String getStringValue(long objectID) { 2281 CommandPacket command = new CommandPacket( 2282 JDWPCommands.StringReferenceCommandSet.CommandSetID, 2283 JDWPCommands.StringReferenceCommandSet.ValueCommand); 2284 command.setNextValueAsObjectID(objectID); 2285 ReplyPacket reply = checkReply(performCommand(command)); 2286 return reply.getNextValueAsString(); 2287 } 2288 2289 /** 2290 * Returns a range of array components 2291 * 2292 * @param objectID 2293 * The array object ID. 2294 * @return The retrieved values. 2295 */ 2296 public Value[] getArrayValues(long objectID) { 2297 CommandPacket command = new CommandPacket( 2298 JDWPCommands.ArrayReferenceCommandSet.CommandSetID, 2299 JDWPCommands.ArrayReferenceCommandSet.LengthCommand); 2300 command.setNextValueAsArrayID(objectID); 2301 ReplyPacket reply = checkReply(performCommand(command)); 2302 int length = reply.getNextValueAsInt(); 2303 2304 if (length == 0) { 2305 return null; 2306 } 2307 2308 command = new CommandPacket( 2309 JDWPCommands.ArrayReferenceCommandSet.CommandSetID, 2310 JDWPCommands.ArrayReferenceCommandSet.GetValuesCommand); 2311 command.setNextValueAsArrayID(objectID); 2312 command.setNextValueAsInt(0); 2313 command.setNextValueAsInt(length); 2314 reply = checkReply(performCommand(command)); 2315 ArrayRegion arrayRegion = reply.getNextValueAsArrayRegion(); 2316 2317 Value[] values = new Value[length]; 2318 for (int i = 0; i < length; i++) { 2319 values[i] = arrayRegion.getValue(i); 2320 } 2321 2322 return values; 2323 } 2324 2325 /** 2326 * Returns a source line number according to a corresponding line code index 2327 * in a method's line table. 2328 * 2329 * @param classID 2330 * The class object ID. 2331 * @param methodID 2332 * The method ID. 2333 * @param codeIndex 2334 * The line code index. 2335 * @return An integer line number. 2336 */ 2337 public final int getLineNumber(long classID, long methodID, long codeIndex) { 2338 int lineNumber = -1; 2339 ReplyPacket reply = getLineTable(classID, methodID); 2340 if (reply.getErrorCode() != JDWPConstants.Error.NONE) { 2341 return lineNumber; 2342 } 2343 2344 reply.getNextValueAsLong(); // start line index, is not used 2345 reply.getNextValueAsLong(); // end line index, is not used 2346 int lines = reply.getNextValueAsInt(); 2347 for (int i = 0; i < lines; i++) { 2348 long lineCodeIndex = reply.getNextValueAsLong(); 2349 lineNumber = reply.getNextValueAsInt(); 2350 if (lineCodeIndex == codeIndex) { 2351 break; 2352 } 2353 2354 if (lineCodeIndex > codeIndex) { 2355 --lineNumber; 2356 break; 2357 } 2358 } 2359 2360 return lineNumber; 2361 } 2362 2363 /** 2364 * Returns a line code index according to a corresponding line number in a 2365 * method's line table. 2366 * 2367 * @param classID 2368 * The class object ID. 2369 * @param methodID 2370 * The method ID. 2371 * @param lineNumber 2372 * A source line number. 2373 * @return An integer representing the line code index. 2374 */ 2375 public final long getLineCodeIndex(long classID, long methodID, 2376 int lineNumber) { 2377 ReplyPacket reply = getLineTable(classID, methodID); 2378 if (reply.getErrorCode() != JDWPConstants.Error.NONE) { 2379 return -1L; 2380 } 2381 2382 reply.getNextValueAsLong(); // start line index, is not used 2383 reply.getNextValueAsLong(); // end line index, is not used 2384 int lines = reply.getNextValueAsInt(); 2385 for (int i = 0; i < lines; i++) { 2386 long lineCodeIndex = reply.getNextValueAsLong(); 2387 if (lineNumber == reply.getNextValueAsInt()) { 2388 return lineCodeIndex; 2389 } 2390 } 2391 2392 return -1L; 2393 } 2394 2395 /** 2396 * Returns all variables which are visible within the given frame. 2397 * 2398 * @param frame 2399 * The frame whose visible local variables to retrieve. 2400 * @return A list of Variable objects representing each visible local 2401 * variable within the given frame. 2402 */ 2403 public final List<Variable> getLocalVars(Frame frame) { 2404 List<Variable> vars = getVariableTable(frame.getLocation().classID, frame 2405 .getLocation().methodID); 2406 if (vars == null) { 2407 return null; 2408 } 2409 2410 // All variables that are not visible from within current frame must be 2411 // removed from the list 2412 long frameCodeIndex = frame.getLocation().index; 2413 for (int i = 0; i < vars.size(); i++) { 2414 Variable var = (Variable) vars.toArray()[i]; 2415 long varCodeIndex = var.getCodeIndex(); 2416 if (varCodeIndex > frameCodeIndex 2417 || (frameCodeIndex >= varCodeIndex + var.getLength())) { 2418 vars.remove(i); 2419 --i; 2420 continue; 2421 } 2422 } 2423 2424 return vars; 2425 } 2426 2427 /** 2428 * Sets the value of one or more local variables 2429 * 2430 * @param frame 2431 * The frame ID. 2432 * @param vars 2433 * An array of Variable objects whose values to set 2434 * @param values 2435 * An array of Value objects to set 2436 */ 2437 public final void setLocalVars(Frame frame, Variable[] vars, Value[] values) { 2438 if (vars.length != values.length) { 2439 throw new TestErrorException( 2440 "Number of variables doesn't correspond to number of their values"); 2441 } 2442 2443 CommandPacket command = new CommandPacket( 2444 JDWPCommands.StackFrameCommandSet.CommandSetID, 2445 JDWPCommands.StackFrameCommandSet.SetValuesCommand); 2446 command.setNextValueAsThreadID(frame.getThreadID()); 2447 command.setNextValueAsFrameID(frame.getID()); 2448 command.setNextValueAsInt(vars.length); 2449 for (int i = 0; i < vars.length; i++) { 2450 command.setNextValueAsInt(vars[i].getSlot()); 2451 command.setNextValueAsValue(values[i]); 2452 } 2453 2454 checkReply(performCommand(command)); 2455 } 2456 2457 /** 2458 * Sets the value of one or more instance fields 2459 * 2460 * @param objectID 2461 * The object ID. 2462 * @param fieldIDs 2463 * An array of fields IDs 2464 * @param values 2465 * An array of Value objects representing each value to set 2466 */ 2467 public final void setInstanceFieldsValues(long objectID, long[] fieldIDs, 2468 Value[] values) { 2469 if (fieldIDs.length != values.length) { 2470 throw new TestErrorException( 2471 "Number of fields doesn't correspond to number of their values"); 2472 } 2473 2474 CommandPacket command = new CommandPacket( 2475 JDWPCommands.ObjectReferenceCommandSet.CommandSetID, 2476 JDWPCommands.ObjectReferenceCommandSet.SetValuesCommand); 2477 command.setNextValueAsObjectID(objectID); 2478 command.setNextValueAsInt(fieldIDs.length); 2479 for (int i = 0; i < fieldIDs.length; i++) { 2480 command.setNextValueAsFieldID(fieldIDs[i]); 2481 command.setNextValueAsUntaggedValue(values[i]); 2482 } 2483 2484 checkReply(performCommand(command)); 2485 } 2486 2487 /** 2488 * Sets a range of array components. The specified range must be within the 2489 * bounds of the array. 2490 * 2491 * @param arrayID 2492 * The array object ID. 2493 * @param firstIndex 2494 * The first index to set. 2495 * @param values 2496 * An array of Value objects representing each value to set. 2497 */ 2498 public final void setArrayValues(long arrayID, int firstIndex, 2499 Value[] values) { 2500 CommandPacket command = new CommandPacket( 2501 JDWPCommands.ArrayReferenceCommandSet.CommandSetID, 2502 JDWPCommands.ArrayReferenceCommandSet.SetValuesCommand); 2503 command.setNextValueAsArrayID(arrayID); 2504 command.setNextValueAsInt(firstIndex); 2505 command.setNextValueAsInt(values.length); 2506 for (int i = 0; i < values.length; i++) { 2507 command.setNextValueAsUntaggedValue(values[i]); 2508 } 2509 2510 checkReply(performCommand(command)); 2511 } 2512 2513 /** 2514 * Sets the value of one or more static fields 2515 * 2516 * @param classID 2517 * The class type ID. 2518 * @param fieldIDs 2519 * An array of fields IDs 2520 * @param values 2521 * An array of Value objects representing each value to set 2522 */ 2523 public final void setStaticFieldsValues(long classID, long[] fieldIDs, 2524 Value[] values) { 2525 if (fieldIDs.length != values.length) { 2526 throw new TestErrorException( 2527 "Number of fields doesn't correspond to number of their values"); 2528 } 2529 2530 CommandPacket command = new CommandPacket( 2531 JDWPCommands.ClassTypeCommandSet.CommandSetID, 2532 JDWPCommands.ClassTypeCommandSet.SetValuesCommand); 2533 command.setNextValueAsClassID(classID); 2534 command.setNextValueAsInt(fieldIDs.length); 2535 for (int i = 0; i < fieldIDs.length; i++) { 2536 command.setNextValueAsFieldID(fieldIDs[i]); 2537 command.setNextValueAsUntaggedValue(values[i]); 2538 } 2539 2540 checkReply(performCommand(command)); 2541 } 2542 2543 /** 2544 * Creates java String in target VM with the given value. 2545 * 2546 * @param value 2547 * The value of the string. 2548 * @return The string id. 2549 */ 2550 public final long createString(String value) { 2551 CommandPacket command = new CommandPacket( 2552 JDWPCommands.VirtualMachineCommandSet.CommandSetID, 2553 JDWPCommands.VirtualMachineCommandSet.CreateStringCommand); 2554 command.setNextValueAsString(value); 2555 ReplyPacket reply = checkReply(performCommand(command)); 2556 return reply.getNextValueAsStringID(); 2557 } 2558 2559 /** 2560 * Processes JDWP PopFrames command from StackFrame command set. 2561 * 2562 * @param frame 2563 * The instance of Frame. 2564 */ 2565 public final void popFrame(Frame frame) { 2566 CommandPacket command = new CommandPacket( 2567 JDWPCommands.StackFrameCommandSet.CommandSetID, 2568 JDWPCommands.StackFrameCommandSet.PopFramesCommand); 2569 command.setNextValueAsThreadID(frame.getThreadID()); 2570 command.setNextValueAsFrameID(frame.getID()); 2571 checkReply(performCommand(command)); 2572 } 2573 2574 /** 2575 * Invokes a member method of the given object. 2576 * 2577 * @param objectID 2578 * The object ID. 2579 * @param threadID 2580 * The thread ID. 2581 * @param methodName 2582 * The name of method for the invocation. 2583 * @param args 2584 * The arguments for the invocation. 2585 * @param options 2586 * The invocation options. 2587 * @return ReplyPacket for corresponding command 2588 */ 2589 public final ReplyPacket invokeInstanceMethod(long objectID, long threadID, 2590 String methodName, Value[] args, int options) { 2591 long classID = getReferenceType(objectID); 2592 long methodID = getMethodID(classID, methodName); 2593 CommandPacket command = new CommandPacket( 2594 JDWPCommands.ObjectReferenceCommandSet.CommandSetID, 2595 JDWPCommands.ObjectReferenceCommandSet.InvokeMethodCommand); 2596 command.setNextValueAsObjectID(objectID); 2597 command.setNextValueAsThreadID(threadID); 2598 command.setNextValueAsClassID(classID); 2599 command.setNextValueAsMethodID(methodID); 2600 command.setNextValueAsInt(args.length); 2601 for (int i = 0; i < args.length; i++) { 2602 command.setNextValueAsValue(args[i]); 2603 } 2604 command.setNextValueAsInt(options); 2605 2606 return checkReply(performCommand(command)); 2607 } 2608 2609 /** 2610 * Invokes a static method of the given class. 2611 * 2612 * @param classID 2613 * The class type ID. 2614 * @param threadID 2615 * The thread ID. 2616 * @param methodName 2617 * The name of method for the invocation. 2618 * @param args 2619 * The arguments for the invocation. 2620 * @param options 2621 * The invocation options. 2622 * @return ReplyPacket for corresponding command 2623 */ 2624 public final ReplyPacket invokeStaticMethod(long classID, long threadID, 2625 String methodName, Value[] args, int options) { 2626 long methodID = getMethodID(classID, methodName); 2627 CommandPacket command = new CommandPacket( 2628 JDWPCommands.ClassTypeCommandSet.CommandSetID, 2629 JDWPCommands.ClassTypeCommandSet.InvokeMethodCommand); 2630 command.setNextValueAsClassID(classID); 2631 command.setNextValueAsThreadID(threadID); 2632 command.setNextValueAsMethodID(methodID); 2633 command.setNextValueAsInt(args.length); 2634 for (int i = 0; i < args.length; i++) { 2635 command.setNextValueAsValue(args[i]); 2636 } 2637 command.setNextValueAsInt(options); 2638 2639 return checkReply(performCommand(command)); 2640 } 2641 } 2642