1 /* 2 * Copyright (c) 2002, 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.ThreadReference.popFrames; 25 26 import com.sun.jdi.*; 27 import com.sun.jdi.event.*; 28 import com.sun.jdi.request.*; 29 30 import java.util.*; 31 import java.io.*; 32 33 import nsk.share.*; 34 import nsk.share.jpda.*; 35 import nsk.share.jdi.*; 36 37 /** 38 * The test checks that the JDI method:<br> 39 * <code>com.sun.jdi.ThreadReference.popFrames()</code><br> 40 * properly throws <i>IncompatibleThreadStateException</i> or 41 * <i>InvalidStackFrameException</i>, if specified thread is resumed. 42 * 43 * <p>Note, the test is pending decision on the bug:<p> 44 * 45 * 4512840 JDI spec: for ThreadReference.popFrame() needs clarification<p> 46 * 47 * Actually, only one exception should be thrown in case of resumed 48 * thread instead of two ones. 49 */ 50 public class popframes006 { 51 static final String DEBUGGEE_CLASS = 52 "nsk.jdi.ThreadReference.popFrames.popframes006t"; 53 54 // name of debuggee's main thread 55 static final String DEBUGGEE_THRNAME = "popframes006tThr"; 56 // debuggee local var used to find needed stack frame 57 static final String DEBUGGEE_LOCALVAR = "popframes006tFindMe"; 58 // debuggee field used to indicate that popping has been done 59 static final String DEBUGGEE_FIELD = "wasPopped"; 60 61 // debuggee source line where it should be stopped 62 static final int DEBUGGEE_STOPATLINE = 80; 63 64 static final int ATTEMPTS = 5; 65 static final int DELAY = 500; // in milliseconds 66 67 static final String COMMAND_READY = "ready"; 68 static final String COMMAND_GO = "go"; 69 static final String COMMAND_QUIT = "quit"; 70 71 private ArgumentHandler argHandler; 72 private Log log; 73 private IOPipe pipe; 74 private Debugee debuggee; 75 private VirtualMachine vm; 76 private BreakpointRequest BPreq; 77 private ObjectReference objRef; 78 private volatile int tot_res = Consts.TEST_PASSED; 79 private volatile boolean gotEvent = false; 80 main(String argv[])81 public static void main (String argv[]) { 82 System.exit(run(argv,System.out) + Consts.JCK_STATUS_BASE); 83 } 84 run(String argv[], PrintStream out)85 public static int run(String argv[], PrintStream out) { 86 return new popframes006().runIt(argv, out); 87 } 88 runIt(String args[], PrintStream out)89 private int runIt(String args[], PrintStream out) { 90 argHandler = new ArgumentHandler(args); 91 log = new Log(out, argHandler); 92 Binder binder = new Binder(argHandler, log); 93 94 debuggee = binder.bindToDebugee(DEBUGGEE_CLASS); 95 pipe = debuggee.createIOPipe(); 96 vm = debuggee.VM(); 97 debuggee.redirectStderr(log, "popframes006t.err> "); 98 debuggee.resume(); 99 String cmd = pipe.readln(); 100 if (!cmd.equals(COMMAND_READY)) { 101 log.complain("TEST BUG: unknown debuggee command: " + cmd); 102 tot_res = Consts.TEST_FAILED; 103 return quitDebuggee(); 104 } 105 106 ThreadReference thrRef = null; 107 if ((thrRef = 108 debuggee.threadByName(DEBUGGEE_THRNAME)) == null) { 109 log.complain("TEST FAILURE: method Debugee.threadByName() returned null for debuggee thread " 110 + DEBUGGEE_THRNAME); 111 tot_res = Consts.TEST_FAILED; 112 return quitDebuggee(); 113 } 114 115 Field doExit = null; 116 try { 117 // debuggee main class 118 ReferenceType rType = debuggee.classByName(DEBUGGEE_CLASS); 119 120 suspendAtBP(rType, DEBUGGEE_STOPATLINE); 121 122 // debuggee field used to indicate that popping has been done 123 doExit = rType.fieldByName(DEBUGGEE_FIELD); 124 125 // debuggee stack frame to be popped 126 StackFrame stFrame = findFrame(thrRef, DEBUGGEE_LOCALVAR); 127 128 log.display("\nTrying to pop stack frame \"" + stFrame 129 + "\"\n\tlocation \"" + stFrame.location() 130 + "\"\n\tgot from thread reference \"" + thrRef 131 + "\"\n\twith resumed debuggee thread ..."); 132 133 log.display("Resuming debuggee ..."); 134 vm.resume(); 135 136 // wait for the thread resumption 137 int num = 0; 138 while (thrRef.isSuspended()) { 139 if (num > ATTEMPTS) 140 throw new Failure("unable to continue testing after " 141 + ATTEMPTS 142 + " attempts: debuggee thread " 143 + thrRef + " is not resumed yet"); 144 145 Thread.currentThread().sleep(DELAY); 146 num++; 147 } 148 log.display("Debugee is resumed"); 149 150 // Check the tested assersion 151 try { 152 thrRef.popFrames(stFrame); 153 log.complain("TEST FAILED: expected IncompatibleThreadStateException or InvalidStackFrameException was not thrown" 154 + "\n\twhen attempted to pop stack frame got from thread reference \"" 155 + thrRef + "\"\n\twith resumed debuggee thread"); 156 tot_res = Consts.TEST_FAILED; 157 // actually, it should be only one expected exception instead of two ones: 158 // see the bug 4512840 159 } catch(IncompatibleThreadStateException ee) { 160 log.display("CHECK PASSED: caught expected " + ee); 161 } catch(InvalidStackFrameException ee2) { 162 log.display("CHECK PASSED: caught expected " + ee2); 163 } catch(UnsupportedOperationException une) { 164 if (vm.canPopFrames()) { 165 une.printStackTrace(); 166 log.complain("TEST FAILED: caught exception: " + une 167 + "\n\tHowever, VirtualMachine.canPopFrames() shows, that the target VM" 168 + "\n\tdoes support popping frames of a threads stack: " 169 + vm.canPopFrames()); 170 tot_res = Consts.TEST_FAILED; 171 } else { 172 log.display("Warinig: unable to test an assertion: caught exception: " + une 173 + "\n\tand VirtualMachine.canPopFrames() shows, that the target VM" 174 + "\n\tdoes not support popping frames of a threads stack as well: " 175 + vm.canPopFrames()); 176 } 177 178 } catch(Exception ue) { 179 ue.printStackTrace(); 180 log.complain("TEST FAILED: ThreadReference.popFrames(): caught unexpected " 181 + ue + "\n\tinstead of IncompatibleThreadStateException or InvalidStackFrameException" 182 + "\n\twhen attempted to pop stack frame got from thread reference \"" 183 + thrRef + "\"\n\twith resumed debuggee thread"); 184 tot_res = Consts.TEST_FAILED; 185 } 186 } catch (Exception e) { 187 e.printStackTrace(); 188 log.complain("TEST FAILURE: caught unexpected exception: " + e); 189 tot_res = Consts.TEST_FAILED; 190 } finally { 191 // Finish the test 192 // force an method to exit 193 if (objRef != null && doExit != null) { 194 try { 195 objRef.setValue(doExit, vm.mirrorOf(true)); 196 } catch(Exception sve) { 197 sve.printStackTrace(); 198 } 199 } 200 } 201 202 return quitDebuggee(); 203 } 204 findFrame(ThreadReference thrRef, String varName)205 private StackFrame findFrame(ThreadReference thrRef, String varName) { 206 try { 207 List frames = thrRef.frames(); 208 Iterator iter = frames.iterator(); 209 while (iter.hasNext()) { 210 StackFrame stackFr = (StackFrame) iter.next(); 211 try { 212 LocalVariable locVar = 213 stackFr.visibleVariableByName(varName); 214 // visible variable with the given name is found 215 if (locVar != null) { 216 objRef = (ObjectReference) 217 stackFr.getValue(locVar); 218 return stackFr; 219 } 220 } catch(AbsentInformationException e) { 221 // this is not needed stack frame, ignoring 222 } catch(NativeMethodException ne) { 223 // current method is native, also ignoring 224 } 225 } 226 } catch (Exception e) { 227 e.printStackTrace(); 228 tot_res = Consts.TEST_FAILED; 229 throw new Failure("findFrame: caught unexpected exception: " + e); 230 } 231 throw new Failure("findFrame: needed debuggee stack frame not found"); 232 } 233 setBP(ReferenceType refType, int bpLine)234 private BreakpointRequest setBP(ReferenceType refType, int bpLine) { 235 EventRequestManager evReqMan = 236 debuggee.getEventRequestManager(); 237 Location loc; 238 239 try { 240 List locations = refType.allLineLocations(); 241 Iterator iter = locations.iterator(); 242 while (iter.hasNext()) { 243 loc = (Location) iter.next(); 244 if (loc.lineNumber() == bpLine) { 245 BreakpointRequest BPreq = 246 evReqMan.createBreakpointRequest(loc); 247 log.display("created " + BPreq + "\n\tfor " + refType 248 + " ; line=" + bpLine); 249 return BPreq; 250 } 251 } 252 } catch (Exception e) { 253 e.printStackTrace(); 254 throw new Failure("setBP: caught unexpected exception: " + e); 255 } 256 throw new Failure("setBP: location corresponding debuggee source line " 257 + bpLine + " not found"); 258 } 259 suspendAtBP(ReferenceType rType, int bpLine)260 private void suspendAtBP(ReferenceType rType, int bpLine) { 261 262 /** 263 * This is a class containing a critical section which may lead to time 264 * out of the test. 265 */ 266 class CriticalSection extends Thread { 267 public volatile boolean waitFor = true; 268 269 public void run() { 270 try { 271 do { 272 EventSet eventSet = vm.eventQueue().remove(DELAY); 273 if (eventSet != null) { // it is not a timeout 274 EventIterator it = eventSet.eventIterator(); 275 while (it.hasNext()) { 276 Event event = it.nextEvent(); 277 if (event instanceof VMDisconnectEvent) { 278 log.complain("TEST FAILED: unexpected VMDisconnectEvent"); 279 break; 280 } else if (event instanceof VMDeathEvent) { 281 log.complain("TEST FAILED: unexpected VMDeathEvent"); 282 break; 283 } else if (event instanceof BreakpointEvent) { 284 if (event.request().equals(BPreq)) { 285 log.display("expected Breakpoint event occured: " 286 + event.toString()); 287 gotEvent = true; 288 return; 289 } 290 } else 291 log.display("following JDI event occured: " 292 + event.toString()); 293 } 294 } 295 } while(waitFor); 296 log.complain("TEST FAILED: no expected Breakpoint event"); 297 tot_res = Consts.TEST_FAILED; 298 } catch (Exception e) { 299 e.printStackTrace(); 300 tot_res = Consts.TEST_FAILED; 301 log.complain("TEST FAILED: caught unexpected exception: " + e); 302 } 303 } 304 } 305 ///////////////////////////////////////////////////////////////////////////// 306 307 BPreq = setBP(rType, bpLine); 308 BPreq.enable(); 309 CriticalSection critSect = new CriticalSection(); 310 log.display("\nStarting potential timed out section:\n\twaiting " 311 + (argHandler.getWaitTime()) 312 + " minute(s) for JDI Breakpoint event ...\n"); 313 critSect.start(); 314 pipe.println(COMMAND_GO); 315 try { 316 critSect.join((argHandler.getWaitTime())*60000); 317 if (critSect.isAlive()) { 318 critSect.waitFor = false; 319 throw new Failure("timeout occured while waiting for Breakpoint event"); 320 } 321 } catch (InterruptedException e) { 322 critSect.waitFor = false; 323 throw new Failure("TEST INCOMPLETE: InterruptedException occured while waiting for Breakpoint event"); 324 } finally { 325 BPreq.disable(); 326 } 327 log.display("\nPotential timed out section successfully passed\n"); 328 if (gotEvent == false) 329 throw new Failure("unable to suspend debuggee thread at breakpoint"); 330 } 331 quitDebuggee()332 private int quitDebuggee() { 333 log.display("Final resumption of debuggee VM"); 334 vm.resume(); 335 pipe.println(COMMAND_QUIT); 336 debuggee.waitFor(); 337 int debStat = debuggee.getStatus(); 338 if (debStat != (Consts.JCK_STATUS_BASE + Consts.TEST_PASSED)) { 339 log.complain("TEST FAILED: debuggee process finished with status: " 340 + debStat); 341 tot_res = Consts.TEST_FAILED; 342 } else 343 log.display("\nDebuggee process finished with the status: " 344 + debStat); 345 346 return tot_res; 347 } 348 } 349