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.InvokeMethod;
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.InvokeMethod.
34  *
35  * See invokemeth001.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 invokemeth001 {
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.InvokeMethod";
53     static final String TEST_CLASS_NAME = PACKAGE_NAME + "." + "invokemeth001";
54     static final String DEBUGEE_CLASS_NAME = TEST_CLASS_NAME + "a";
55 
56     // tested JDWP command
57     static final String JDWP_COMMAND_NAME = "ClassType.InvokeMethod";
58     static final int JDWP_COMMAND_ID = JDWP.Command.ClassType.InvokeMethod;
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_METHOD_NAME = "testedMethod";
67     static final String BREAKPOINT_METHOD_NAME = "run";
68     static final int BREAKPOINT_LINE_NUMBER = invokemeth001a.BREAKPOINT_LINE_NUMBER;
69 
70     // data for invoked method
71     static final int ARGUMENTS_COUNT = 1;
72     static final int INITIAL_VALUE = invokemeth001a.INITIAL_VALUE;
73     static final int ARGUMENT_VALUE = invokemeth001a.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     int waitTime = 0;  // minutes
85     long timeout = 0;  // milliseconds
86     boolean dead = false;
87     boolean success = true;
88 
89     // data obtained from debuggee
90     long classID = 0;
91     long threadID = 0;
92     long methodID = 0;
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 invokemeth001().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         waitTime = argumentHandler.getWaitTime();  // minutes
121         timeout = waitTime * 60 * 1000;           // milliseconds
122 
123         // execute test and display results
124         try {
125             log.display("\n>>> Starting debugee \n");
126 
127             // launch debuggee
128             binder = new Binder(argumentHandler, log);
129             log.display("Launching debugee VM");
130             debugee = binder.bindToDebugee(DEBUGEE_CLASS_NAME);
131             transport = debugee.getTransport();
132             log.display("  ... debuggee launched");
133 
134             // set timeout for debuggee responces
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             // prepare debuggee for testing and obtain required data
150             log.display("\n>>> Getting prepared for testing \n");
151             prepareForTest();
152 
153             // test JDWP command
154             log.display("\n>> Testing JDWP command \n");
155             testCommand();
156 
157             // check command results
158             if (success) {
159                 log.display("\n>>> Checking result of tested command \n");
160                 checkResult();
161             }
162 
163             // finish debuggee
164             log.display("\n>> Finishing debuggee \n");
165 
166             // resume debuggee after testing command
167             log.display("Resuming debuggee");
168             debugee.resume();
169             log.display("  ... debuggee resumed");
170 
171             // wait for VM_DEATH event
172             log.display("Waiting for VM_DEATH event");
173             debugee.waitForVMDeath();
174             log.display("  ... VM_DEATH event received");
175             dead = true;
176 
177         } catch (Failure e) {
178             log.complain("TEST FAILED: " + e.getMessage());
179             success = false;
180         } catch (Exception e) {
181             e.printStackTrace(out);
182             log.complain("Caught unexpected exception while running the test:\n\t" + e);
183             success = false;
184         } finally {
185             log.display("\n>>> Finishing test \n");
186 
187             // disconnect debugee and wait for its exit
188             if (debugee != null) {
189                 quitDebugee();
190             }
191         }
192 
193         // check result
194         if (!success) {
195             log.complain("TEST FAILED");
196             return FAILED;
197         }
198         out.println("TEST PASSED");
199         return PASSED;
200     }
201 
202     /**
203      * Get debuggee prepared for testing and obtain required data.
204      */
prepareForTest()205     void prepareForTest() {
206         // wait for tested class loaded on debuggee startup and obtain its classID
207         log.display("Waiting for class loaded:\n\t" + TESTED_CLASS_NAME);
208         classID = debugee.waitForClassLoaded(TESTED_CLASS_NAME, JDWP.SuspendPolicy.ALL);
209         log.display("  ... class loaded with classID: " + classID);
210         log.display("");
211 
212         // query debuggee for tested methodID
213         log.display("Getting tested methodID by name: " + TESTED_METHOD_NAME);
214         methodID = debugee.getMethodID(classID, TESTED_METHOD_NAME, true);
215         log.display("  ... got methodID: " + methodID);
216         log.display("");
217 
218         // set breakpoint and wait for debugee reached it
219         log.display("Waiting for breakpoint reached at: "
220                     + BREAKPOINT_METHOD_NAME + ":" +  BREAKPOINT_LINE_NUMBER);
221         threadID = debugee.waitForBreakpointReached(classID,
222                                                 BREAKPOINT_METHOD_NAME,
223                                                 BREAKPOINT_LINE_NUMBER,
224                                                 JDWP.SuspendPolicy.ALL);
225         log.display("  ... breakpoint reached with threadID: " + threadID);
226         log.display("Tested thread is suspended by breakpoint event");
227     }
228 
229     /**
230      * Perform testing JDWP command.
231      */
testCommand()232     void testCommand() {
233         // create command packet and fill requred out data
234         log.display("Create command packet:");
235         log.display("Command: " + JDWP_COMMAND_NAME);
236         CommandPacket command = new CommandPacket(JDWP_COMMAND_ID);
237         log.display("  classID: " + classID);
238         command.addReferenceTypeID(classID);
239         log.display("  threadID: " + threadID);
240         command.addObjectID(threadID);
241         log.display("  methodID: " + methodID);
242         command.addMethodID(methodID);
243         log.display("  arguments: " + ARGUMENTS_COUNT);
244         command.addInt(ARGUMENTS_COUNT);
245         for (int i = 0; i < ARGUMENTS_COUNT; i++) {
246             JDWP.Value value = new JDWP.Value(JDWP.Tag.INT, new Integer(ARGUMENT_VALUE));
247             log.display("    arg: " + value);
248             command.addValue(value);
249         }
250         log.display("  options: " + INVOKE_OPTIONS);
251         command.addInt(INVOKE_OPTIONS);
252         command.setLength();
253 
254         // send command packet to debugee
255         try {
256             log.display("Sending command packet:\n" + command);
257             transport.write(command);
258         } catch (IOException e) {
259             log.complain("Unable to send command packet:\n\t" + e);
260             success = false;
261             return;
262         }
263 
264         ReplyPacket reply = new ReplyPacket();
265 
266         // receive reply packet from debugee
267         try {
268             log.display("Waiting for reply packet");
269             transport.read(reply);
270             log.display("  ... reply packet received:\n" + reply);
271         } catch (IOException e) {
272             log.complain("Unable to read reply packet for tested command:\n\t" + e);
273             success = false;
274             return;
275         }
276 
277         // check reply packet header
278         try{
279             log.display("Checking header of reply packet");
280             reply.checkHeader(command.getPacketID());
281             log.display("  ... packet header is correct");
282         } catch (BoundException e) {
283             log.complain("Wrong header of reply packet for tested command:\n\t"
284                         + e.getMessage());
285             success = false;
286             return;
287         }
288 
289         // start parsing reply packet data
290         log.display("Parsing reply packet data:");
291         reply.resetPosition();
292 
293         // extract return value
294         JDWP.Value returnValue = null;
295         try {
296             returnValue = reply.getValue();
297             log.display("    returnValue: " + returnValue);
298         } catch (BoundException e) {
299             log.complain("Unable to extract returnValues from reply packet:\n\t"
300                         + e.getMessage());
301             success = false;
302             return;
303         }
304 
305         // extract exception tag
306         JDWP.Value exception = null;
307         try {
308             exception = reply.getValue();
309             log.display("    exception: " + exception);
310         } catch (BoundException e) {
311             log.complain("Unable to extract exception from reply packet:\n\t"
312                         + e.getMessage());
313             success = false;
314             return;
315         }
316 
317         // check for extra data in reply packet
318         if (!reply.isParsed()) {
319             log.complain("Extra trailing bytes found in reply packet at: "
320                         + reply.offsetString());
321             success = false;
322         }
323 
324         log.display("  ... packed data parsed");
325 
326         // check that return value is an integer
327         if (returnValue.getTag() != JDWP.Tag.INT) {
328             log.complain("Unexpected tag of returnValue returned: " + returnValue.getTag()
329                         + " (expected: " + JDWP.Tag.INT + ")");
330             success = false;
331         }
332 
333         // check that return value is as expected
334         int intValue = ((Integer)returnValue.getValue()).intValue();
335         if (intValue != RETURN_VALUE) {
336             log.complain("Unexpected value of returnValue returned: " + intValue
337                         + " (expected: " + RETURN_VALUE + ")");
338             success = false;
339         }
340 
341         // check that exception value is an object
342         if (exception.getTag() != JDWP.Tag.OBJECT) {
343             log.complain("Unexpected tag of exception returned: " + exception.getTag()
344                         + " (expected: " + JDWP.Tag.OBJECT + ")");
345             success = false;
346         }
347 
348         // check that exception object is null
349         long exceptionID = ((Long)exception.getValue()).longValue();
350         if (exceptionID != 0) {
351             log.complain("Non-null exception object returned: " + exceptionID
352                         + " (expected: " + 0 + ")");
353             success = false;
354         }
355     }
356 
357     /**
358      * Check result of the tested JDWP command.
359      */
checkResult()360     void checkResult() {
361         // query debuggee for result value from a static field
362         log.display("Getting result value from static field: " + RESULT_FIELD_NAME);
363         JDWP.Value value = debugee.getStaticFieldValue(classID, RESULT_FIELD_NAME, JDWP.Tag.INT);
364         int result = ((Integer)value.getValue()).intValue();
365         log.display("  ... got result: " + result);
366 
367         // check if the result value is changed as expected
368         if (result != ARGUMENT_VALUE) {
369             log.complain("Method has not been really invoked: \n\t"
370                         + "variable not changed by the method: " + result
371                         + " (expected: " + ARGUMENT_VALUE + ")");
372             success = false;
373         } else {
374             log.display("Method has been really invoked: \n\t"
375                         + " variable changed by the method: " + result
376                         + " (expected: " + ARGUMENT_VALUE + ")");
377         }
378     }
379 
380     /**
381      * Disconnect debuggee and wait for it exited.
382      */
quitDebugee()383     void quitDebugee() {
384         if (debugee == null)
385             return;
386 
387         // disconnect debugee
388         if (!dead) {
389             try {
390                 log.display("Disconnecting debuggee");
391                 debugee.dispose();
392                 log.display("  ... debuggee disconnected");
393             } catch (Failure e) {
394                 log.display("Failed to finally disconnect debuggee:\n\t"
395                             + e.getMessage());
396             }
397         }
398 
399         // wait for debugee exited
400         log.display("Waiting for debuggee exit");
401         int code = debugee.waitFor();
402         log.display("  ... debuggee exited with exit code: " + code);
403 
404         // analize debugee exit status code
405         if (code != JCK_STATUS_BASE + PASSED) {
406             log.complain("Debuggee FAILED with exit code: " + code);
407             success = false;
408         }
409     }
410 
411 }
412