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.Event.SINGLE_STEP;
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 event: SINGLE_STEP.
34  *
35  * See singlestep002.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 event is tested in the method waitForTestedEvent().
40  *
41  * @see #runIt()
42  * @see #waitForTestedEvent()
43  */
44 public class singlestep002 {
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 constants
52     static final String PACKAGE_NAME = "nsk.jdwp.Event.SINGLE_STEP";
53     static final String TEST_CLASS_NAME = PACKAGE_NAME + "." + "singlestep002";
54     static final String DEBUGEE_CLASS_NAME = TEST_CLASS_NAME + "a";
55 
56     // tested JDWP event constants
57     static final byte TESTED_EVENT_KIND = JDWP.EventKind.SINGLE_STEP;
58     static final byte TESTED_EVENT_SUSPEND_POLICY = JDWP.SuspendPolicy.ALL;
59     static final int STEP_DEPTH = JDWP.StepDepth.INTO;
60     static final int STEP_SIZE = JDWP.StepSize.LINE;
61 
62     // name and signature of the tested class
63     static final String TESTED_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TestedClass";
64     static final String TESTED_CLASS_SIGNATURE = "L" + TESTED_CLASS_NAME.replace('.', '/') + ";";
65     static final String TESTED_THREAD_NAME = "TestedThread";
66 
67     // name of field and method of tested class
68     static final String THREAD_FIELD_NAME = "thread";
69     static final String BREAKPOINT_METHOD_NAME = "run";
70     static final String STEP_METHOD_NAME = "methodForStep";
71     static final int BREAKPOINT_LINE = singlestep002a.BREAKPOINT_LINE;
72     static final int SINGLE_STEP_LINE = singlestep002a.SINGLE_STEP_LINE;
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     int waitTime = 0;  // minutes
81     long timeout = 0;  // milliseconds
82     boolean dead = false;
83     boolean success = true;
84 
85     // obtained data
86     long testedClassID = 0;
87     long testedThreadID = 0;
88     long testedMethodID = 0;
89     long stepMethodID = 0;
90     JDWP.Location testedLocation = null;
91     int eventRequestID = 0;
92 
93     // -------------------------------------------------------------------
94 
95     /**
96      * Start test from command line.
97      */
main(String argv[])98     public static void main(String argv[]) {
99         System.exit(run(argv,System.out) + JCK_STATUS_BASE);
100     }
101 
102     /**
103      * Start test from JCK-compilant environment.
104      */
run(String argv[], PrintStream out)105     public static int run(String argv[], PrintStream out) {
106         return new singlestep002().runIt(argv, out);
107     }
108 
109     // -------------------------------------------------------------------
110 
111     /**
112      * Perform test execution.
113      */
runIt(String argv[], PrintStream out)114     public int runIt(String argv[], PrintStream out) {
115 
116         // make log for debugger messages
117         argumentHandler = new ArgumentHandler(argv);
118         log = new Log(out, argumentHandler);
119         waitTime = argumentHandler.getWaitTime();
120         timeout = waitTime * 60 * 1000;
121 
122         // execute test and display results
123         try {
124             log.display("\n>>> Starting debugee \n");
125 
126             // launch debuggee
127             binder = new Binder(argumentHandler, log);
128             log.display("Launching debugee");
129             debugee = binder.bindToDebugee(DEBUGEE_CLASS_NAME);
130             transport = debugee.getTransport();
131             log.display("  ... debugee launched");
132             log.display("");
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 debuggee started
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
150             log.display("\n>>> Getting prepared for testing \n");
151             prepareForTest();
152 
153             // test JDWP event
154             log.display("\n>>> Testing JDWP event \n");
155             log.display("Making request for SINGLE_STEP event for class:\n\t"
156                     + TESTED_CLASS_NAME);
157             requestTestedEvent();
158             log.display("  ... got requestID: " + eventRequestID);
159             log.display("");
160 
161             // resume debuggee
162             log.display("Resumindg debuggee");
163             debugee.resume();
164             log.display("  ... debuggee resumed");
165             log.display("");
166 
167             // wait for tested SINGLE_STEP event
168             log.display("Waiting for SINGLE_STEP event received");
169             waitForTestedEvent();
170             log.display("  ... event received");
171             log.display("");
172 
173             // clear tested request for SINGLE_STEP event
174             log.display("Clearing request for tested event");
175             clearTestedRequest();
176             log.display("  ... request removed");
177 
178             // finish debuggee after testing
179             log.display("\n>>> Finishing debuggee \n");
180 
181             // resume debuggee
182             log.display("Resuming debuggee");
183             debugee.resume();
184             log.display("  ... debuggee resumed");
185 
186             // wait for debuggee exited
187             log.display("Waiting for VM_DEATH event");
188             debugee.waitForVMDeath();
189             dead = true;
190             log.display("  ... VM_DEATH event received");
191 
192         } catch (Failure e) {
193             log.complain("TEST FAILED: " + e.getMessage());
194             success = false;
195         } catch (Exception e) {
196             e.printStackTrace(out);
197             log.complain("Caught unexpected exception while running the test:\n\t" + e);
198             success = false;
199         } finally {
200             // quit debugee
201             log.display("\n>>> Finishing test \n");
202             quitDebugee();
203         }
204 
205         // check test results
206         if (!success) {
207             log.complain("TEST FAILED");
208             return FAILED;
209         }
210 
211         out.println("TEST PASSED");
212         return PASSED;
213 
214     }
215 
216     /**
217      * Get debuggee prepared for testing and obtain required data.
218      */
prepareForTest()219     void prepareForTest() {
220         // wait for tested class loaded
221         log.display("Waiting for tested class loaded");
222         testedClassID = debugee.waitForClassLoaded(TESTED_CLASS_NAME, JDWP.SuspendPolicy.ALL);
223         log.display("  ... got classID: " + testedClassID);
224         log.display("");
225 
226         // get methodID for the tested method
227         log.display("Getting tested methodID for method name: " + BREAKPOINT_METHOD_NAME);
228         testedMethodID = debugee.getMethodID(testedClassID, BREAKPOINT_METHOD_NAME, true);
229         log.display("  ... got methodID: " + testedMethodID);
230 
231         // get methodID for the method with STEP_EVENT
232         log.display("Getting methodID for STEP_EVENT method name: " + STEP_METHOD_NAME);
233         stepMethodID = debugee.getMethodID(testedClassID, STEP_METHOD_NAME, true);
234         log.display("  ... got methodID: " + stepMethodID);
235 
236         // get codeIndex for method entry line
237         log.display("Getting codeIndex for single step line: " + SINGLE_STEP_LINE);
238         long codeIndex = debugee.getCodeIndex(testedClassID, stepMethodID, SINGLE_STEP_LINE);
239         log.display("  ... got index: " + codeIndex);
240 
241         // create location for method entry line
242         log.display("Creating location of single step event");
243         testedLocation = new JDWP.Location(JDWP.TypeTag.CLASS, testedClassID,
244                                                         stepMethodID, codeIndex);
245         log.display("  ... got location: " + testedLocation);
246         log.display("");
247 
248         // wait for breakpoint reached
249         log.display("Waiting for breakpoint reached at: "
250                         + BREAKPOINT_METHOD_NAME + ":" + BREAKPOINT_LINE);
251         testedThreadID = debugee.waitForBreakpointReached(testedClassID,
252                                                         BREAKPOINT_METHOD_NAME,
253                                                         BREAKPOINT_LINE,
254                                                         JDWP.SuspendPolicy.ALL);
255         log.display("  ... breakpoint reached with threadID: " + testedThreadID);
256         log.display("");
257     }
258 
259     /**
260      * Make request for tested SINGLE_STEP event.
261      */
requestTestedEvent()262     void requestTestedEvent() {
263         Failure failure = new Failure("Error occured while makind request for tested event");
264 
265         // create command packet and fill requred out data
266         log.display("Create command packet: " + "EventRequest.Set");
267         CommandPacket command = new CommandPacket(JDWP.Command.EventRequest.Set);
268         log.display("    eventKind: " + TESTED_EVENT_KIND);
269         command.addByte(TESTED_EVENT_KIND);
270         log.display("    eventPolicy: " + TESTED_EVENT_SUSPEND_POLICY);
271         command.addByte(TESTED_EVENT_SUSPEND_POLICY);
272         log.display("    modifiers: " + 1);
273         command.addInt(1);
274         log.display("      modKind: " + JDWP.EventModifierKind.STEP + " (STEP)");
275         command.addByte(JDWP.EventModifierKind.STEP);
276         log.display("      threadID: " + testedThreadID);
277         command.addObjectID(testedThreadID);
278         log.display("      size: " + STEP_SIZE);
279         command.addInt(STEP_SIZE);
280         log.display("      depth: " + STEP_DEPTH);
281         command.addInt(STEP_DEPTH);
282         command.setLength();
283         log.display("  ... command packet composed");
284         log.display("");
285 
286         // send command packet to debugee
287         try {
288             log.display("Sending command packet:\n" + command);
289             transport.write(command);
290             log.display("  ... command packet sent");
291         } catch (IOException e) {
292             log.complain("Unable to send command packet:\n\t" + e);
293             success = false;
294             throw failure;
295         }
296         log.display("");
297 
298         ReplyPacket reply = new ReplyPacket();
299 
300         // receive reply packet from debugee
301         try {
302             log.display("Waiting for reply packet");
303             transport.read(reply);
304             log.display("  ... packet received:\n" + reply);
305         } catch (IOException e) {
306             log.complain("Unable to read reply packet:\n\t" + e);
307             success = false;
308             throw failure;
309         }
310         log.display("");
311 
312         // check reply packet header
313         try{
314             log.display("Checking header of reply packet");
315             reply.checkHeader(command.getPacketID());
316             log.display("  .. packet header is correct");
317         } catch (BoundException e) {
318             log.complain("Bad header of reply packet:\n\t" + e.getMessage());
319             success = false;
320             throw failure;
321         }
322 
323         // start parsing reply packet data
324         log.display("Parsing reply packet:");
325         reply.resetPosition();
326 
327         // extract requestID
328         int requestID = 0;
329         try {
330             requestID = reply.getInt();
331             log.display("    requestID: " + requestID);
332         } catch (BoundException e) {
333             log.complain("Unable to extract requestID from request reply packet:\n\t"
334                         + e.getMessage());
335             success = false;
336             throw failure;
337         }
338 
339         // check requestID
340         if (requestID == 0) {
341             log.complain("Unexpected null requestID returned: " + requestID);
342             success = false;
343             throw failure;
344         }
345 
346         eventRequestID = requestID;
347 
348         // check for extra data in reply packet
349         if (!reply.isParsed()) {
350             log.complain("Extra trailing bytes found in request reply packet at: "
351                         + reply.offsetString());
352             success = false;
353         }
354 
355         log.display("  ... reply packet parsed");
356     }
357 
358     /**
359      * Clear request for tested SINGLE_STEP event.
360      */
clearTestedRequest()361     void clearTestedRequest() {
362         Failure failure = new Failure("Error occured while clearing request for tested event");
363 
364         // create command packet and fill requred out data
365         log.display("Create command packet: " + "EventRequest.Clear");
366         CommandPacket command = new CommandPacket(JDWP.Command.EventRequest.Clear);
367         log.display("    event: " + TESTED_EVENT_KIND);
368         command.addByte(TESTED_EVENT_KIND);
369         log.display("    requestID: " + eventRequestID);
370         command.addInt(eventRequestID);
371         log.display("  ... command packet composed");
372         log.display("");
373 
374         // send command packet to debugee
375         try {
376             log.display("Sending command packet:\n" + command);
377             transport.write(command);
378             log.display("  ... command packet sent");
379         } catch (IOException e) {
380             log.complain("Unable to send command packet:\n\t" + e);
381             success = false;
382             throw failure;
383         }
384         log.display("");
385 
386         ReplyPacket reply = new ReplyPacket();
387 
388         // receive reply packet from debugee
389         try {
390             log.display("Waiting for reply packet");
391             transport.read(reply);
392             log.display("  ... packet received:\n" + reply);
393         } catch (IOException e) {
394             log.complain("Unable to read reply packet:\n\t" + e);
395             success = false;
396             throw failure;
397         }
398 
399         // check reply packet header
400         try{
401             log.display("Checking header of reply packet");
402             reply.checkHeader(command.getPacketID());
403             log.display("  .. packet header is correct");
404         } catch (BoundException e) {
405             log.complain("Bad header of reply packet:\n\t" + e.getMessage());
406             success = false;
407             throw failure;
408         }
409 
410         // start parsing reply packet data
411         log.display("Parsing reply packet:");
412         reply.resetPosition();
413 
414         log.display("    no data");
415 
416         // check for extra data in reply packet
417         if (!reply.isParsed()) {
418             log.complain("Extra trailing bytes found in request reply packet at: "
419                         + reply.offsetString());
420             success = false;
421         }
422 
423         log.display("  ... reply packet parsed");
424     }
425 
426     /**
427      * Wait for tested SINGLE_STEP event.
428      */
waitForTestedEvent()429     void waitForTestedEvent() {
430 
431         EventPacket eventPacket = null;
432 
433         // receive reply packet from debugee
434         try {
435             log.display("Waiting for event packet");
436             eventPacket = debugee.getEventPacket(timeout);
437             log.display("  ... event packet received:\n" + eventPacket);
438         } catch (IOException e) {
439             log.complain("Unable to read tested event packet:\n\t" + e);
440             success = false;
441             return;
442         }
443         log.display("");
444 
445         // check reply packet header
446         try{
447             log.display("Checking header of event packet");
448             eventPacket.checkHeader();
449             log.display("  ... packet header is correct");
450         } catch (BoundException e) {
451             log.complain("Bad header of tested event packet:\n\t"
452                         + e.getMessage());
453             success = false;
454             return;
455         }
456 
457         // start parsing reply packet data
458         log.display("Parsing event packet:");
459         eventPacket.resetPosition();
460 
461         // get suspendPolicy value
462         byte suspendPolicy = 0;
463         try {
464             suspendPolicy = eventPacket.getByte();
465             log.display("    suspendPolicy: " + suspendPolicy);
466         } catch (BoundException e) {
467             log.complain("Unable to get suspendPolicy value from tested event packet:\n\t"
468                         + e.getMessage());
469             success = false;
470             return;
471         }
472 
473         // check suspendPolicy value
474         if (suspendPolicy != TESTED_EVENT_SUSPEND_POLICY) {
475             log.complain("Unexpected SuspendPolicy in tested event packet: " +
476                         suspendPolicy + " (expected: " + TESTED_EVENT_SUSPEND_POLICY + ")");
477             success = false;
478         }
479 
480         // get events count
481         int events = 0;
482         try {
483             events = eventPacket.getInt();
484             log.display("    events: " + events);
485         } catch (BoundException e) {
486             log.complain("Unable to get events count from tested event packet:\n\t"
487                         + e.getMessage());
488             success = false;
489             return;
490         }
491 
492         // check events count
493         if (events < 0) {
494             log.complain("Negative value of events number in tested event packet: " +
495                         events + " (expected: " + 1 + ")");
496             success = false;
497         } else if (events != 1) {
498             log.complain("Invalid number of events in tested event packet: " +
499                         events + " (expected: " + 1 + ")");
500             success = false;
501         }
502 
503         // extract each event
504         long eventThreadID = 0;
505         for (int i = 0; i < events; i++) {
506             log.display("    event #" + i + ":");
507 
508             // get eventKind
509             byte eventKind = 0;
510             try {
511                 eventKind = eventPacket.getByte();
512                 log.display("      eventKind: " + eventKind);
513             } catch (BoundException e) {
514                 log.complain("Unable to get eventKind of event #" + i + " from tested event packet:\n\t"
515                             + e.getMessage());
516                 success = false;
517                 return;
518             }
519 
520             // check eventKind
521             if (eventKind == JDWP.EventKind.VM_DEATH) {
522                 log.complain("Unexpected VM_DEATH event received: " +
523                             eventKind + " (expected: " + JDWP.EventKind.SINGLE_STEP + ")");
524                 dead = true;
525                 success = false;
526                 return;
527             }  else if (eventKind != JDWP.EventKind.SINGLE_STEP) {
528                 log.complain("Unexpected eventKind of event " + i + " in tested event packet: " +
529                             eventKind + " (expected: " + JDWP.EventKind.SINGLE_STEP + ")");
530                 success = false;
531                 return;
532             }
533 
534             // get requestID
535             int requestID = 0;
536             try {
537                 requestID = eventPacket.getInt();
538                 log.display("      requestID: " + requestID);
539             } catch (BoundException e) {
540                 log.complain("Unable to get requestID of event #" + i + " from tested event packet:\n\t"
541                             + e.getMessage());
542                 success = false;
543                 return;
544             }
545 
546             // check requestID
547             if (requestID != eventRequestID) {
548                 log.complain("Unexpected requestID of event " + i + " in tested event packet: " +
549                             requestID + " (expected: " + eventRequestID + ")");
550                 success = false;
551             }
552 
553             // get threadID
554             long threadID = 0;
555             try {
556                 threadID = eventPacket.getObjectID();
557                 log.display("      threadID: " + threadID);
558             } catch (BoundException e) {
559                 log.complain("Unable to get threadID of event #" + i + " from tested event packet:\n\t"
560                             + e.getMessage());
561                 success = false;
562                 return;
563             }
564 
565             // check threadID
566             if (threadID != testedThreadID) {
567                 log.complain("Unexpected threadID of event " + i + " in tested event packet: " +
568                             threadID + " (expected: " + testedThreadID + ")");
569                 success = false;
570             }
571 
572             // get location
573             JDWP.Location location = null;
574             try {
575                 location = eventPacket.getLocation();
576                 log.display("      location: " + location);
577             } catch (BoundException e) {
578                 log.complain("Unable to get location of event #" + i + " from tested event packet:\n\t"
579                             + e.getMessage());
580                 success = false;
581                 return;
582             }
583 
584             // check location
585             if (location.getTag() != testedLocation.getTag()) {
586                 log.complain("Unexpected class tag of location of event " + i
587                             + " in tested event packet: " + location.getTag()
588                             + " (expected: " + testedLocation.getTag() + ")");
589                 success = false;
590             }
591             if (location.getClassID() != testedLocation.getClassID()) {
592                 log.complain("Unexpected classID of location of event " + i
593                             + " in tested event packet: " + location.getClassID()
594                             + " (expected: " + testedLocation.getClassID() + ")");
595                 success = false;
596             }
597             if (location.getMethodID() != testedLocation.getMethodID()) {
598                 log.complain("Unexpected methodID of location of event " + i
599                             + " in tested event packet: " + location.getMethodID()
600                             + " (expected: " + testedLocation.getMethodID() + ")");
601                 success = false;
602             }
603             if (location.getIndex() != testedLocation.getIndex()) {
604                 log.complain("Unexpected codeIndex of location of event " + i
605                             + " in tested event packet: " + location.getIndex()
606                             + " (expected: " + testedLocation.getIndex() + ")");
607                 success = false;
608             }
609         }
610 
611         // check for extra data in event packet
612         if (!eventPacket.isParsed()) {
613             log.complain("Extra trailing bytes found in event packet at: "
614                         + eventPacket.offsetString());
615             success = false;
616         }
617 
618         log.display("  ... event packet parsed");
619     }
620 
621     /**
622      * Disconnect debuggee and wait for it exited.
623      */
quitDebugee()624     void quitDebugee() {
625         if (debugee == null)
626             return;
627 
628         // disconnect debugee
629         if (!dead) {
630             try {
631                 log.display("Disconnecting debuggee");
632                 debugee.dispose();
633                 log.display("  ... debuggee disconnected");
634             } catch (Failure e) {
635                 log.display("Failed to finally disconnect debuggee:\n\t"
636                             + e.getMessage());
637             }
638         }
639 
640         // wait for debugee exited
641         log.display("Waiting for debuggee exit");
642         int code = debugee.waitFor();
643         log.display("  ... debuggee exited with exit code: " + code);
644 
645         // analize debugee exit status code
646         if (code != JCK_STATUS_BASE + PASSED) {
647             log.complain("Debuggee FAILED with exit code: " + code);
648             success = false;
649         }
650     }
651 
652 }
653