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.NewInstance;
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.NewInstance.
34  *
35  * See newinst001.README for description of test execution.
36  *
37  * This class represents debugger part of the test.
38  * Test is executed by invoking method runIt().
39  * JDWP command is tested in the method testCommand().
40  *
41  * @see #runIt()
42  * @see #testCommand()
43  */
44 public class newinst001 {
45 
46     // exit status constants
47     static final int JCK_STATUS_BASE = 95;
48     static final int PASSED = 0;
49     static final int FAILED = 2;
50 
51     // package and classes names
52     static final String PACKAGE_NAME = "nsk.jdwp.ClassType.NewInstance";
53     static final String TEST_CLASS_NAME = PACKAGE_NAME + "." + "newinst001";
54     static final String DEBUGEE_CLASS_NAME = TEST_CLASS_NAME + "a";
55 
56     // tested JDWP command
57     static final String JDWP_COMMAND_NAME = "ClassType.NewInstance";
58     static final int JDWP_COMMAND_ID = JDWP.Command.ClassType.NewInstance;
59 
60     // tested class name and signature
61     static final String TESTED_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TestedObjectClass";
62     static final String TESTED_CLASS_SIGNATURE = "L" + TESTED_CLASS_NAME.replace('.', '/') + ";";
63 
64     // field and method names
65     static final String RESULT_FIELD_NAME = "result";
66     static final String TESTED_CONSTRUCTOR_NAME = "<init>";
67     static final String BREAKPOINT_METHOD_NAME = "run";
68     static final int BREAKPOINT_LINE_NUMBER = newinst001a.BREAKPOINT_LINE_NUMBER;
69 
70     // data for invoked method
71     static final int ARGUMENTS_COUNT = 1;
72     static final int INITIAL_VALUE = newinst001a.INITIAL_VALUE;
73     static final int ARGUMENT_VALUE = newinst001a.FINAL_VALUE;
74     static final int RETURN_VALUE = INITIAL_VALUE;
75     static final int INVOKE_OPTIONS = 0;
76 
77     // usual scaffold objects
78     ArgumentHandler argumentHandler = null;
79     Log log = null;
80     Binder binder = null;
81     Debugee debugee = null;
82     Transport transport = null;
83     IOPipe pipe = null;
84     boolean dead = false;
85 
86     // data obtained from debuggee
87     long classID = 0;
88     long threadID = 0;
89     long methodID = 0;
90 
91     // test passed or not
92     boolean success = true;
93 
94     // -------------------------------------------------------------------
95 
96     /**
97      * Start test from command line.
98      */
main(String argv[])99     public static void main(String argv[]) {
100         System.exit(run(argv,System.out) + JCK_STATUS_BASE);
101     }
102 
103     /**
104      * Start JCK-compilant test.
105      */
run(String argv[], PrintStream out)106     public static int run(String argv[], PrintStream out) {
107         return new newinst001().runIt(argv, out);
108     }
109 
110     // -------------------------------------------------------------------
111 
112     /**
113      * Perform test execution.
114      */
runIt(String argv[], PrintStream out)115     public int runIt(String argv[], PrintStream out) {
116 
117         // make log for debugger messages
118         argumentHandler = new ArgumentHandler(argv);
119         log = new Log(out, argumentHandler);
120 
121         // execute test and display results
122         try {
123             log.display("\n>>> Starting debugee \n");
124 
125             // launch debuggee
126             binder = new Binder(argumentHandler, log);
127             log.display("Launching debugee VM");
128             debugee = binder.bindToDebugee(DEBUGEE_CLASS_NAME);
129             transport = debugee.getTransport();
130             log.display("  ... debuggee launched");
131 
132             // set timeout for debuggee responces
133             int waitTime = argumentHandler.getWaitTime();  // minutes
134             long timeout = waitTime * 60 * 1000;           // milliseconds
135             log.display("Setting timeout for debuggee responces: " + waitTime + " minute(s)");
136             transport.setReadTimeout(timeout);
137             log.display("  ... timeout set");
138 
139             // wait for VM_INIT event
140             log.display("Waiting for VM_INIT event");
141             debugee.waitForVMInit();
142             log.display("  ... VM_INIT event received");
143 
144             // query debugee for VM-dependent ID sizes
145             log.display("Querying for IDSizes");
146             debugee.queryForIDSizes();
147             log.display("  ... size of VM-dependent types adjusted");
148 
149             // run the test
150             runTest();
151 
152             // wait for VM_DEATH event
153             log.display("Waiting for VM_DEATH event");
154             debugee.waitForVMDeath();
155             log.display("  ... VM_DEATH event received");
156             dead = true;
157 
158         } catch (Failure e) {
159             log.complain("TEST FAILED: " + e.getMessage());
160             success = false;
161         } catch (Exception e) {
162             e.printStackTrace(out);
163             log.complain("Caught unexpected exception while running the test:\n\t" + e);
164             success = false;
165         } finally {
166             log.display("\n>>> Finishing test \n");
167 
168             // disconnect debugee and wait for its exit
169             if (debugee != null) {
170                 quitDebugee();
171             }
172         }
173 
174         // check result
175         if (!success) {
176             log.complain("TEST FAILED");
177             return FAILED;
178         }
179         out.println("TEST PASSED");
180         return PASSED;
181     }
182 
183     /**
184      * Obtain required data and test JDWP command.
185      */
runTest()186     void runTest() {
187         log.display("\n>>> Obtaining required data \n");
188 
189         // wait for tested class loaded on debuggee startup and obtain its classID
190         log.display("Waiting for class loaded:\n\t" + TESTED_CLASS_NAME);
191         classID = debugee.waitForClassLoaded(TESTED_CLASS_NAME, JDWP.SuspendPolicy.ALL);
192         log.display("  ... got classID: " + classID);
193         log.display("");
194 
195         // query debuggee for tested methodID
196         log.display("Getting tested methodID by constructor name: " + TESTED_CONSTRUCTOR_NAME);
197         methodID = debugee.getMethodID(classID, TESTED_CONSTRUCTOR_NAME, true);
198         log.display("  ... got methodID: " + methodID);
199         log.display("");
200 
201         // set breakpoint and wait for debugee reached it
202         log.display("Waiting for breakpoint reached at: "
203                     + BREAKPOINT_METHOD_NAME + ":" +  BREAKPOINT_LINE_NUMBER);
204         threadID = debugee.waitForBreakpointReached(classID,
205                                                 BREAKPOINT_METHOD_NAME,
206                                                 BREAKPOINT_LINE_NUMBER,
207                                                 JDWP.SuspendPolicy.EVENT_THREAD);
208         log.display("  ... breakpoint reached with threadID: " + threadID);
209 
210         // test JDWP command
211         log.display("\n>> Testing JDWP command \n");
212         testCommand();
213 
214         // check command results
215         if (success) {
216             log.display("\n>>> Checking command results \n");
217             checkResult();
218         }
219 
220         // resume debuggee after the command
221         log.display("Resuming debuggee");
222         debugee.resume();
223         log.display("  ... debuggee resumed");
224     }
225 
226     /**
227      * Perform testing JDWP command.
228      */
testCommand()229     void testCommand() {
230         // create command packet and fill requred out data
231         log.display("Create command packet:");
232         log.display("Command: " + JDWP_COMMAND_NAME);
233         CommandPacket command = new CommandPacket(JDWP_COMMAND_ID);
234         log.display("  classID: " + classID);
235         command.addReferenceTypeID(classID);
236         log.display("  threadID: " + threadID);
237         command.addObjectID(threadID);
238         log.display("  methodID: " + methodID);
239         command.addMethodID(methodID);
240         log.display("  arguments: " + ARGUMENTS_COUNT);
241         command.addInt(ARGUMENTS_COUNT);
242         for (int i = 0; i < ARGUMENTS_COUNT; i++) {
243             JDWP.Value value = new JDWP.Value(JDWP.Tag.INT, new Integer(ARGUMENT_VALUE));
244             log.display("    arg: " + value);
245             command.addValue(value);
246         }
247         log.display("  options: " + INVOKE_OPTIONS);
248         command.addInt(INVOKE_OPTIONS);
249         command.setLength();
250 
251         // send command packet to debugee
252         try {
253             log.display("Sending command packet:\n" + command);
254             transport.write(command);
255         } catch (IOException e) {
256             log.complain("Unable to send command packet:\n\t" + e);
257             success = false;
258             return;
259         }
260 
261         // receive reply packet from debugee
262         ReplyPacket reply = new ReplyPacket();
263         try {
264             log.display("Waiting for reply packet");
265             transport.read(reply);
266             log.display("  ... reply packet received:\n" + reply);
267         } catch (IOException e) {
268             log.complain("Unable to read reply packet for tested command:\n\t" + e);
269             success = false;
270             return;
271         }
272 
273         // check reply packet header
274         try{
275             log.display("Checking header of reply packet");
276             reply.checkHeader(command.getPacketID());
277             log.display("  ... packet header is correct");
278         } catch (BoundException e) {
279             log.complain("Wrong header of reply packet for tested command:\n\t"
280                         + e.getMessage());
281             success = false;
282             return;
283         }
284 
285         // start parsing reply packet data
286         log.display("Parsing reply packet data:");
287         reply.resetPosition();
288 
289         // extract return value
290         JDWP.Value newObject = null;
291         try {
292             newObject = reply.getValue();
293             log.display("    newObject: " + newObject);
294         } catch (BoundException e) {
295             log.complain("Unable to extract returnValues from reply packet:\n\t"
296                         + e.getMessage());
297             success = false;
298             return;
299         }
300 
301         // extract exception tag
302         JDWP.Value exception = null;
303         try {
304             exception = reply.getValue();
305             log.display("    exception: " + exception);
306         } catch (BoundException e) {
307             log.complain("Unable to extract exception from reply packet:\n\t"
308                         + e.getMessage());
309             success = false;
310             return;
311         }
312 
313         // check for extra data in reply packet
314         if (!reply.isParsed()) {
315             log.complain("Extra trailing bytes found in reply packet at: "
316                         + reply.offsetString());
317             success = false;
318         }
319 
320         log.display("  ... packed data parsed");
321 
322         // check that return value is an integer
323         if (newObject.getTag() != JDWP.Tag.OBJECT) {
324             log.complain("Unexpected tag of returnValue returned: " + newObject.getTag()
325                         + " (expected: " + JDWP.Tag.OBJECT + ")");
326             success = false;
327         }
328 
329         // check that return value is as expected
330         long newObjectID = ((Long)newObject.getValue()).longValue();
331         if (newObjectID == 0) {
332             log.complain("Unexpected null objectID for newObject value returned: "
333                         + newObjectID + " (expected: not " + 0 + ")");
334             success = false;
335         }
336 
337         // check that exception value is an object
338         if (exception.getTag() != JDWP.Tag.OBJECT) {
339             log.complain("Unexpected tag of exception returned: " + exception.getTag()
340                         + " (expected: " + JDWP.Tag.OBJECT + ")");
341             success = false;
342         }
343 
344         // check that exception object is null
345         long exceptionID = ((Long)exception.getValue()).longValue();
346         if (exceptionID != 0) {
347             log.complain("Not null objectID for exception value returned: " + exceptionID
348                         + " (expected: " + 0 + ")");
349             success = false;
350         }
351     }
352 
353     /**
354      * Check result of the tested JDWP command.
355      */
checkResult()356     void checkResult() {
357         // query debuggee for result value from a static field
358         log.display("Getting result value from static field: " + RESULT_FIELD_NAME);
359         int result = queryInt(classID, RESULT_FIELD_NAME, JDWP.Tag.INT);
360         log.display("  ... got result: " + result);
361 
362         // check if the result value is changed as expected
363         if (result != ARGUMENT_VALUE) {
364             log.complain("Method has not been really invoked: \n\t"
365                         + "variable not changed by the method: " + result
366                         + " (expected: " + ARGUMENT_VALUE + ")");
367             success = false;
368         } else {
369             log.display("Method has been really invoked: \n\t"
370                         + " variable changed by the method: " + result
371                         + " (expected: " + ARGUMENT_VALUE + ")");
372         }
373     }
374 
375     /**
376      * Query debuggee for value of static field of the class.
377      */
queryFieldValue(long classID, String fieldName, byte tag)378     JDWP.Value queryFieldValue(long classID, String fieldName, byte tag) {
379         // get fieledID for static field (declared in the class)
380         long fieldID = debugee.getClassFieldID(classID, fieldName, true);
381         // get value of the field
382         JDWP.Value value = debugee.getStaticFieldValue(classID, fieldID);
383 
384         // check that value has THREAD tag
385         if (value.getTag() != tag) {
386             log.complain("unexpedted value tag returned from debuggee: " + value.getTag()
387                         + " (expected: " + tag + ")");
388             throw new Failure("Error occured while getting value from static field: "
389                             + fieldName);
390         }
391 
392         return value;
393     }
394 
395     /**
396      * Query debuggee for objectID value of static field of the class.
397      */
queryObjectID(long classID, String fieldName, byte tag)398     long queryObjectID(long classID, String fieldName, byte tag) {
399         JDWP.Value value = queryFieldValue(classID, fieldName, tag);
400         long objectID = ((Long)value.getValue()).longValue();
401         return objectID;
402     }
403 
404     /**
405      * Query debuggee for int value of static field of the class.
406      */
queryInt(long classID, String fieldName, byte tag)407     int queryInt(long classID, String fieldName, byte tag) {
408         JDWP.Value value = queryFieldValue(classID, fieldName, tag);
409         int intValue = ((Integer)value.getValue()).intValue();
410         return intValue;
411     }
412 
413     /**
414      * Sending debugee signal to quit and waiting for it exits.
415      */
quitDebugee()416     void quitDebugee() {
417         if (debugee == null)
418             return;
419 
420         // disconnect debuggee if not dead
421         if (!dead) {
422             try {
423                 log.display("Disconnecting debuggee");
424                 debugee.dispose();
425                 log.display("  ... debuggee disconnected");
426             } catch (Failure e) {
427                 log.display("Failed to finally dispose debuggee:\n\t" + e.getMessage());
428             }
429         }
430 
431         // wait for debugee exits
432         log.display("Waiting for debuggee exits");
433         int code = debugee.waitFor();
434         log.display("  ... debuggee finished with exit code: " + code);
435 
436         // analize debuggee exit status code
437         if (code != JCK_STATUS_BASE + PASSED) {
438             log.complain("Debuggee FAILED with exit code: " + code);
439         }
440     }
441 
442 }
443