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 * Indicates whether the non-standard capability <i>canRedefineDexClasses</i> is supported. 472 * 473 * @return true if supported, false otherwise. 474 */ 475 public boolean canRedefineDexClasses() { 476 capabilities(); 477 // This unused capability is used by android libjdwp agents to say if they can redefine 478 // classes using (single class) DEX files. 479 return targetVMCapabilities.reserved32; 480 } 481 482 /** 483 * Resumes debuggee VM. 484 * 485 * @return ReplyPacket for corresponding command 486 */ 487 public ReplyPacket resume() { 488 CommandPacket commandPacket = new CommandPacket( 489 JDWPCommands.VirtualMachineCommandSet.CommandSetID, 490 JDWPCommands.VirtualMachineCommandSet.ResumeCommand); 491 492 return checkReply(performCommand(commandPacket)); 493 } 494 495 /** 496 * Resumes specified thread on target Virtual Machine 497 * 498 * @return ReplyPacket for corresponding command 499 */ 500 public ReplyPacket resumeThread(long threadID) { 501 CommandPacket commandPacket = new CommandPacket( 502 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 503 JDWPCommands.ThreadReferenceCommandSet.ResumeCommand); 504 505 commandPacket.setNextValueAsThreadID(threadID); 506 return checkReply(performCommand(commandPacket)); 507 } 508 509 /** 510 * Suspends debuggee VM. 511 * 512 * @return ReplyPacket for corresponding command 513 */ 514 public ReplyPacket suspend() { 515 CommandPacket commandPacket = new CommandPacket( 516 JDWPCommands.VirtualMachineCommandSet.CommandSetID, 517 JDWPCommands.VirtualMachineCommandSet.SuspendCommand); 518 519 return checkReply(performCommand(commandPacket)); 520 } 521 522 /** 523 * Suspends specified thread in debuggee VM. 524 * 525 * @return ReplyPacket for corresponding command 526 */ 527 public ReplyPacket suspendThread(long threadID) { 528 CommandPacket commandPacket = new CommandPacket( 529 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 530 JDWPCommands.ThreadReferenceCommandSet.SuspendCommand); 531 532 commandPacket.setNextValueAsThreadID(threadID); 533 return checkReply(performCommand(commandPacket)); 534 } 535 536 /** 537 * Disposes connection to debuggee VM. 538 * 539 * @return ReplyPacket for corresponding command 540 */ 541 public ReplyPacket dispose() { 542 // Create new command packet 543 CommandPacket commandPacket = new CommandPacket(); 544 commandPacket 545 .setCommand(JDWPCommands.VirtualMachineCommandSet.DisposeCommand); 546 commandPacket 547 .setCommandSet(JDWPCommands.VirtualMachineCommandSet.CommandSetID); 548 549 // Send packet 550 return checkReply(performCommand(commandPacket)); 551 } 552 553 /** 554 * Exits debuggee VM process. 555 * 556 * @return ReplyPacket for corresponding command 557 */ 558 public ReplyPacket exit(int exitCode) { 559 // Create new command packet 560 CommandPacket commandPacket = new CommandPacket(); 561 commandPacket 562 .setCommand(JDWPCommands.VirtualMachineCommandSet.ExitCommand); 563 commandPacket 564 .setCommandSet(JDWPCommands.VirtualMachineCommandSet.CommandSetID); 565 commandPacket.setNextValueAsInt(exitCode); 566 567 // Send packet 568 return checkReply(performCommand(commandPacket)); 569 } 570 571 /** 572 * Adjusts lengths for all VM-specific types. 573 * 574 * @return ReplyPacket for corresponding command 575 */ 576 public ReplyPacket adjustTypeLength() { 577 // Create new command packet 578 CommandPacket commandPacket = new CommandPacket(); 579 commandPacket 580 .setCommand(JDWPCommands.VirtualMachineCommandSet.IDSizesCommand); 581 commandPacket 582 .setCommandSet(JDWPCommands.VirtualMachineCommandSet.CommandSetID); 583 584 // Send packet 585 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 586 587 // Get FieldIDSize from ReplyPacket 588 TypesLengths.setTypeLength(TypesLengths.FIELD_ID, replyPacket 589 .getNextValueAsInt()); 590 591 // Get MethodIDSize from ReplyPacket 592 TypesLengths.setTypeLength(TypesLengths.METHOD_ID, replyPacket 593 .getNextValueAsInt()); 594 595 // Get ObjectIDSize from ReplyPacket 596 TypesLengths.setTypeLength(TypesLengths.OBJECT_ID, replyPacket 597 .getNextValueAsInt()); 598 599 // Get ReferenceTypeIDSize from ReplyPacket 600 TypesLengths.setTypeLength(TypesLengths.REFERENCE_TYPE_ID, replyPacket 601 .getNextValueAsInt()); 602 603 // Get FrameIDSize from ReplyPacket 604 TypesLengths.setTypeLength(TypesLengths.FRAME_ID, replyPacket 605 .getNextValueAsInt()); 606 607 // Adjust all other types lengths 608 TypesLengths.setTypeLength(TypesLengths.ARRAY_ID, TypesLengths 609 .getTypeLength(TypesLengths.OBJECT_ID)); 610 TypesLengths.setTypeLength(TypesLengths.STRING_ID, TypesLengths 611 .getTypeLength(TypesLengths.OBJECT_ID)); 612 TypesLengths.setTypeLength(TypesLengths.THREAD_ID, TypesLengths 613 .getTypeLength(TypesLengths.OBJECT_ID)); 614 TypesLengths.setTypeLength(TypesLengths.THREADGROUP_ID, TypesLengths 615 .getTypeLength(TypesLengths.OBJECT_ID)); 616 TypesLengths.setTypeLength(TypesLengths.LOCATION_ID, TypesLengths 617 .getTypeLength(TypesLengths.OBJECT_ID)); 618 TypesLengths.setTypeLength(TypesLengths.CLASS_ID, TypesLengths 619 .getTypeLength(TypesLengths.OBJECT_ID)); 620 TypesLengths.setTypeLength(TypesLengths.CLASSLOADER_ID, TypesLengths 621 .getTypeLength(TypesLengths.OBJECT_ID)); 622 TypesLengths.setTypeLength(TypesLengths.CLASSOBJECT_ID, TypesLengths 623 .getTypeLength(TypesLengths.OBJECT_ID)); 624 return replyPacket; 625 } 626 627 /** 628 * Gets TypeID for specified type signature and type tag. 629 * 630 * @param typeSignature 631 * type signature 632 * @param classTypeTag 633 * type tag 634 * @return received TypeID 635 */ 636 public long getTypeID(String typeSignature, byte classTypeTag) { 637 int classes = 0; 638 byte refTypeTag = 0; 639 long typeID = -1; 640 641 // Request referenceTypeID for exception 642 ReplyPacket classReference = getClassBySignature(typeSignature); 643 644 // Get referenceTypeID from received packet 645 classes = classReference.getNextValueAsInt(); 646 for (int i = 0; i < classes; i++) { 647 refTypeTag = classReference.getNextValueAsByte(); 648 if (refTypeTag == classTypeTag) { 649 typeID = classReference.getNextValueAsReferenceTypeID(); 650 classReference.getNextValueAsInt(); 651 break; 652 } else { 653 classReference.getNextValueAsReferenceTypeID(); 654 classReference.getNextValueAsInt(); 655 refTypeTag = 0; 656 } 657 } 658 return typeID; 659 } 660 661 /** 662 * Gets ClassID for specified class signature. 663 * 664 * @param classSignature 665 * class signature 666 * @return received ClassID 667 */ 668 public long getClassID(String classSignature) { 669 return getTypeID(classSignature, JDWPConstants.TypeTag.CLASS); 670 } 671 672 /** 673 * Gets ThreadID for specified thread name. 674 * 675 * @param threadName 676 * thread name 677 * @return received ThreadID 678 */ 679 public long getThreadID(String threadName) { 680 ReplyPacket request = null; 681 long threadID = -1; 682 long thread = -1; 683 String name = null; 684 int threads = -1; 685 686 // Get All Threads IDs 687 request = getAllThreadID(); 688 689 // Get thread ID for threadName 690 threads = request.getNextValueAsInt(); 691 for (int i = 0; i < threads; i++) { 692 thread = request.getNextValueAsThreadID(); 693 name = getThreadName(thread); 694 if (threadName.equals(name)) { 695 threadID = thread; 696 break; 697 } 698 } 699 700 return threadID; 701 } 702 703 /** 704 * Returns all running thread IDs. 705 * 706 * @return received reply packet 707 */ 708 public ReplyPacket getAllThreadID() { 709 // Create new command packet 710 CommandPacket commandPacket = new CommandPacket( 711 JDWPCommands.VirtualMachineCommandSet.CommandSetID, 712 JDWPCommands.VirtualMachineCommandSet.AllThreadsCommand); 713 714 return checkReply(performCommand(commandPacket)); 715 } 716 717 /** 718 * Gets class signature for specified class ID. 719 * 720 * @param classID 721 * class ID 722 * @return received class signature 723 */ 724 public String getClassSignature(long classID) { 725 // Create new command packet 726 CommandPacket commandPacket = new CommandPacket( 727 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 728 JDWPCommands.ReferenceTypeCommandSet.SignatureCommand); 729 commandPacket.setNextValueAsReferenceTypeID(classID); 730 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 731 return replyPacket.getNextValueAsString(); 732 } 733 734 /** 735 * Returns thread name for specified <code>threadID</code>. 736 * 737 * @param threadID 738 * thread ID 739 * @return thread name 740 */ 741 public String getThreadName(long threadID) { 742 // Create new command packet 743 CommandPacket commandPacket = new CommandPacket( 744 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 745 JDWPCommands.ThreadReferenceCommandSet.NameCommand); 746 commandPacket.setNextValueAsThreadID(threadID); 747 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 748 return replyPacket.getNextValueAsString(); 749 } 750 751 /** 752 * Returns thread status for specified <code>threadID</code>. 753 * 754 * @param threadID 755 * thread ID 756 * @return thread status 757 */ 758 public int getThreadStatus(long threadID) { 759 CommandPacket commandPacket = new CommandPacket( 760 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 761 JDWPCommands.ThreadReferenceCommandSet.StatusCommand); 762 commandPacket.setNextValueAsThreadID(threadID); 763 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 764 return replyPacket.getNextValueAsInt(); 765 } 766 767 /** 768 * Returns suspend count for specified <code>threadID</code>. 769 * 770 * @param threadID 771 * thread ID 772 * @return thread's suspend count 773 */ 774 public int getThreadSuspendCount(long threadID) { 775 CommandPacket commandPacket = new CommandPacket( 776 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 777 JDWPCommands.ThreadReferenceCommandSet.SuspendCountCommand); 778 commandPacket.setNextValueAsThreadID(threadID); 779 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 780 return replyPacket.getNextValueAsInt(); 781 } 782 783 /** 784 * Returns name of thread group for specified <code>groupID</code> 785 * 786 * @param groupID 787 * thread group ID 788 * 789 * @return name of thread group 790 */ 791 public String getThreadGroupName(long groupID) { 792 // Create new command packet 793 CommandPacket commandPacket = new CommandPacket( 794 JDWPCommands.ThreadGroupReferenceCommandSet.CommandSetID, 795 JDWPCommands.ThreadGroupReferenceCommandSet.NameCommand); 796 commandPacket.setNextValueAsReferenceTypeID(groupID); 797 ReplyPacket replyPacket = checkReply(performCommand(commandPacket)); 798 return replyPacket.getNextValueAsString(); 799 } 800 801 /** 802 * Gets InterfaceID for specified interface signature. 803 * 804 * @param interfaceSignature 805 * interface signature 806 * @return received ClassID 807 */ 808 public long getInterfaceID(String interfaceSignature) { 809 return getTypeID(interfaceSignature, JDWPConstants.TypeTag.INTERFACE); 810 } 811 812 /** 813 * Gets ArrayID for specified array signature. 814 * 815 * @param arraySignature 816 * array signature 817 * @return received ArrayID 818 */ 819 public long getArrayID(String arraySignature) { 820 return getTypeID(arraySignature, JDWPConstants.TypeTag.INTERFACE); 821 } 822 823 /** 824 * Gets RequestID from specified ReplyPacket. 825 * 826 * @param request 827 * ReplyPacket with RequestID 828 * @return received RequestID 829 */ 830 public int getRequestID(ReplyPacket request) { 831 return request.getNextValueAsInt(); 832 } 833 834 /** 835 * Returns FieldID for specified class and field name. 836 * 837 * @param classID 838 * ClassID to find field 839 * @param fieldName 840 * field name 841 * @return received FieldID 842 */ 843 public long getFieldID(long classID, String fieldName) { 844 Field[] fields = getFieldsInfo(classID); 845 for (Field field : fields) { 846 if (field.getName().equals(fieldName)) { 847 return field.getFieldID(); 848 } 849 } 850 return -1; 851 } 852 853 /** 854 * Gets Method ID for specified class and method name. 855 * 856 * @param classID 857 * class to find method 858 * @param methodName 859 * method name 860 * @return received MethodID 861 */ 862 public long getMethodID(long classID, String methodName) { 863 // Only take method name into account. 864 return getMethodID(classID, methodName, null); 865 } 866 867 /** 868 * Gets Method ID for specified class, method name and signature. 869 * 870 * @param classID 871 * class to find method 872 * @param methodName 873 * method name 874 * @param methodSignature 875 * method signature 876 * @return received MethodID 877 */ 878 public long getMethodID(long classID, String methodName, String methodSignature) { 879 Method[] methods = getMethods(classID); 880 for (Method method : methods) { 881 if (method.getName().equals(methodName)) { 882 if (methodSignature == null || method.getSignature().equals(methodSignature)) { 883 return method.getMethodID(); 884 } 885 } 886 } 887 return -1; 888 } 889 890 /** 891 * Returns method name for specified pair of classID and methodID. 892 * 893 * @param classID 894 * @param methodID 895 * @return method name 896 */ 897 public String getMethodName(long classID, long methodID) { 898 Method[] methods = getMethods(classID); 899 for (Method method : methods) { 900 if (methodID == method.getMethodID()) { 901 return method.getName(); 902 } 903 } 904 return "unknown"; 905 } 906 907 /** 908 * Sets ClassPrepare event request for given class name pattern with suspend policy ALL. 909 * 910 * @param classRegexp 911 * Required class pattern. Matches are limited to exact matches 912 * of the given class pattern and matches of patterns that begin 913 * or end with '*'; for example, "*.Foo" or "java.*". 914 * @return ReplyPacket for setting request. 915 */ 916 public ReplyPacket setClassPrepared(String classRegexp) { 917 return setClassMatchEvent(JDWPConstants.EventKind.CLASS_PREPARE, 918 JDWPConstants.SuspendPolicy.ALL, classRegexp); 919 } 920 921 /** 922 * Set ClassPrepare event request for given class ID with suspend policy ALL. 923 * 924 * @param referenceTypeID 925 * class referenceTypeID 926 * @return ReplyPacket for setting request 927 */ 928 public ReplyPacket setClassPrepared(long referenceTypeID) { 929 return setClassOnlyEvent(JDWPConstants.EventKind.CLASS_PREPARE, 930 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 931 } 932 933 /** 934 * Sets ClassPrepare event request for given source name pattern with suspend policy ALL. 935 * 936 * @param sourceNamePattern 937 * Required source name pattern. Matches are limited to exact matches 938 * of the given source name pattern and matches of patterns that begin 939 * or end with '*'; for example, "*.Foo" or "java.*". 940 * @return ReplyPacket for setting request. 941 */ 942 public ReplyPacket setClassPreparedForSourceNameMatch(String sourceNamePattern) { 943 byte eventKind = JDWPConstants.EventKind.CLASS_PREPARE; 944 byte suspendPolicy = JDWPConstants.SuspendPolicy.ALL; 945 Event event = Event.builder(eventKind, suspendPolicy) 946 .setSourceNameMatch(sourceNamePattern) 947 .build(); 948 return setEvent(event); 949 } 950 951 /** 952 * Sets ClassUnload event request for given class name pattern with suspend policy ALL. 953 * 954 * @param classRegexp 955 * class name pattern 956 * @return ReplyPacket for setting request 957 */ 958 public ReplyPacket setClassUnload(String classRegexp) { 959 return setClassMatchEvent(JDWPConstants.EventKind.CLASS_UNLOAD, 960 JDWPConstants.SuspendPolicy.ALL, classRegexp); 961 } 962 963 /** 964 * Set ClassUnload event request for given class ID with suspend policy ALL. 965 * 966 * @param referenceTypeID 967 * class referenceTypeID 968 * @return ReplyPacket for setting request 969 */ 970 public ReplyPacket setClassUnload(long referenceTypeID) { 971 return setClassOnlyEvent(JDWPConstants.EventKind.CLASS_UNLOAD, 972 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 973 } 974 975 /** 976 * Sets ClassLoad event request for given class signature with suspend policy ALL. 977 * 978 * @param classSignature 979 * class signature 980 * @return ReplyPacket for setting request 981 */ 982 public ReplyPacket setClassLoad(String classSignature) { 983 long typeID; 984 985 // Request referenceTypeID for class 986 typeID = getClassID(classSignature); 987 988 // Set corresponding event 989 return setClassLoad(typeID); 990 } 991 992 /** 993 * Set ClassLoad event request for given class ID with suspend policy ALL. 994 * 995 * @param referenceTypeID 996 * class referenceTypeID 997 * @return ReplyPacket for setting request 998 */ 999 public ReplyPacket setClassLoad(long referenceTypeID) { 1000 return setClassOnlyEvent(JDWPConstants.EventKind.CLASS_LOAD, 1001 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1002 } 1003 1004 /** 1005 * Set MonitorContendedEnter event request for given class's reference type 1006 * 1007 * @param referenceTypeID 1008 * class referenceTypeID 1009 * @return ReplyPacket for setting request 1010 */ 1011 public ReplyPacket setMonitorContendedEnterForClassOnly(long referenceTypeID) { 1012 return setClassOnlyEvent(JDWPConstants.EventKind.MONITOR_CONTENDED_ENTER, 1013 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1014 } 1015 1016 /** 1017 * Set MonitorContendedEnter event request for given class's name pattern 1018 * 1019 * @param classRegexp 1020 * class name pattern 1021 * @return ReplyPacket for setting request 1022 */ 1023 public ReplyPacket setMonitorContendedEnterForClassMatch(String classRegexp) { 1024 return setClassMatchEvent(JDWPConstants.EventKind.MONITOR_CONTENDED_ENTER, 1025 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1026 } 1027 1028 /** 1029 * Set MonitorContendedEntered event request for given class's reference type 1030 * 1031 * @param referenceTypeID 1032 * class referenceTypeID 1033 * @return ReplyPacket for setting request 1034 */ 1035 public ReplyPacket setMonitorContendedEnteredForClassOnly(long referenceTypeID) { 1036 return setClassOnlyEvent(JDWPConstants.EventKind.MONITOR_CONTENDED_ENTERED, 1037 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1038 } 1039 1040 /** 1041 * Set MonitorContendedEntered event request for given class's name pattern 1042 * 1043 * @param classRegexp 1044 * class name pattern 1045 * @return ReplyPacket for setting request 1046 */ 1047 public ReplyPacket setMonitorContendedEnteredForClassMatch(String classRegexp) { 1048 return setClassMatchEvent(JDWPConstants.EventKind.MONITOR_CONTENDED_ENTERED, 1049 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1050 } 1051 1052 /** 1053 * Set MonitorWait event request for given class's reference type 1054 * 1055 * @param referenceTypeID 1056 * class referenceTypeID 1057 * @return ReplyPacket for setting request 1058 */ 1059 public ReplyPacket setMonitorWaitForClassOnly(long referenceTypeID) { 1060 return setClassOnlyEvent(JDWPConstants.EventKind.MONITOR_WAIT, 1061 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1062 } 1063 1064 /** 1065 * Set MonitorWait event request for given given class name pattern. 1066 * 1067 * @param classRegexp 1068 * Required class pattern. Matches are limited to exact matches 1069 * of the given class pattern and matches of patterns that begin 1070 * or end with '*'; for example, "*.Foo" or "java.*". 1071 * @return ReplyPacket for setting request. 1072 */ 1073 public ReplyPacket setMonitorWaitForClassMatch(String classRegexp) { 1074 return setClassMatchEvent(JDWPConstants.EventKind.MONITOR_WAIT, 1075 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1076 } 1077 1078 /** 1079 * Set MonitorWait event request for classes 1080 * whose name does not match the given restricted regular expression. 1081 * 1082 * @param classRegexp 1083 * Exclude class pattern. Matches are limited to exact matches 1084 * of the given class pattern and matches of patterns that begin 1085 * or end with '*'; for example, "*.Foo" or "java.*". 1086 * @return ReplyPacket for setting request. 1087 */ 1088 public ReplyPacket setMonitorWaitForClassExclude (String classRegexp) { 1089 return setClassExcludeEvent(JDWPConstants.EventKind.MONITOR_WAIT, 1090 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1091 } 1092 1093 /** 1094 * Set MonitorWaited event request for given class's reference type 1095 * 1096 * @param referenceTypeID 1097 * class referenceTypeID 1098 * @return ReplyPacket for setting request 1099 */ 1100 public ReplyPacket setMonitorWaitedForClassOnly(long referenceTypeID) { 1101 return setClassOnlyEvent(JDWPConstants.EventKind.MONITOR_WAITED, 1102 JDWPConstants.SuspendPolicy.ALL, referenceTypeID); 1103 } 1104 1105 /** 1106 * Set MonitorWaited event request for given given source name pattern. 1107 * 1108 * @param classRegexp 1109 * Required class pattern. Matches are limited to exact matches 1110 * of the given class pattern and matches of patterns that begin 1111 * or end with '*'; for example, "*.Foo" or "java.*". 1112 * @return ReplyPacket for setting request. 1113 */ 1114 public ReplyPacket setMonitorWaitedForClassMatch(String classRegexp) { 1115 return setClassMatchEvent(JDWPConstants.EventKind.MONITOR_WAITED, 1116 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1117 } 1118 1119 /** 1120 * Set MonitorWaited event request for classes 1121 * whose name does not match the given restricted regular expression. 1122 * 1123 * @param classRegexp 1124 * Required class pattern. Matches are limited to exact matches 1125 * of the given class pattern and matches of patterns that begin 1126 * or end with '*'; for example, "*.Foo" or "java.*". 1127 * @return ReplyPacket for setting request. 1128 */ 1129 public ReplyPacket setMonitorWaitedForClassExclude (String classRegexp) { 1130 return setClassExcludeEvent(JDWPConstants.EventKind.MONITOR_WAITED, 1131 JDWPConstants.SuspendPolicy.ALL, classRegexp); 1132 } 1133 1134 /** 1135 * Set event request for given event. 1136 * 1137 * @param event 1138 * event to set request for 1139 * @return ReplyPacket for setting request 1140 */ 1141 public ReplyPacket setEvent(Event event) { 1142 // Create new command packet 1143 CommandPacket commandPacket = new CommandPacket( 1144 JDWPCommands.EventRequestCommandSet.CommandSetID, 1145 JDWPCommands.EventRequestCommandSet.SetCommand); 1146 1147 // Set eventKind 1148 commandPacket.setNextValueAsByte(event.eventKind); 1149 // Set suspendPolicy 1150 commandPacket.setNextValueAsByte(event.suspendPolicy); 1151 1152 // Set modifiers 1153 commandPacket.setNextValueAsInt(event.mods.size()); 1154 1155 for (EventMod eventModifier : event.mods) { 1156 1157 commandPacket.setNextValueAsByte(eventModifier.modKind); 1158 1159 switch (eventModifier.modKind) { 1160 case EventMod.ModKind.Count: { 1161 // Case Count 1162 commandPacket.setNextValueAsInt(eventModifier.count); 1163 break; 1164 } 1165 case EventMod.ModKind.Conditional: { 1166 // Case Conditional 1167 commandPacket.setNextValueAsInt(eventModifier.exprID); 1168 break; 1169 } 1170 case EventMod.ModKind.ThreadOnly: { 1171 // Case ThreadOnly 1172 commandPacket.setNextValueAsThreadID(eventModifier.thread); 1173 break; 1174 } 1175 case EventMod.ModKind.ClassOnly: { 1176 // Case ClassOnly 1177 commandPacket 1178 .setNextValueAsReferenceTypeID(eventModifier.clazz); 1179 break; 1180 } 1181 case EventMod.ModKind.ClassMatch: { 1182 // Case ClassMatch 1183 commandPacket.setNextValueAsString(eventModifier.classPattern); 1184 break; 1185 } 1186 case EventMod.ModKind.ClassExclude: { 1187 // Case ClassExclude 1188 commandPacket.setNextValueAsString(eventModifier.classPattern); 1189 break; 1190 } 1191 case EventMod.ModKind.LocationOnly: { 1192 // Case LocationOnly 1193 commandPacket.setNextValueAsLocation(eventModifier.loc); 1194 break; 1195 } 1196 case EventMod.ModKind.ExceptionOnly: 1197 // Case ExceptionOnly 1198 commandPacket 1199 .setNextValueAsReferenceTypeID(eventModifier.exceptionOrNull); 1200 commandPacket.setNextValueAsBoolean(eventModifier.caught); 1201 commandPacket.setNextValueAsBoolean(eventModifier.uncaught); 1202 break; 1203 case EventMod.ModKind.FieldOnly: { 1204 // Case FieldOnly 1205 commandPacket 1206 .setNextValueAsReferenceTypeID(eventModifier.declaring); 1207 commandPacket.setNextValueAsFieldID(eventModifier.fieldID); 1208 break; 1209 } 1210 case EventMod.ModKind.Step: { 1211 // Case Step 1212 commandPacket.setNextValueAsThreadID(eventModifier.thread); 1213 commandPacket.setNextValueAsInt(eventModifier.size); 1214 commandPacket.setNextValueAsInt(eventModifier.depth); 1215 break; 1216 } 1217 case EventMod.ModKind.InstanceOnly: { 1218 // Case InstanceOnly 1219 commandPacket.setNextValueAsObjectID(eventModifier.instance); 1220 break; 1221 } 1222 case EventMod.ModKind.SourceNameMatch: { 1223 // Case SourceNameMatch 1224 commandPacket.setNextValueAsString(eventModifier.sourceNamePattern); 1225 } 1226 } 1227 } 1228 1229 // Send packet 1230 return checkReply(performCommand(commandPacket)); 1231 } 1232 1233 public Method[] getMethods(long classID) { 1234 boolean withGeneric = true; 1235 CommandPacket commandPacket = new CommandPacket( 1236 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 1237 JDWPCommands.ReferenceTypeCommandSet.MethodsWithGenericCommand); 1238 commandPacket.setNextValueAsReferenceTypeID(classID); 1239 ReplyPacket reply = performCommand(commandPacket); 1240 if (reply.getErrorCode() == JDWPConstants.Error.NOT_IMPLEMENTED) { 1241 withGeneric = false; 1242 commandPacket.setCommand(JDWPCommands.ReferenceTypeCommandSet.MethodsCommand); 1243 reply = performCommand(commandPacket); 1244 } 1245 checkReply(reply); 1246 1247 int declared = reply.getNextValueAsInt(); 1248 Method[] methods = new Method[declared]; 1249 for (int i = 0; i < declared; i++) { 1250 long methodID = reply.getNextValueAsMethodID(); 1251 String methodName = reply.getNextValueAsString(); 1252 String methodSignature = reply.getNextValueAsString(); 1253 String methodGenericSignature = ""; 1254 if (withGeneric) { 1255 methodGenericSignature = reply.getNextValueAsString(); 1256 } 1257 int methodModifiers = reply.getNextValueAsInt(); 1258 methods[i] = new Method( 1259 methodID, 1260 methodName, 1261 methodSignature, 1262 methodGenericSignature, 1263 methodModifiers 1264 ); 1265 } 1266 return methods; 1267 } 1268 1269 /** 1270 * Gets class reference by signature. 1271 * 1272 * @param classSignature 1273 * class signature. 1274 * @return ReplyPacket for corresponding command 1275 */ 1276 public ReplyPacket getClassBySignature(String classSignature) { 1277 CommandPacket commandPacket = new CommandPacket( 1278 JDWPCommands.VirtualMachineCommandSet.CommandSetID, 1279 JDWPCommands.VirtualMachineCommandSet.ClassesBySignatureCommand); 1280 commandPacket.setNextValueAsString(classSignature); 1281 return checkReply(performCommand(commandPacket)); 1282 } 1283 1284 /** 1285 * Returns for specified class array with information about fields of this class. 1286 * <BR>Each element of array contains: 1287 * <BR>Field ID, Field name, Field signature, Field modifier bit flags; 1288 * @param refType - ReferenceTypeID, defining class. 1289 * @return array with information about fields. 1290 */ 1291 public Field[] getFieldsInfo(long refType) { 1292 boolean withGeneric = true; 1293 CommandPacket packet = new CommandPacket(JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 1294 JDWPCommands.ReferenceTypeCommandSet.FieldsWithGenericCommand); 1295 packet.setNextValueAsReferenceTypeID(refType); 1296 ReplyPacket reply = performCommand(packet); 1297 if (reply.getErrorCode() == JDWPConstants.Error.NOT_IMPLEMENTED) { 1298 withGeneric = false; 1299 packet.setCommand(JDWPCommands.ReferenceTypeCommandSet.FieldsCommand); 1300 reply = performCommand(packet); 1301 } 1302 checkReply(reply); 1303 1304 int declared = reply.getNextValueAsInt(); 1305 Field[] fields = new Field[declared]; 1306 for (int i = 0; i < declared; i++) { 1307 long fieldID = reply.getNextValueAsFieldID(); 1308 String fieldName = reply.getNextValueAsString(); 1309 String fieldSignature = reply.getNextValueAsString(); 1310 String fieldGenericSignature = ""; 1311 if (withGeneric) { 1312 fieldGenericSignature = reply.getNextValueAsString(); 1313 } 1314 int fieldModifiers = reply.getNextValueAsInt(); 1315 fields[i] = new Field(fieldID, refType, fieldName, fieldSignature, 1316 fieldGenericSignature, fieldModifiers); 1317 } 1318 return fields; 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 boolean withGeneric = true; 1896 CommandPacket command = new CommandPacket( 1897 JDWPCommands.MethodCommandSet.CommandSetID, 1898 JDWPCommands.MethodCommandSet.VariableTableWithGenericCommand); 1899 command.setNextValueAsReferenceTypeID(classID); 1900 command.setNextValueAsMethodID(methodID); 1901 ReplyPacket reply = performCommand(command); 1902 if (reply.getErrorCode() == JDWPConstants.Error.NOT_IMPLEMENTED) { 1903 withGeneric = false; 1904 command.setCommand(JDWPCommands.MethodCommandSet.VariableTableCommand); 1905 reply = performCommand(command); 1906 } 1907 if (reply.getErrorCode() == JDWPConstants.Error.ABSENT_INFORMATION 1908 || reply.getErrorCode() == JDWPConstants.Error.NATIVE_METHOD) { 1909 return null; 1910 } 1911 1912 checkReply(reply); 1913 1914 reply.getNextValueAsInt(); // argCnt, is not used 1915 int slots = reply.getNextValueAsInt(); 1916 ArrayList<Variable> vars = new ArrayList<Variable>(slots); 1917 for (int i = 0; i < slots; i++) { 1918 Variable var = new Variable(); 1919 var.setCodeIndex(reply.getNextValueAsLong()); 1920 var.setName(reply.getNextValueAsString()); 1921 var.setSignature(reply.getNextValueAsString()); 1922 if (withGeneric) { 1923 var.setGenericSignature(reply.getNextValueAsString()); 1924 } 1925 var.setLength(reply.getNextValueAsInt()); 1926 var.setSlot(reply.getNextValueAsInt()); 1927 vars.add(var); 1928 } 1929 1930 return vars; 1931 } 1932 1933 /** 1934 * Returns values of local variables in a given frame 1935 * 1936 * @param frame 1937 * Frame whose variables to get 1938 * @return An array of Value objects 1939 */ 1940 public final Value[] getFrameValues(Frame frame) { 1941 CommandPacket command = new CommandPacket( 1942 JDWPCommands.StackFrameCommandSet.CommandSetID, 1943 JDWPCommands.StackFrameCommandSet.GetValuesCommand); 1944 command.setNextValueAsThreadID(frame.getThreadID()); 1945 command.setNextValueAsFrameID(frame.getID()); 1946 int slots = frame.getVars().size(); 1947 command.setNextValueAsInt(slots); 1948 Iterator<?> it = frame.getVars().iterator(); 1949 while (it.hasNext()) { 1950 Frame.Variable var = (Frame.Variable) it.next(); 1951 command.setNextValueAsInt(var.getSlot()); 1952 command.setNextValueAsByte(var.getTag()); 1953 } 1954 1955 ReplyPacket reply = checkReply(performCommand(command)); 1956 reply.getNextValueAsInt(); // number of values , is not used 1957 Value[] values = new Value[slots]; 1958 for (int i = 0; i < slots; i++) { 1959 values[i] = reply.getNextValueAsValue(); 1960 } 1961 1962 return values; 1963 } 1964 1965 /** 1966 * Returns the immediate superclass of a class 1967 * 1968 * @param classID 1969 * The class ID whose superclass ID is to get 1970 * @return The superclass ID (null if the class ID for java.lang.Object is 1971 * specified). 1972 */ 1973 public final long getSuperclassId(long classID) { 1974 CommandPacket command = new CommandPacket( 1975 JDWPCommands.ClassTypeCommandSet.CommandSetID, 1976 JDWPCommands.ClassTypeCommandSet.SuperclassCommand); 1977 command.setNextValueAsClassID(classID); 1978 ReplyPacket reply = checkReply(performCommand(command)); 1979 return reply.getNextValueAsClassID(); 1980 } 1981 1982 /** 1983 * Returns the runtime type of the object 1984 * 1985 * @param objectID 1986 * The object ID 1987 * @return The runtime reference type. 1988 */ 1989 public final long getReferenceType(long objectID) { 1990 CommandPacket command = new CommandPacket( 1991 JDWPCommands.ObjectReferenceCommandSet.CommandSetID, 1992 JDWPCommands.ObjectReferenceCommandSet.ReferenceTypeCommand); 1993 command.setNextValueAsObjectID(objectID); 1994 ReplyPacket reply = checkReply(performCommand(command)); 1995 reply.getNextValueAsByte(); 1996 return reply.getNextValueAsLong(); 1997 } 1998 1999 /** 2000 * Returns the class object corresponding to this type 2001 * 2002 * @param refType 2003 * The reference type ID. 2004 * @return The class object. 2005 */ 2006 public final long getClassObjectId(long refType) { 2007 CommandPacket command = new CommandPacket( 2008 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 2009 JDWPCommands.ReferenceTypeCommandSet.ClassObjectCommand); 2010 command.setNextValueAsReferenceTypeID(refType); 2011 ReplyPacket reply = checkReply(performCommand(command)); 2012 return reply.getNextValueAsObjectID(); 2013 } 2014 2015 /** 2016 * Returns line number information for the method, if present. 2017 * 2018 * @param refType 2019 * The class ID 2020 * @param methodID 2021 * The method ID 2022 * @return ReplyPacket for corresponding command. 2023 */ 2024 public final ReplyPacket getLineTable(long refType, long methodID) { 2025 CommandPacket command = new CommandPacket( 2026 JDWPCommands.MethodCommandSet.CommandSetID, 2027 JDWPCommands.MethodCommandSet.LineTableCommand); 2028 command.setNextValueAsReferenceTypeID(refType); 2029 command.setNextValueAsMethodID(methodID); 2030 // ReplyPacket reply = 2031 // debuggeeWrapper.vmMirror.checkReply(debuggeeWrapper.vmMirror.performCommand(command)); 2032 // it is impossible to obtain line table information from native 2033 // methods, so reply checking is not performed 2034 ReplyPacket reply = performCommand(command); 2035 if (reply.getErrorCode() != JDWPConstants.Error.NONE) { 2036 if (reply.getErrorCode() == JDWPConstants.Error.NATIVE_METHOD) { 2037 return reply; 2038 } 2039 } 2040 2041 return checkReply(reply); 2042 } 2043 2044 /** 2045 * Returns the value of one or more instance fields. 2046 * 2047 * @param objectID 2048 * The object ID 2049 * @param fieldIDs 2050 * IDs of fields to get 2051 * @return An array of Value objects representing each field's value 2052 */ 2053 public final Value[] getObjectReferenceValues(long objectID, long[] fieldIDs) { 2054 int fieldsCount = fieldIDs.length; 2055 if (fieldsCount == 0) { 2056 return null; 2057 } 2058 2059 CommandPacket command = new CommandPacket( 2060 JDWPCommands.ObjectReferenceCommandSet.CommandSetID, 2061 JDWPCommands.ObjectReferenceCommandSet.GetValuesCommand); 2062 command.setNextValueAsReferenceTypeID(objectID); 2063 command.setNextValueAsInt(fieldsCount); 2064 for (int i = 0; i < fieldsCount; i++) { 2065 command.setNextValueAsFieldID(fieldIDs[i]); 2066 } 2067 2068 ReplyPacket reply = checkReply(performCommand(command)); 2069 reply.getNextValueAsInt(); // fields returned, is not used 2070 Value[] values = new Value[fieldsCount]; 2071 for (int i = 0; i < fieldsCount; i++) { 2072 values[i] = reply.getNextValueAsValue(); 2073 } 2074 2075 return values; 2076 } 2077 2078 /** 2079 * Returns the value of one or more static fields of the reference type 2080 * 2081 * @param refTypeID 2082 * The reference type ID. 2083 * @param fieldIDs 2084 * IDs of fields to get 2085 * @return An array of Value objects representing each field's value 2086 */ 2087 public final Value[] getReferenceTypeValues(long refTypeID, long[] fieldIDs) { 2088 int fieldsCount = fieldIDs.length; 2089 if (fieldsCount == 0) { 2090 return null; 2091 } 2092 2093 CommandPacket command = new CommandPacket( 2094 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 2095 JDWPCommands.ReferenceTypeCommandSet.GetValuesCommand); 2096 command.setNextValueAsReferenceTypeID(refTypeID); 2097 command.setNextValueAsInt(fieldsCount); 2098 for (int i = 0; i < fieldsCount; i++) { 2099 command.setNextValueAsFieldID(fieldIDs[i]); 2100 } 2101 2102 ReplyPacket reply = checkReply(performCommand(command)); 2103 reply.getNextValueAsInt(); // fields returned, is not used 2104 Value[] values = new Value[fieldsCount]; 2105 for (int i = 0; i < fieldsCount; i++) { 2106 values[i] = reply.getNextValueAsValue(); 2107 } 2108 2109 return values; 2110 } 2111 2112 /** 2113 * Returns the value of one static field of the reference type 2114 * 2115 * @param refTypeID 2116 * The reference type ID. 2117 * @param fieldID 2118 * ID of field to get 2119 * @return A Value object representing the field's value 2120 */ 2121 public final Value getReferenceTypeValue(long refTypeID, long fieldID) { 2122 Value[] values = getReferenceTypeValues(refTypeID, new long[]{fieldID}); 2123 return values[0]; 2124 } 2125 2126 /** 2127 * Returns the value of the 'this' reference for this frame 2128 * 2129 * @param threadID 2130 * The frame's thread ID 2131 * @param frameID 2132 * The frame ID. 2133 * @return The 'this' object ID for this frame. 2134 */ 2135 public final long getThisObject(long threadID, long frameID) { 2136 CommandPacket command = new CommandPacket( 2137 JDWPCommands.StackFrameCommandSet.CommandSetID, 2138 JDWPCommands.StackFrameCommandSet.ThisObjectCommand); 2139 command.setNextValueAsThreadID(threadID); 2140 command.setNextValueAsFrameID(frameID); 2141 ReplyPacket reply = checkReply(performCommand(command)); 2142 TaggedObject taggedObject = reply.getNextValueAsTaggedObject(); 2143 return taggedObject.objectID; 2144 } 2145 2146 /** 2147 * Returns the reference type reflected by this class object 2148 * 2149 * @param classObjectID 2150 * The class object ID. 2151 * @return ReplyPacket for corresponding command 2152 */ 2153 public final ReplyPacket getReflectedType(long classObjectID) { 2154 CommandPacket command = new CommandPacket( 2155 JDWPCommands.ClassObjectReferenceCommandSet.CommandSetID, 2156 JDWPCommands.ClassObjectReferenceCommandSet.ReflectedTypeCommand); 2157 command.setNextValueAsClassObjectID(classObjectID); 2158 return checkReply(performCommand(command)); 2159 } 2160 2161 /** 2162 * Returns the JNI signature of a reference type. JNI signature formats are 2163 * described in the Java Native Interface Specification 2164 * 2165 * @param refTypeID 2166 * The reference type ID. 2167 * @return The JNI signature for the reference type. 2168 */ 2169 public final String getReferenceTypeSignature(long refTypeID) { 2170 CommandPacket command = new CommandPacket( 2171 JDWPCommands.ReferenceTypeCommandSet.CommandSetID, 2172 JDWPCommands.ReferenceTypeCommandSet.SignatureCommand); 2173 command.setNextValueAsReferenceTypeID(refTypeID); 2174 ReplyPacket reply = checkReply(performCommand(command)); 2175 return reply.getNextValueAsString(); 2176 } 2177 2178 /** 2179 * Returns the thread group that contains a given thread 2180 * 2181 * @param threadID 2182 * The thread object ID. 2183 * @return The thread group ID of this thread. 2184 */ 2185 public final long getThreadGroupID(long threadID) { 2186 CommandPacket command = new CommandPacket( 2187 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 2188 JDWPCommands.ThreadReferenceCommandSet.ThreadGroupCommand); 2189 command.setNextValueAsThreadID(threadID); 2190 ReplyPacket reply = checkReply(performCommand(command)); 2191 return reply.getNextValueAsThreadGroupID(); 2192 } 2193 2194 /** 2195 * Checks whether a given thread is suspended or not 2196 * 2197 * @param threadID 2198 * The thread object ID. 2199 * @return True if a given thread is suspended, false otherwise. 2200 */ 2201 public final boolean isThreadSuspended(long threadID) { 2202 CommandPacket command = new CommandPacket( 2203 JDWPCommands.ThreadReferenceCommandSet.CommandSetID, 2204 JDWPCommands.ThreadReferenceCommandSet.StatusCommand); 2205 command.setNextValueAsThreadID(threadID); 2206 ReplyPacket reply = checkReply(performCommand(command)); 2207 reply.getNextValueAsInt(); // the thread's status; is not used 2208 return reply.getNextValueAsInt() == JDWPConstants.SuspendStatus.SUSPEND_STATUS_SUSPENDED; 2209 } 2210 2211 /** 2212 * Returns JNI signature of method. 2213 * 2214 * @param classID 2215 * The reference type ID. 2216 * @param methodID 2217 * The method ID. 2218 * @return JNI signature of method. 2219 */ 2220 public final String getMethodSignature(long classID, long methodID) { 2221 Method[] methods = getMethods(classID); 2222 for (Method method : methods) { 2223 if (methodID == method.getMethodID()) { 2224 String value = method.getSignature(); 2225 value = value.replaceAll("/", "."); 2226 int lastRoundBracketIndex = value.lastIndexOf(")"); 2227 value = value.substring(0, lastRoundBracketIndex + 1); 2228 return value; 2229 } 2230 } 2231 return null; 2232 } 2233 2234 /** 2235 * Returns the characters contained in the string 2236 * 2237 * @param objectID 2238 * The String object ID. 2239 * @return A string value. 2240 */ 2241 public final String getStringValue(long objectID) { 2242 CommandPacket command = new CommandPacket( 2243 JDWPCommands.StringReferenceCommandSet.CommandSetID, 2244 JDWPCommands.StringReferenceCommandSet.ValueCommand); 2245 command.setNextValueAsObjectID(objectID); 2246 ReplyPacket reply = checkReply(performCommand(command)); 2247 return reply.getNextValueAsString(); 2248 } 2249 2250 /** 2251 * Returns a range of array components 2252 * 2253 * @param objectID 2254 * The array object ID. 2255 * @return The retrieved values. 2256 */ 2257 public Value[] getArrayValues(long objectID) { 2258 CommandPacket command = new CommandPacket( 2259 JDWPCommands.ArrayReferenceCommandSet.CommandSetID, 2260 JDWPCommands.ArrayReferenceCommandSet.LengthCommand); 2261 command.setNextValueAsArrayID(objectID); 2262 ReplyPacket reply = checkReply(performCommand(command)); 2263 int length = reply.getNextValueAsInt(); 2264 2265 if (length == 0) { 2266 return null; 2267 } 2268 2269 command = new CommandPacket( 2270 JDWPCommands.ArrayReferenceCommandSet.CommandSetID, 2271 JDWPCommands.ArrayReferenceCommandSet.GetValuesCommand); 2272 command.setNextValueAsArrayID(objectID); 2273 command.setNextValueAsInt(0); 2274 command.setNextValueAsInt(length); 2275 reply = checkReply(performCommand(command)); 2276 ArrayRegion arrayRegion = reply.getNextValueAsArrayRegion(); 2277 2278 Value[] values = new Value[length]; 2279 for (int i = 0; i < length; i++) { 2280 values[i] = arrayRegion.getValue(i); 2281 } 2282 2283 return values; 2284 } 2285 2286 /** 2287 * Returns a source line number according to a corresponding line code index 2288 * in a method's line table. 2289 * 2290 * @param classID 2291 * The class object ID. 2292 * @param methodID 2293 * The method ID. 2294 * @param codeIndex 2295 * The line code index. 2296 * @return An integer line number. 2297 */ 2298 public final int getLineNumber(long classID, long methodID, long codeIndex) { 2299 int lineNumber = -1; 2300 ReplyPacket reply = getLineTable(classID, methodID); 2301 if (reply.getErrorCode() != JDWPConstants.Error.NONE) { 2302 return lineNumber; 2303 } 2304 2305 reply.getNextValueAsLong(); // start line index, is not used 2306 reply.getNextValueAsLong(); // end line index, is not used 2307 int lines = reply.getNextValueAsInt(); 2308 for (int i = 0; i < lines; i++) { 2309 long lineCodeIndex = reply.getNextValueAsLong(); 2310 lineNumber = reply.getNextValueAsInt(); 2311 if (lineCodeIndex == codeIndex) { 2312 break; 2313 } 2314 2315 if (lineCodeIndex > codeIndex) { 2316 --lineNumber; 2317 break; 2318 } 2319 } 2320 2321 return lineNumber; 2322 } 2323 2324 /** 2325 * Returns a line code index according to a corresponding line number in a 2326 * method's line table. 2327 * 2328 * @param classID 2329 * The class object ID. 2330 * @param methodID 2331 * The method ID. 2332 * @param lineNumber 2333 * A source line number. 2334 * @return An integer representing the line code index. 2335 */ 2336 public final long getLineCodeIndex(long classID, long methodID, 2337 int lineNumber) { 2338 ReplyPacket reply = getLineTable(classID, methodID); 2339 if (reply.getErrorCode() != JDWPConstants.Error.NONE) { 2340 return -1L; 2341 } 2342 2343 reply.getNextValueAsLong(); // start line index, is not used 2344 reply.getNextValueAsLong(); // end line index, is not used 2345 int lines = reply.getNextValueAsInt(); 2346 for (int i = 0; i < lines; i++) { 2347 long lineCodeIndex = reply.getNextValueAsLong(); 2348 if (lineNumber == reply.getNextValueAsInt()) { 2349 return lineCodeIndex; 2350 } 2351 } 2352 2353 return -1L; 2354 } 2355 2356 /** 2357 * Returns all variables which are visible within the given frame. 2358 * 2359 * @param frame 2360 * The frame whose visible local variables to retrieve. 2361 * @return A list of Variable objects representing each visible local 2362 * variable within the given frame. 2363 */ 2364 public final List<Variable> getLocalVars(Frame frame) { 2365 List<Variable> vars = getVariableTable(frame.getLocation().classID, frame 2366 .getLocation().methodID); 2367 if (vars == null) { 2368 return null; 2369 } 2370 2371 // All variables that are not visible from within current frame must be 2372 // removed from the list 2373 long frameCodeIndex = frame.getLocation().index; 2374 for (int i = 0; i < vars.size(); i++) { 2375 Variable var = (Variable) vars.toArray()[i]; 2376 long varCodeIndex = var.getCodeIndex(); 2377 if (varCodeIndex > frameCodeIndex 2378 || (frameCodeIndex >= varCodeIndex + var.getLength())) { 2379 vars.remove(i); 2380 --i; 2381 continue; 2382 } 2383 } 2384 2385 return vars; 2386 } 2387 2388 /** 2389 * Sets the value of one or more local variables 2390 * 2391 * @param frame 2392 * The frame ID. 2393 * @param vars 2394 * An array of Variable objects whose values to set 2395 * @param values 2396 * An array of Value objects to set 2397 */ 2398 public final void setLocalVars(Frame frame, Variable[] vars, Value[] values) { 2399 if (vars.length != values.length) { 2400 throw new TestErrorException( 2401 "Number of variables doesn't correspond to number of their values"); 2402 } 2403 2404 CommandPacket command = new CommandPacket( 2405 JDWPCommands.StackFrameCommandSet.CommandSetID, 2406 JDWPCommands.StackFrameCommandSet.SetValuesCommand); 2407 command.setNextValueAsThreadID(frame.getThreadID()); 2408 command.setNextValueAsFrameID(frame.getID()); 2409 command.setNextValueAsInt(vars.length); 2410 for (int i = 0; i < vars.length; i++) { 2411 command.setNextValueAsInt(vars[i].getSlot()); 2412 command.setNextValueAsValue(values[i]); 2413 } 2414 2415 checkReply(performCommand(command)); 2416 } 2417 2418 /** 2419 * Sets the value of one or more instance fields 2420 * 2421 * @param objectID 2422 * The object ID. 2423 * @param fieldIDs 2424 * An array of fields IDs 2425 * @param values 2426 * An array of Value objects representing each value to set 2427 */ 2428 public final void setInstanceFieldsValues(long objectID, long[] fieldIDs, 2429 Value[] values) { 2430 if (fieldIDs.length != values.length) { 2431 throw new TestErrorException( 2432 "Number of fields doesn't correspond to number of their values"); 2433 } 2434 2435 CommandPacket command = new CommandPacket( 2436 JDWPCommands.ObjectReferenceCommandSet.CommandSetID, 2437 JDWPCommands.ObjectReferenceCommandSet.SetValuesCommand); 2438 command.setNextValueAsObjectID(objectID); 2439 command.setNextValueAsInt(fieldIDs.length); 2440 for (int i = 0; i < fieldIDs.length; i++) { 2441 command.setNextValueAsFieldID(fieldIDs[i]); 2442 command.setNextValueAsUntaggedValue(values[i]); 2443 } 2444 2445 checkReply(performCommand(command)); 2446 } 2447 2448 /** 2449 * Sets a range of array components. The specified range must be within the 2450 * bounds of the array. 2451 * 2452 * @param arrayID 2453 * The array object ID. 2454 * @param firstIndex 2455 * The first index to set. 2456 * @param values 2457 * An array of Value objects representing each value to set. 2458 */ 2459 public final void setArrayValues(long arrayID, int firstIndex, 2460 Value[] values) { 2461 CommandPacket command = new CommandPacket( 2462 JDWPCommands.ArrayReferenceCommandSet.CommandSetID, 2463 JDWPCommands.ArrayReferenceCommandSet.SetValuesCommand); 2464 command.setNextValueAsArrayID(arrayID); 2465 command.setNextValueAsInt(firstIndex); 2466 command.setNextValueAsInt(values.length); 2467 for (int i = 0; i < values.length; i++) { 2468 command.setNextValueAsUntaggedValue(values[i]); 2469 } 2470 2471 checkReply(performCommand(command)); 2472 } 2473 2474 /** 2475 * Sets the value of one or more static fields 2476 * 2477 * @param classID 2478 * The class type ID. 2479 * @param fieldIDs 2480 * An array of fields IDs 2481 * @param values 2482 * An array of Value objects representing each value to set 2483 */ 2484 public final void setStaticFieldsValues(long classID, long[] fieldIDs, 2485 Value[] values) { 2486 if (fieldIDs.length != values.length) { 2487 throw new TestErrorException( 2488 "Number of fields doesn't correspond to number of their values"); 2489 } 2490 2491 CommandPacket command = new CommandPacket( 2492 JDWPCommands.ClassTypeCommandSet.CommandSetID, 2493 JDWPCommands.ClassTypeCommandSet.SetValuesCommand); 2494 command.setNextValueAsClassID(classID); 2495 command.setNextValueAsInt(fieldIDs.length); 2496 for (int i = 0; i < fieldIDs.length; i++) { 2497 command.setNextValueAsFieldID(fieldIDs[i]); 2498 command.setNextValueAsUntaggedValue(values[i]); 2499 } 2500 2501 checkReply(performCommand(command)); 2502 } 2503 2504 /** 2505 * Creates java String in target VM with the given value. 2506 * 2507 * @param value 2508 * The value of the string. 2509 * @return The string id. 2510 */ 2511 public final long createString(String value) { 2512 CommandPacket command = new CommandPacket( 2513 JDWPCommands.VirtualMachineCommandSet.CommandSetID, 2514 JDWPCommands.VirtualMachineCommandSet.CreateStringCommand); 2515 command.setNextValueAsString(value); 2516 ReplyPacket reply = checkReply(performCommand(command)); 2517 return reply.getNextValueAsStringID(); 2518 } 2519 2520 /** 2521 * Processes JDWP PopFrames command from StackFrame command set. 2522 * 2523 * @param frame 2524 * The instance of Frame. 2525 */ 2526 public final void popFrame(Frame frame) { 2527 CommandPacket command = new CommandPacket( 2528 JDWPCommands.StackFrameCommandSet.CommandSetID, 2529 JDWPCommands.StackFrameCommandSet.PopFramesCommand); 2530 command.setNextValueAsThreadID(frame.getThreadID()); 2531 command.setNextValueAsFrameID(frame.getID()); 2532 checkReply(performCommand(command)); 2533 } 2534 2535 /** 2536 * Invokes a member method of the given object. 2537 * 2538 * @param objectID 2539 * The object ID. 2540 * @param threadID 2541 * The thread ID. 2542 * @param methodName 2543 * The name of method for the invocation. 2544 * @param args 2545 * The arguments for the invocation. 2546 * @param options 2547 * The invocation options. 2548 * @return ReplyPacket for corresponding command 2549 */ 2550 public final ReplyPacket invokeInstanceMethod(long objectID, long threadID, 2551 String methodName, Value[] args, int options) { 2552 long classID = getReferenceType(objectID); 2553 long methodID = getMethodID(classID, methodName); 2554 CommandPacket command = new CommandPacket( 2555 JDWPCommands.ObjectReferenceCommandSet.CommandSetID, 2556 JDWPCommands.ObjectReferenceCommandSet.InvokeMethodCommand); 2557 command.setNextValueAsObjectID(objectID); 2558 command.setNextValueAsThreadID(threadID); 2559 command.setNextValueAsClassID(classID); 2560 command.setNextValueAsMethodID(methodID); 2561 command.setNextValueAsInt(args.length); 2562 for (int i = 0; i < args.length; i++) { 2563 command.setNextValueAsValue(args[i]); 2564 } 2565 command.setNextValueAsInt(options); 2566 2567 return checkReply(performCommand(command)); 2568 } 2569 2570 /** 2571 * Invokes a static method of the given class. 2572 * 2573 * @param classID 2574 * The class type ID. 2575 * @param threadID 2576 * The thread ID. 2577 * @param methodName 2578 * The name of method for the invocation. 2579 * @param args 2580 * The arguments for the invocation. 2581 * @param options 2582 * The invocation options. 2583 * @return ReplyPacket for corresponding command 2584 */ 2585 public final ReplyPacket invokeStaticMethod(long classID, long threadID, 2586 String methodName, Value[] args, int options) { 2587 long methodID = getMethodID(classID, methodName); 2588 CommandPacket command = new CommandPacket( 2589 JDWPCommands.ClassTypeCommandSet.CommandSetID, 2590 JDWPCommands.ClassTypeCommandSet.InvokeMethodCommand); 2591 command.setNextValueAsClassID(classID); 2592 command.setNextValueAsThreadID(threadID); 2593 command.setNextValueAsMethodID(methodID); 2594 command.setNextValueAsInt(args.length); 2595 for (int i = 0; i < args.length; i++) { 2596 command.setNextValueAsValue(args[i]); 2597 } 2598 command.setNextValueAsInt(options); 2599 2600 return checkReply(performCommand(command)); 2601 } 2602 } 2603