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