• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
VmMirror(TestOptions config, LogWriter logWriter)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      */
checkReply(ReplyPacket reply)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      */
setBreakpoint(Location location)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      */
setBreakpoint(Location location, byte suspendPolicy)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      */
setCountableBreakpoint(byte typeTag, Breakpoint breakpoint, byte suspendPolicy, int count)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      */
setBreakpointAtMethodBegin(long classID, String methodName)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      */
setBreakpointAtMethodBegin(long classID, String methodName, byte suspendPolicy)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      */
waitForBreakpoint(int requestID)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      */
clearBreakpoint(int requestID)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      */
ClearAllBreakpoints()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      */
capabilities()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      */
canRedefineClasses()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      */
canPopFrames()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      */
canGetSourceDebugExtension()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      */
canRequestVMDeathEvent()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      */
canSetDefaultStratum()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      */
canUseSourceNameFilters()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      */
canGetConstantPool()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      */
canForceEarlyReturn()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      */
canRedefineDexClasses()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      */
resume()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      */
resumeThread(long threadID)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      */
suspend()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      */
suspendThread(long threadID)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      */
dispose()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      */
exit(int exitCode)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      */
adjustTypeLength()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      */
getTypeID(String typeSignature, byte classTypeTag)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      */
getClassID(String classSignature)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      */
getThreadID(String threadName)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      */
getAllThreadID()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      */
getClassSignature(long classID)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      */
getThreadName(long threadID)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      */
getThreadStatus(long threadID)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      */
getThreadSuspendCount(long threadID)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      */
getThreadGroupName(long groupID)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      */
getInterfaceID(String interfaceSignature)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      */
getArrayID(String arraySignature)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      */
getRequestID(ReplyPacket request)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      */
getFieldID(long classID, String fieldName)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      */
getMethodID(long classID, String methodName)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      */
getMethodID(long classID, String methodName, String methodSignature)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      */
getMethodName(long classID, long methodID)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      */
setClassPrepared(String classRegexp)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      */
setClassPrepared(long referenceTypeID)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      */
setClassPreparedForSourceNameMatch(String sourceNamePattern)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      */
setClassUnload(String classRegexp)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      */
setClassUnload(long referenceTypeID)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      */
setClassLoad(String classSignature)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      */
setClassLoad(long referenceTypeID)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      */
setMonitorContendedEnterForClassOnly(long referenceTypeID)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      */
setMonitorContendedEnterForClassMatch(String classRegexp)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      */
setMonitorContendedEnteredForClassOnly(long referenceTypeID)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      */
setMonitorContendedEnteredForClassMatch(String classRegexp)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      */
setMonitorWaitForClassOnly(long referenceTypeID)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      */
setMonitorWaitForClassMatch(String classRegexp)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      */
setMonitorWaitForClassExclude(String classRegexp)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      */
setMonitorWaitedForClassOnly(long referenceTypeID)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      */
setMonitorWaitedForClassMatch(String classRegexp)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      */
setMonitorWaitedForClassExclude(String classRegexp)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      */
setEvent(Event event)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 
getMethods(long classID)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      */
getClassBySignature(String classSignature)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      */
getFieldsInfo(long refType)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      */
setException(String exceptionSignature, boolean caught, boolean uncaught)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      */
setException(long exceptionID, boolean caught, boolean uncaught)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      */
setMethodEntry(String classRegexp)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      */
setMethodExit(String classRegexp)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      */
setMethodExitWithReturnValue(String classRegexp)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      */
setFieldAccess(String classSignature, byte classTypeTag, String fieldName)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      */
setFieldModification(String classSignature, byte classTypeTag, String fieldName)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      */
setStep(long threadID, int stepSize, int stepDepth)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      */
setStep(String[] classRegexp, long threadID, int stepSize, int stepDepth)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      */
setThreadStart(byte suspendPolicy)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      */
setThreadEnd(byte suspendPolicy)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 
setClassOnlyEvent(byte eventKind, byte suspendPolicy, long classId)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 
setClassMatchEvent(byte eventKind, byte suspendPolicy, String pattern)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 
setClassExcludeEvent(byte eventKind, byte suspendPolicy, String pattern)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      */
clearEvent(byte eventKind, int requestID)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      */
performCommand(CommandPacket command)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      */
performCommand(CommandPacket command, long timeout)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      */
sendCommand(CommandPacket command)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      */
receiveReply(int commandId)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      */
receiveReply(int commandId, long timeout)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      */
receiveEvent()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      */
receiveEvent(long timeout)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      */
receiveCertainEvent(byte eventKind)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      */
getConnection()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      */
setConnection(TransportWrapper connection)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      */
closeConnection()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      */
getFrameCount(long threadID)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      */
getAllThreadFrames(long threadID)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      */
getThreadFrames(long threadID, int startIndex, int length)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      */
getVariableTable(long classID, long methodID)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      */
getFrameValues(Frame frame)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      */
getSuperclassId(long classID)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      */
getReferenceType(long objectID)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      */
getClassObjectId(long refType)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      */
getLineTable(long refType, long methodID)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      */
getObjectReferenceValues(long objectID, long[] fieldIDs)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      */
getReferenceTypeValues(long refTypeID, long[] fieldIDs)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      */
getReferenceTypeValue(long refTypeID, long fieldID)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      */
getThisObject(long threadID, long frameID)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      */
getReflectedType(long classObjectID)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      */
getReferenceTypeSignature(long refTypeID)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      */
getThreadGroupID(long threadID)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      */
isThreadSuspended(long threadID)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      */
getMethodSignature(long classID, long methodID)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      */
getStringValue(long objectID)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      */
getArrayValues(long objectID)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      */
getLineNumber(long classID, long methodID, long codeIndex)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      */
getLineCodeIndex(long classID, long methodID, int lineNumber)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      */
getLocalVars(Frame frame)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      */
setLocalVars(Frame frame, Variable[] vars, Value[] values)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      */
setInstanceFieldsValues(long objectID, long[] fieldIDs, Value[] values)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      */
setArrayValues(long arrayID, int firstIndex, Value[] values)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      */
setStaticFieldsValues(long classID, long[] fieldIDs, Value[] values)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      */
createString(String value)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      */
popFrame(Frame frame)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      */
invokeInstanceMethod(long objectID, long threadID, String methodName, Value[] args, int options)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      */
invokeStaticMethod(long classID, long threadID, String methodName, Value[] args, int options)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