1 /*
2  * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package nsk.jdwp.ArrayReference.GetValues;
25 
26 import java.io.*;
27 
28 import nsk.share.*;
29 import nsk.share.jpda.*;
30 import nsk.share.jdwp.*;
31 
32 /**
33  * Test for JDWP command: ArrayReference.GetValues.
34  *
35  * See getvalues001.README for description of test execution.
36  *
37  * Test is executed by invoking method runIt().
38  * JDWP command is tested in method testCommand().
39  *
40  * @see #runIt()
41  * @see #testCommand()
42  */
43 public class getvalues001 {
44 
45     // exit status constants
46     static final int JCK_STATUS_BASE = 95;
47     static final int PASSED = 0;
48     static final int FAILED = 2;
49 
50     // communication signals constants
51     static final String READY = "ready";
52     static final String QUIT = "quit";
53 
54     // package and classes names constants
55     static final String PACKAGE_NAME = "nsk.jdwp.ArrayReference.GetValues";
56     static final String TEST_CLASS_NAME = PACKAGE_NAME + "." + "getvalues001";
57     static final String DEBUGEE_CLASS_NAME = TEST_CLASS_NAME + "a";
58 
59     // tested JDWP command constants
60     static final String JDWP_COMMAND_NAME = "ArrayReference.GetValues";
61     static final int JDWP_COMMAND_ID = JDWP.Command.ArrayReference.GetValues;
62 
63     // tested class name and signature constants
64     static final String TESTED_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TestedClass";
65     static final String TESTED_CLASS_SIGNATURE = "L" + TESTED_CLASS_NAME.replace('.', '/') + ";";
66 
67     // name of the static field in the tested class with the tested object value
68     static final String ARRAY_FIELD_NAME = getvalues001a.ARRAY_FIELD_NAME;
69     static final int ARRAY_LENGTH = getvalues001a.ARRAY_LENGTH;
70 
71     // first index and number of array components to get
72     static final int ARRAY_FIRST_INDEX = 4;
73     static final int ARRAY_ITEMS_COUNT = 10;
74 
75     // usual scaffold objects
76     ArgumentHandler argumentHandler = null;
77     Log log = null;
78     Binder binder = null;
79     Debugee debugee = null;
80     Transport transport = null;
81     IOPipe pipe = null;
82 
83     // test passed or not
84     boolean success = true;
85 
86     // -------------------------------------------------------------------
87 
88     /**
89      * Start test from command line.
90      */
main(String argv[])91     public static void main (String argv[]) {
92         System.exit(run(argv,System.out) + JCK_STATUS_BASE);
93     }
94 
95     /**
96      * Start JCK-compilant test.
97      */
run(String argv[], PrintStream out)98     public static int run(String argv[], PrintStream out) {
99         return new getvalues001().runIt(argv, out);
100     }
101 
102     // -------------------------------------------------------------------
103 
104     /**
105      * Perform test execution.
106      */
runIt(String argv[], PrintStream out)107     public int runIt(String argv[], PrintStream out) {
108 
109         // make log for debugger messages
110         argumentHandler = new ArgumentHandler(argv);
111         log = new Log(out, argumentHandler);
112 
113         // execute test and display results
114         try {
115             log.display("\n>>> Preparing debugee for testing \n");
116 
117             // launch debugee
118             binder = new Binder(argumentHandler, log);
119             log.display("Launching debugee");
120             debugee = binder.bindToDebugee(DEBUGEE_CLASS_NAME);
121             transport = debugee.getTransport();
122             pipe = debugee.createIOPipe();
123 
124             // make debuggee ready for testing
125             prepareDebugee();
126 
127             // work with prepared debugee
128             try {
129                 log.display("\n>>> Obtaining requred data from debugee \n");
130 
131                 // query debugee for TypeID of tested class
132                 log.display("Getting ReferenceTypeID by signature:\n"
133                             + "  " + TESTED_CLASS_SIGNATURE);
134                 long classID = debugee.getReferenceTypeID(TESTED_CLASS_SIGNATURE);
135                 log.display("  got classID: " + classID);
136 
137                 // query debuggee for arrayID value from static field
138                 log.display("Getting arrayID value from static field: "
139                             + ARRAY_FIELD_NAME);
140                 long arrayID = queryObjectID(classID,
141                             ARRAY_FIELD_NAME, JDWP.Tag.ARRAY);
142                 log.display("  got arrayID: " + arrayID);
143 
144                 // perform testing JDWP command
145                 log.display("\n>>> Testing JDWP command \n");
146                 testCommand(arrayID);
147 
148             } finally {
149                 // quit debugee
150                 log.display("\n>>> Finishing test \n");
151                 quitDebugee();
152             }
153 
154         } catch (Failure e) {
155             log.complain("TEST FAILED: " + e.getMessage());
156             e.printStackTrace(out);
157             success = false;
158         } catch (Exception e) {
159             log.complain("Caught unexpected exception:\n" + e);
160             e.printStackTrace(out);
161             success = false;
162         }
163 
164         if (!success) {
165             log.complain("TEST FAILED");
166             return FAILED;
167         }
168 
169         out.println("TEST PASSED");
170         return PASSED;
171 
172     }
173 
174     /**
175      * Prepare debugee for testing and waiting for ready signal.
176      */
prepareDebugee()177     void prepareDebugee() {
178         // wait for VM_INIT event from debugee
179         log.display("Waiting for VM_INIT event");
180         debugee.waitForVMInit();
181 
182         // query debugee for VM-dependent ID sizes
183         log.display("Querying for IDSizes");
184         debugee.queryForIDSizes();
185 
186         // resume initially suspended debugee
187         log.display("Resuming debugee VM");
188         debugee.resume();
189 
190         // wait for READY signal from debugee
191         log.display("Waiting for signal from debugee: " + READY);
192         String signal = pipe.readln();
193         log.display("Received signal from debugee: " + signal);
194         if (! signal.equals(READY)) {
195             throw new TestBug("Unexpected signal received form debugee: " + signal
196                             + " (expected: " + READY + ")");
197         }
198     }
199 
200     /**
201      * Sending debugee signal to quit and waiting for it exits.
202      */
quitDebugee()203     void quitDebugee() {
204         // send debugee signal to quit
205         log.display("Sending signal to debugee: " + QUIT);
206         pipe.println(QUIT);
207 
208         // wait for debugee exits
209         log.display("Waiting for debugee exits");
210         int code = debugee.waitFor();
211 
212         // analize debugee exit status code
213         if (code == JCK_STATUS_BASE + PASSED) {
214             log.display("Debugee PASSED with exit code: " + code);
215         } else {
216             log.complain("Debugee FAILED with exit code: " + code);
217             success = false;
218         }
219     }
220 
221     /**
222      * Query debuggee for objectID value of static class field.
223      */
queryObjectID(long classID, String fieldName, byte tag)224     long queryObjectID(long classID, String fieldName, byte tag) {
225         // get fieledID for static field (declared in the class)
226         long fieldID = debugee.getClassFieldID(classID, fieldName, true);
227         // get value of the field
228         JDWP.Value value = debugee.getStaticFieldValue(classID, fieldID);
229 
230         // check that value has THREAD tag
231         if (value.getTag() != tag) {
232             throw new Failure("Wrong objectID tag received from field \"" + fieldName
233                             + "\": " + value.getTag() + " (expected: " + tag + ")");
234         }
235 
236         // extract threadID from the value
237         long objectID = ((Long)value.getValue()).longValue();
238         return objectID;
239     }
240 
241     /**
242      * Perform testing JDWP command for specified objectID.
243      */
testCommand(long arrayID)244     void testCommand(long arrayID) {
245         // create command packet
246         log.display("Create command packet:");
247         log.display("Command: " + JDWP_COMMAND_NAME);
248         CommandPacket command = new CommandPacket(JDWP_COMMAND_ID);
249 
250         // add out data to the command packet
251         log.display("  arrayID: " + arrayID);
252         command.addObjectID(arrayID);
253         log.display("  firstIndex: " + ARRAY_FIRST_INDEX);
254         command.addInt(ARRAY_FIRST_INDEX);
255         log.display("  length: " + ARRAY_ITEMS_COUNT);
256         command.addInt(ARRAY_ITEMS_COUNT);
257         command.setLength();
258 
259         // send command packet to debugee
260         try {
261             log.display("Sending command packet:\n" + command);
262             transport.write(command);
263         } catch (IOException e) {
264             log.complain("Unable to send command packet:\n" + e);
265             success = false;
266             return;
267         }
268 
269         ReplyPacket reply = new ReplyPacket();
270 
271         // receive reply packet from debugee
272         try {
273             log.display("Waiting for reply packet");
274             transport.read(reply);
275             log.display("Reply packet received:\n" + reply);
276         } catch (IOException e) {
277             log.complain("Unable to read reply packet:\n" + e);
278             success = false;
279             return;
280         }
281 
282         // check reply packet header
283         try{
284             log.display("Checking reply packet header");
285             reply.checkHeader(command.getPacketID());
286         } catch (BoundException e) {
287             log.complain("Bad header of reply packet: " + e.getMessage());
288             success = false;
289         }
290 
291         // start parsing reply packet data
292         log.display("Parsing reply packet:");
293         reply.resetPosition();
294 
295         // extract values tag
296         byte tag = (byte)0;
297         try {
298             tag = reply.getByte();
299             log.display("  tag: " + tag);
300 
301         } catch (BoundException e) {
302             log.complain("Unable to extract values tag from reply packet:\n\t"
303                         + e.getMessage());
304             success = false;
305         }
306 
307         // check if number of values are as expected
308         if (tag != JDWP.Tag.INT) {
309             log.complain("Unexpected values tag received:" + tag
310                         + " (expected: " + JDWP.Tag.INT + ")");
311             success = false;
312         }
313 
314         // extract number of values
315         int values = 0;
316         try {
317             values = reply.getInt();
318             log.display("  values: " + values);
319 
320         } catch (BoundException e) {
321             log.complain("Unable to extract number of values from reply packet:\n\t"
322                         + e.getMessage());
323             success = false;
324         }
325 
326         // check if number of values are as expected
327         if (values < 0) {
328             log.complain("Negative number of values received:" + values
329                         + " (expected: " + ARRAY_ITEMS_COUNT + ")");
330             success = false;
331         } else if (values != ARRAY_ITEMS_COUNT) {
332             log.complain("Unexpected number of values received:" + values
333                         + " (expected: " + ARRAY_ITEMS_COUNT + ")");
334             success = false;
335         }
336 
337         // extract and check each value
338         for (int i = 0; i < values; i++ ) {
339             int index = i + ARRAY_FIRST_INDEX;
340             log.display("  value #" + i + " (index: " + index  + ")");
341 
342             // extract value
343             JDWP.UntaggedValue value = null;
344             try {
345                 value = reply.getUntaggedValue(JDWP.Tag.INT);
346                 log.display("    untagged_value: " + value);
347             } catch (BoundException e) {
348                 log.complain("Unable to extract " + i + " value from reply packet:\n\t"
349                             + e.getMessage());
350                 success = false;
351                 break;
352             }
353 
354             // check that extracted value is as expected
355             int intValue = ((Integer)value.getValue()).intValue();
356             if (intValue != index * 10) {
357                 log.complain("Unexpected value for " + index + " component received: "
358                             + intValue + " (expected: " + (index * 10) + ")");
359                 success = false;
360             }
361         }
362 
363         // check for extra data in reply packet
364         if (! reply.isParsed()) {
365             log.complain("Extra trailing bytes found in reply packet at: "
366                         + "0x" + reply.toHexString(reply.currentDataPosition(), 4));
367             success = false;
368         }
369     }
370 
371 }
372