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.MethodExitEvent._itself_; 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.List; 32 import java.util.Iterator; 33 34 import nsk.share.*; 35 import nsk.share.jpda.*; 36 import nsk.share.jdi.*; 37 38 39 // This class is the debugger application in the test 40 41 public class methodexit001 { 42 // exit status constants 43 static final int PASSED = 0; 44 static final int FAILED = 2; 45 static final int JCK_STATUS_BASE = 95; 46 47 // timeout interval for waiting events in a loop 48 static final int TIMEOUT_DELTA = 1000; // milliseconds 49 50 // synchronization commands 51 static final String COMMAND_READY = "ready"; 52 static final String COMMAND_QUIT = "quit"; 53 static final String COMMAND_GO = "go"; 54 static final String COMMAND_DONE = "done"; 55 56 // class names 57 static final String TEST_NAME = "nsk.jdi.MethodExitEvent._itself_.methodexit001"; 58 static final String DEBUGGEE_NAME = TEST_NAME + "a"; 59 60 // JDI scaffold objects 61 static private Debugee debuggee; 62 static private IOPipe pipe; 63 static private VirtualMachine vm; 64 static private Log log; 65 static private ArgumentHandler argHandler; 66 static private EventSet eventSet; 67 68 // mirrors for tested debuggee entities 69 static private MethodExitRequest checkedRequest; 70 static private Method checkedMethod; 71 static private ReferenceType checkedClass; 72 73 // auxilary breakpoints 74 static private BreakpointRequest startingBreakpointRequest; 75 static private BreakpointRequest endingBreakpointRequest; 76 static private Method runMethod; 77 78 // flags and counters 79 static private long eventTimeout; 80 static private int depthVal, eventsCounter; 81 static private volatile boolean testFailed, eventReceived; 82 83 // start test from command line main(String args[])84 public static void main (String args[]) { 85 System.exit(run(args, System.out) + JCK_STATUS_BASE); 86 } 87 88 // start test from JCK-compatible environment run(final String args[], final PrintStream out)89 public static int run(final String args[], final PrintStream out) { 90 91 testFailed = false; 92 eventReceived = false; 93 eventsCounter = 0; 94 95 argHandler = new ArgumentHandler(args); 96 log = new Log(out, argHandler); 97 eventTimeout = argHandler.getWaitTime() * 60 * 1000; // milliseconds 98 99 // launch debuggee 100 Binder binder = new Binder(argHandler, log); 101 log.display("Connecting to debuggee"); 102 debuggee = binder.bindToDebugee(DEBUGGEE_NAME); 103 debuggee.redirectStderr(log, "debuggee >"); 104 105 pipe = debuggee.createIOPipe(); 106 107 // resume debuggee 108 log.display("Resuming debuggee"); 109 debuggee.resume(); 110 111 try { 112 113 // wait for debugee started 114 log.display("Waiting for command: " + COMMAND_READY); 115 String command = pipe.readln(); 116 if (!command.equals(COMMAND_READY)) { 117 throw new Failure("TEST BUG: unknown debuggee's command: " + command); 118 } 119 120 // get mirrors for checked class, thread, and method 121 122 vm = debuggee.VM(); 123 124 log.display("Getting loaded class in debuggee"); 125 checkedClass = debuggee.classByName(DEBUGGEE_NAME); 126 127 log.display("Getting reference to method 'foo'"); 128 checkedMethod = debuggee.methodByName(checkedClass, "foo"); 129 130 // create event request (initially disabled) 131 132 EventRequestManager eventRManager = vm.eventRequestManager(); 133 134 log.display("Creating MethodExitRequest"); 135 if ((checkedRequest = eventRManager.createMethodExitRequest()) == null) { 136 throw new Failure("TEST BUG: unable to create MethodExitRequest"); 137 } 138 139 checkedRequest.addClassFilter(checkedClass); 140 log.display("MethodExitRequest is created"); 141 142 // create two auxilary breakpoints 143 144 log.display("Getting reference to method <run>"); 145 runMethod = debuggee.methodByName(checkedClass, "run"); 146 if (runMethod == null) { 147 throw new Failure("TEST BUG: returned null reference to method <run>"); 148 } 149 150 log.display("Creating two auxilary breakpoints into method <run>"); 151 startingBreakpointRequest = debuggee.setBreakpoint(runMethod, methodexit001a.STARTING_BREAKPOINT_LINE); 152 endingBreakpointRequest = debuggee.setBreakpoint(runMethod, methodexit001a.ENDING_BREAKPOINT_LINE); 153 154 // define separate thread for handling events 155 class EventHandler extends Thread { 156 public void run() { 157 eventSet = null; 158 try { 159 while (!eventReceived) { 160 eventSet = vm.eventQueue().remove(); 161 162 EventIterator eventIterator = eventSet.eventIterator(); 163 while (eventIterator.hasNext()) { 164 165 Event event = eventIterator.nextEvent(); 166 167 // enable or disable checked event request at BreakpointEvent 168 if (event instanceof BreakpointEvent) { 169 Location eventLocation = ((BreakpointEvent)event).location(); 170 int lineNumber = eventLocation.lineNumber(); 171 log.display("BreakpointEvent received for location " + lineNumber); 172 if (lineNumber == methodexit001a.STARTING_BREAKPOINT_LINE) { 173 log.display("Enabling MethodExitRequest at breakpoint before invoking method"); 174 checkedRequest.enable(); 175 } else if (lineNumber == methodexit001a.ENDING_BREAKPOINT_LINE) { 176 log.display("Disabling MethodExitRequest at breakpoint after invoking method"); 177 checkedRequest.disable(); 178 eventReceived = true; 179 } else { 180 testFailed = true; 181 throw new Failure("TEST BUG: Unknown location of breakpoint event: " + lineNumber); 182 } 183 } 184 185 // handle checked MethodEntryEvent 186 if (event instanceof MethodExitEvent) { 187 MethodExitEvent castedEvent = (MethodExitEvent) event; 188 EventRequest eventRequest = castedEvent.request(); 189 190 if (castedEvent.method().equals(checkedMethod)) { 191 eventsCounter++; 192 log.display("FAILURE 1: MethodExitEvent is received for method " + 193 checkedMethod.name() + " at location " + castedEvent.location().lineNumber()); 194 testFailed = true; 195 } 196 } 197 } 198 eventSet.resume(); 199 } 200 } catch (InterruptedException e) { 201 log.complain("TEST INCOMPLETE: caught InterruptedException while waiting for event"); 202 testFailed = true; 203 } catch (VMDisconnectedException e) { 204 log.complain("TEST INCOMPLETE: caught VMDisconnectedException while waiting for event"); 205 testFailed = true; 206 } 207 log.display("eventHandler completed"); 208 } 209 } 210 211 // start event handling thread 212 EventHandler eventHandler = new EventHandler(); 213 log.display("Starting eventHandler"); 214 eventHandler.start(); 215 216 // force debuggee to invoke method 217 log.display("Sending command: " + COMMAND_GO); 218 pipe.println(COMMAND_GO); 219 220 log.display(""); 221 222 // waiting for debuggee comfirms method invoked 223 log.display("Waiting for command: " + COMMAND_DONE); 224 command = pipe.readln(); 225 if (!command.equals(COMMAND_DONE)) { 226 throw new Failure("TEST BUG: unknown debuggee's command: " + command); 227 } 228 229 log.display(""); 230 231 // wait for all expected events received or timeout exceeds 232 log.display("Waiting for all expected events received"); 233 try { 234 eventHandler.join(eventTimeout); 235 if (eventHandler.isAlive()) { 236 log.complain("FAILURE 20: Timeout for waiting event was exceeded"); 237 eventHandler.interrupt(); 238 testFailed = true; 239 } 240 } catch (InterruptedException e) { 241 log.complain("TEST INCOMPLETE: InterruptedException caught while waiting for eventHandler's death"); 242 testFailed = true; 243 } 244 245 // check whether all expected events received or not 246 if (eventsCounter == 0) { 247 log.display("No any MethodExitEvent received for checked method as expected"); 248 } 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 // force debuggee to exit 262 log.display("Sending command: " + COMMAND_QUIT); 263 pipe.println(COMMAND_QUIT); 264 265 // wait for debuggee exits and analyze its exit code 266 log.display("Waiting for debuggee terminating"); 267 int debuggeeStatus = debuggee.endDebugee(); 268 if (debuggeeStatus == PASSED + JCK_STATUS_BASE) { 269 log.display("Debuggee PASSED with exit code: " + debuggeeStatus); 270 } else { 271 log.complain("Debuggee FAILED with exit code: " + debuggeeStatus); 272 testFailed = true; 273 } 274 } 275 276 // check test results 277 if (testFailed) { 278 log.complain("TEST FAILED"); 279 return FAILED; 280 } 281 282 log.display("TEST PASSED"); 283 return PASSED; 284 285 } 286 } 287