Home | History | Annotate | Download | only in jdwp
      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