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.jdi.ExceptionEvent.catchLocation;
25 
26 import com.sun.jdi.*;
27 import com.sun.jdi.event.*;
28 import com.sun.jdi.request.*;
29 
30 import java.io.*;
31 import java.util.Iterator;
32 import java.util.List;
33 
34 import nsk.share.*;
35 import nsk.share.jpda.*;
36 import nsk.share.jdi.*;
37 
38 
39 // This class is the debugger in the test
40 
41 public class location002 {
42     static final int PASSED = 0;
43     static final int FAILED = 2;
44     static final int JCK_STATUS_BASE = 95;
45 
46     // time interval to wait for events
47     static final int TIMEOUT_DELTA = 1000; // milliseconds
48 
49     // synchronization commands
50     static final String COMMAND_READY = "ready";
51     static final String COMMAND_QUIT  = "quit";
52     static final String COMMAND_GO    = "go";
53     static final String COMMAND_DONE  = "done";
54     static final String COMMAND_ERROR = "error";
55 
56     // checked classes names
57     static final String DEBUGGEE_NAME  = "nsk.jdi.ExceptionEvent.catchLocation.location002a";
58     static final String JAVA_EXCEPTION = "java.lang.NumberFormatException";
59 
60     // scaffold objects
61     static private Debugee debuggee;
62     static private VirtualMachine vm;
63     static private IOPipe pipe;
64     static private Log log;
65     static private ArgumentHandler argHandler;
66     static private EventSet eventSet;
67 
68     // timeout for waiting events
69     static private long eventTimeout;
70 
71     // mirrors for checked classes and threads in debuggee
72     static private ExceptionRequest  checkedRequest;
73     static private ReferenceType     checkedClass;
74     static private ThreadReference   checkedThread;
75 
76     // results of test execution
77     static private boolean eventsReceived;
78     static private boolean testFailed;
79 
80     // execute test from command line
main(String args[])81     public static void main (String args[]) {
82         System.exit(run(args, System.out) + JCK_STATUS_BASE);
83     }
84 
85     // execute test from JCK-compatible harness
run(final String args[], final PrintStream out)86     public static int run(final String args[], final PrintStream out) {
87 
88         testFailed = false;
89 
90         argHandler = new ArgumentHandler(args);
91         log = new Log(out, argHandler);
92         eventTimeout = argHandler.getWaitTime() * 60 * 1000; // milliseconds
93 
94         // launch debuggee
95         Binder binder = new Binder(argHandler, log);
96         log.display("Connecting to debuggee");
97         debuggee = binder.bindToDebugee(DEBUGGEE_NAME);
98         debuggee.redirectStderr(log, "location001a >");
99 
100         // create synchronization channel with debuggee
101         pipe = debuggee.createIOPipe();
102         vm = debuggee.VM();
103         EventRequestManager erManager = vm.eventRequestManager();
104 
105         // resume debuggee
106         log.display("Resuming debuggee");
107         debuggee.resume();
108 
109         // catch exceptions while testing and finally quit debuggee
110         try {
111 
112             // wait for debuggee started
113             log.display("Waiting for command: " + COMMAND_READY);
114             String command = pipe.readln();
115             if (!command.equals(COMMAND_READY)) {
116                 throw new Failure("TEST BUG: unexpected debuggee's command: " + command);
117             }
118 
119             // get mirrors of checked classes in debuggee
120             log.display("Getting loaded classes in debuggee");
121             if ((checkedClass = debuggee.classByName(DEBUGGEE_NAME)) == null) {
122                 throw new Failure("TEST BUG: cannot find " + DEBUGGEE_NAME);
123             }
124 
125             // get mirror of main thread in debuggee
126             log.display("Getting reference to main thread");
127             Iterator threadIterator = vm.allThreads().iterator();
128             while (threadIterator.hasNext()) {
129                 ThreadReference curThread = (ThreadReference) threadIterator.next();
130                 if (curThread.name().equals("main")) {
131                      checkedThread = curThread;
132                 }
133             }
134             if (checkedThread == null) {
135                 throw new Failure("TEST BUG: unable to find reference to main thread");
136             }
137 
138             // create ExceptionRequest for all throwable classes (initially disabled)
139             log.display("Creating ExceptionRequest");
140             boolean notifyCaught = true;
141             boolean notifyUncaught = true;
142             if ((checkedRequest = erManager.createExceptionRequest(null, notifyCaught, notifyUncaught)) == null) {
143                 throw new Failure("TEST BUG: unable to create ExceptionRequest");
144             }
145 
146             // define separate thread for handling received events
147             class EventHandler extends Thread {
148                 public void run() {
149                     // handle events until expected event received
150                     eventHandlingLoop:
151                     while (!eventsReceived) {
152                         eventSet = null;
153                         try {
154                             eventSet = vm.eventQueue().remove(TIMEOUT_DELTA);
155                         } catch (InterruptedException e) {
156                             log.complain("Unexpected InterruptedException while receiving event: " + e);
157                             break;
158                         }
159 
160                         if (eventSet == null) {
161                             continue;
162                         }
163 
164                         // handle each event from event set
165                         EventIterator eventIterator = eventSet.eventIterator();
166                         while (eventIterator.hasNext()) {
167 
168                             Event event = eventIterator.nextEvent();
169 //                            log.display("Event received:\n  " + event);
170 
171                             // break event handling loop if VMDisconnectEvent received
172                             if (event instanceof VMDisconnectEvent) {
173                                 log.display("VMDisconnectEvent received");
174                                 break eventHandlingLoop;
175                             }
176 
177                             // handle ExceptionEvent
178                             if (event instanceof ExceptionEvent) {
179                                 log.display("ExceptionEvent received");
180 
181                                 ExceptionEvent castedEvent  = (ExceptionEvent)event;
182                                 ReferenceType  eventRefType = castedEvent.exception().referenceType();
183 
184                                 String eventTypeName = eventRefType.name();
185                                 if (eventTypeName.equals(JAVA_EXCEPTION)) {
186                                     log.display("Expected ExceptionEvent for " + JAVA_EXCEPTION + " is received");
187                                     eventsReceived = true;
188 
189                                     Location catchLocation  = castedEvent.catchLocation();
190                                     if (catchLocation != null) {
191                                         log.complain("FAILURE 1: catchLocation for uncaught " + JAVA_EXCEPTION +
192                                                      " is not null :");
193                                         log.complain("declaring type: " + catchLocation.declaringType().name());
194                                         log.complain("line number   : " + catchLocation.lineNumber());
195                                     }
196 
197                                 }
198                             }
199 
200                             // ignore each other events
201 
202                         } // end of event handling loop
203 
204 //                        log.display("Resuming event set");
205                         eventSet.resume();
206 
207                     } // end of event set handling loop
208 
209                     log.display("eventHandler completed");
210 
211                 } // end of run()
212 
213             } // end of EventHandler
214 
215             // start EventHandler thread
216             EventHandler eventHandler = new EventHandler();
217             log.display("Starting eventHandler");
218             eventHandler.start();
219 
220             // enable event request
221             log.display("Enabling ExceptionRequest");
222             checkedRequest.enable();
223 
224             // force debuggee to throw exceptions and generate events
225             log.display("Sending command: " + COMMAND_GO);
226             pipe.println(COMMAND_GO);
227 
228             // wait for all expected events received or timeout exceeds
229             log.display("Waiting for all expected events received");
230             try {
231                 eventHandler.join(eventTimeout);
232                 if (eventHandler.isAlive()) {
233                     log.complain("FAILURE 20: Timeout for waiting event was exceeded");
234                     eventHandler.interrupt();
235                     testFailed = true;
236                 }
237             } catch (InterruptedException e) {
238                 log.complain("TEST INCOMPLETE: InterruptedException caught while waiting for eventHandler's death");
239                 testFailed = true;
240             }
241 
242             // complain if not all expected events received
243             if (!eventsReceived) {
244                 log.complain("FAILURE 2: " + JAVA_EXCEPTION + " was not received");
245                 testFailed= true;
246             }
247 
248             // end testing
249 
250         } catch (Failure e) {
251             log.complain("TEST FAILURE: " + e.getMessage());
252             testFailed = true;
253         } catch (Exception e) {
254             log.complain("Unexpected exception: " + e);
255             e.printStackTrace(out);
256             testFailed = true;
257         } finally {
258 
259             log.display("");
260 
261             // wait for debuggee exits and analize its exit code
262             log.display("Waiting for debuggee terminating");
263             int debuggeeStatus = debuggee.endDebugee();
264             log.display("Debuggee terminated with exit code: " + debuggeeStatus);
265         }
266 
267         // check test results
268         if (testFailed) {
269             log.complain("TEST FAILED");
270             return FAILED;
271         }
272 
273         log.display("TEST PASSED");
274         return PASSED;
275     }
276 }
277