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.ClassType.SetValues;
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: ClassType.SetValues.
34  *
35  * See setvalues001.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 setvalues001 {
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 RUN = "run";
53     static final String DONE = "done";
54     static final String ERROR = "error";
55     static final String QUIT = "quit";
56 
57     // package and classes names constants
58     static final String PACKAGE_NAME = "nsk.jdwp.ClassType.SetValues";
59     static final String TEST_CLASS_NAME = PACKAGE_NAME + "." + "setvalues001";
60     static final String DEBUGEE_CLASS_NAME = TEST_CLASS_NAME + "a";
61 
62     // tested JDWP command constants
63     static final String JDWP_COMMAND_NAME = "ClassType.SetValues";
64     static final int JDWP_COMMAND_ID = JDWP.Command.ClassType.SetValues;
65 
66     // tested class name and signature constants
67     static final String TESTED_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TestedClass";
68     static final String TESTED_CLASS_SIGNATURE = "L" + TESTED_CLASS_NAME.replace('.', '/') + ";";
69 
70     // target values class name and signature constants
71     static final String TARGET_VALUES_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TargetValuesClass";
72     static final String TARGET_VALUES_CLASS_SIGNATURE = "L" + TARGET_VALUES_CLASS_NAME.replace('.', '/') + ";";
73 
74     // usual scaffold objects
75     ArgumentHandler argumentHandler = null;
76     Log log = null;
77     Binder binder = null;
78     Debugee debugee = null;
79     Transport transport = null;
80     IOPipe pipe = null;
81 
82     // test passed or not
83     boolean success = true;
84 
85     // -------------------------------------------------------------------
86 
87     /**
88      * Start test from command line.
89      */
main(String argv[])90     public static void main (String argv[]) {
91         System.exit(run(argv,System.out) + JCK_STATUS_BASE);
92     }
93 
94     /**
95      * Start JCK-compilant test.
96      */
run(String argv[], PrintStream out)97     public static int run(String argv[], PrintStream out) {
98         return new setvalues001().runIt(argv, out);
99     }
100 
101     // -------------------------------------------------------------------
102 
103     /**
104      * Perform test execution.
105      */
runIt(String argv[], PrintStream out)106     public int runIt(String argv[], PrintStream out) {
107 
108         // make log for debugger messages
109         argumentHandler = new ArgumentHandler(argv);
110         log = new Log(out, argumentHandler);
111 
112         // execute test and display results
113         try {
114             log.display("\n>>> Preparing debugee for testing \n");
115 
116             // launch debugee
117             binder = new Binder(argumentHandler, log);
118             log.display("Launching debugee");
119             debugee = binder.bindToDebugee(DEBUGEE_CLASS_NAME);
120             transport = debugee.getTransport();
121             pipe = debugee.createIOPipe();
122 
123             // make debuggee ready for testing
124             prepareDebugee();
125 
126             // work with prepared debugee
127             try {
128                 log.display("\n>>> Obtaining requred data from debugee \n");
129 
130                 // query debugee for classID for the class with target values
131                 log.display("Getting classID for class with target values by signature:\n"
132                             + "  " + TARGET_VALUES_CLASS_SIGNATURE);
133                 long targetValuesClassID =
134                             debugee.getReferenceTypeID(TARGET_VALUES_CLASS_SIGNATURE);
135                 log.display("  got classID: " + targetValuesClassID);
136 
137                 // query debugee for fieldIDs of the class static fields
138                 log.display("Getting fieldIDs for static fields of the class");
139                 long targetValuesFieldIDs[] = queryClassFieldIDs(targetValuesClassID);
140                 log.display("  got fields: " + targetValuesFieldIDs.length);
141                 int count = targetValuesFieldIDs.length;
142 
143                 // query debugee for values of the fields
144                 log.display("Getting values of the static fields");
145                 JDWP.Value targetValues[] =
146                         queryClassFieldValues(targetValuesClassID, targetValuesFieldIDs);
147                 log.display("  got values: " + targetValues.length);
148                 if (targetValues.length != count) {
149                     throw new Failure("Unexpected number of static fields values received: "
150                                     + targetValues.length + "(expected: " + count + ")");
151                 }
152 
153                 // query debugee for classID of the tested class
154                 log.display("Getting tested classID by signature:\n"
155                             + "  " + TESTED_CLASS_SIGNATURE);
156                 long testedClassID = debugee.getReferenceTypeID(TESTED_CLASS_SIGNATURE);
157                 log.display("  got classID: " + testedClassID);
158 
159                 // query debugee for fieldIDs of tested class static fields
160                 log.display("Getting fieldIDs for static fields of the tested class");
161                 long testedFieldIDs[] = queryClassFieldIDs(testedClassID);
162                 log.display("  got fields: " + testedFieldIDs.length);
163                 if (testedFieldIDs.length != count) {
164                     throw new Failure("Unexpected number of static fields of tested class received: "
165                                     + testedFieldIDs.length + "(expected: " + count + ")");
166                 }
167 
168                 // perform testing JDWP command
169                 log.display("\n>>> Testing JDWP command \n");
170                 testCommand(testedClassID, testedFieldIDs, targetValues);
171 
172                 // check confirmation from debuggee that values have been set properly
173                 log.display("\n>>> Checking that the values have been set properly \n");
174                 checkValuesChanged();
175 
176             } finally {
177                 // quit debugee
178                 log.display("\n>>> Finishing test \n");
179                 quitDebugee();
180             }
181 
182         } catch (Failure e) {
183             log.complain("TEST FAILED: " + e.getMessage());
184             e.printStackTrace(out);
185             success = false;
186         } catch (Exception e) {
187             log.complain("Caught unexpected exception:\n" + e);
188             e.printStackTrace(out);
189             success = false;
190         }
191 
192         if (!success) {
193             log.complain("TEST FAILED");
194             return FAILED;
195         }
196 
197         out.println("TEST PASSED");
198         return PASSED;
199 
200     }
201 
202     /**
203      * Prepare debugee for testing and waiting for ready signal.
204      */
prepareDebugee()205     void prepareDebugee() {
206         // wait for VM_INIT event from debugee
207         log.display("Waiting for VM_INIT event");
208         debugee.waitForVMInit();
209 
210         // query debugee for VM-dependent ID sizes
211         log.display("Querying for IDSizes");
212         debugee.queryForIDSizes();
213 
214         // resume initially suspended debugee
215         log.display("Resuming debugee VM");
216         debugee.resume();
217 
218         // wait for READY signal from debugee
219         log.display("Waiting for signal from debugee: " + READY);
220         String signal = pipe.readln();
221         log.display("Received signal from debugee: " + signal);
222         if (! signal.equals(READY)) {
223             throw new TestBug("Unexpected signal received form debugee: " + signal
224                             + " (expected: " + READY + ")");
225         }
226     }
227 
228     /**
229      * Sending debugee signal to quit and waiting for it exits.
230      */
quitDebugee()231     void quitDebugee() {
232         // send debugee signal to quit
233         log.display("Sending signal to debugee: " + QUIT);
234         pipe.println(QUIT);
235 
236         // wait for debugee exits
237         log.display("Waiting for debugee exits");
238         int code = debugee.waitFor();
239 
240         // analize debugee exit status code
241         if (code == JCK_STATUS_BASE + PASSED) {
242             log.display("Debugee PASSED with exit code: " + code);
243         } else {
244             log.complain("Debugee FAILED with exit code: " + code);
245             success = false;
246         }
247     }
248 
249     /**
250      * Query debugee for fieldID's of the class static fields.
251      */
queryClassFieldIDs(long classID)252     long[] queryClassFieldIDs(long classID) {
253         // compose ReferenceType.Fields command packet
254         CommandPacket command = new CommandPacket(JDWP.Command.ReferenceType.Fields);
255         command.addReferenceTypeID(classID);
256         command.setLength();
257 
258         // send the command and receive reply
259         ReplyPacket reply = debugee.receiveReplyFor(command);
260 
261         // extract fieldIDs from the reply packet
262         try {
263             reply.resetPosition();
264 
265             int declared = reply.getInt();
266             long[] fieldIDs = new long[declared];
267 
268             for (int i = 0; i < declared; i++ ) {
269                 long fieldID = reply.getFieldID();
270                 String name = reply.getString();
271                 String signature = reply.getString();
272                 int modBits = reply.getInt();
273 
274                 fieldIDs[i] = fieldID;
275             }
276             return fieldIDs;
277         } catch (BoundException e) {
278             log.complain("Unable to parse reply packet for ReferenceType.Fields command:\n\t"
279                         + e);
280             log.complain("Received reply packet:\n"
281                         + reply);
282             throw new Failure("Error occured while getting static fieldIDs for classID: " + classID);
283         }
284     }
285 
286     /**
287      * Query debugee for values of the class static fields.
288      */
queryClassFieldValues(long classID, long fieldIDs[])289     JDWP.Value[] queryClassFieldValues(long classID, long fieldIDs[]) {
290         // compose ReferenceType.Fields command packet
291         int count = fieldIDs.length;
292         CommandPacket command = new CommandPacket(JDWP.Command.ReferenceType.GetValues);
293         command.addReferenceTypeID(classID);
294         command.addInt(count);
295         for (int i = 0; i < count; i++) {
296             command.addFieldID(fieldIDs[i]);
297         }
298         command.setLength();
299 
300         // send the command and receive reply
301         ReplyPacket reply = debugee.receiveReplyFor(command);
302 
303         // extract values from the reply packet
304         try {
305             reply.resetPosition();
306 
307             int valuesCount = reply.getInt();
308             JDWP.Value values[] = new JDWP.Value[valuesCount];
309             for (int i = 0; i < valuesCount; i++ ) {
310                 JDWP.Value value = reply.getValue();
311                 values[i] = value;
312             }
313             return values;
314         } catch (BoundException e) {
315             log.complain("Unable to parse reply packet for ReferenceType.GetValues command:\n\t"
316                         + e);
317             log.complain("Received reply packet:\n"
318                         + reply);
319             throw new Failure("Error occured while getting static fields values for classID: " + classID);
320         }
321     }
322 
323     /**
324      * Perform testing JDWP command for specified classID.
325      */
testCommand(long classID, long fieldIDs[], JDWP.Value values[])326     void testCommand(long classID, long fieldIDs[], JDWP.Value values[]) {
327         int count = fieldIDs.length;
328 
329         // create command packet
330         log.display("Create command packet:");
331         log.display("Command: " + JDWP_COMMAND_NAME);
332         CommandPacket command = new CommandPacket(JDWP_COMMAND_ID);
333 
334         // add out data to the command packet
335         log.display("  classID: " + classID);
336         command.addReferenceTypeID(classID);
337         log.display("  values: " + count);
338         command.addInt(count);
339         for (int i = 0; i < count; i++) {
340             log.display("    field #" + i +":");
341             log.display("      fieldID: " + fieldIDs[i]);
342             command.addFieldID(fieldIDs[i]);
343 
344             JDWP.Value value = values[i];
345             JDWP.UntaggedValue untaggedValue =
346                     new JDWP.UntaggedValue(value.getValue());
347             log.display("      untagged_value: " + untaggedValue.getValue());
348             command.addUntaggedValue(untaggedValue, value.getTag());
349         }
350         command.setLength();
351 
352         // send command packet to debugee
353         try {
354             log.display("Sending command packet:\n" + command);
355             transport.write(command);
356         } catch (IOException e) {
357             log.complain("Unable to send command packet:\n" + e);
358             success = false;
359             return;
360         }
361 
362         ReplyPacket reply = new ReplyPacket();
363 
364         // receive reply packet from debugee
365         try {
366             log.display("Waiting for reply packet");
367             transport.read(reply);
368             log.display("Reply packet received:\n" + reply);
369         } catch (IOException e) {
370             log.complain("Unable to read reply packet:\n" + e);
371             success = false;
372             return;
373         }
374 
375         // check reply packet header
376         try{
377             log.display("Checking reply packet header");
378             reply.checkHeader(command.getPacketID());
379         } catch (BoundException e) {
380             log.complain("Bad header of reply packet: " + e.getMessage());
381             success = false;
382         }
383 
384         // start parsing reply packet data
385         log.display("Parsing reply packet:");
386         reply.resetPosition();
387 
388         // no data to extract
389 
390         // check for extra data in reply packet
391         if (! reply.isParsed()) {
392             log.complain("Extra trailing bytes found in reply packet at: "
393                         + "0x" + reply.toHexString(reply.currentDataPosition(), 4));
394             success = false;
395         }
396     }
397 
398     /**
399      * Check confiramtion from debuggee that values are changed.
400      */
checkValuesChanged()401     void checkValuesChanged() {
402         // send debugee signal RUN
403         log.display("Sending signal to debugee: " + RUN);
404         pipe.println(RUN);
405 
406         // wait for DONE signal from debugee
407         log.display("Waiting for signal from debugee: " + DONE);
408         String signal = pipe.readln();
409         log.display("Received signal from debugee: " + signal);
410 
411         // check received signal
412         if (signal == null) {
413             throw new TestBug("<null> signal received from debugee: " + signal
414                             + " (expected: " + DONE + ")");
415         } else if (signal.equals(DONE)) {
416             log.display("All static fields values have been correctly set into debuggee VM");
417         } else if (signal.equals(ERROR)) {
418             log.complain("Not all static fields values have been correctly set into debuggee VM");
419             success = false;
420         } else {
421             throw new TestBug("Unexpected signal received from debugee: " + signal
422                             + " (expected: " + DONE + ")");
423         }
424     }
425 
426 }
427