| /* |
| * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package nsk.share.jdi; |
| |
| import java.io.*; |
| import java.util.*; |
| import com.sun.jdi.*; |
| import com.sun.jdi.event.*; |
| import com.sun.jdi.request.*; |
| import nsk.share.*; |
| import nsk.share.jpda.*; |
| import nsk.share.test.StressOptions; |
| import nsk.share.test.Stresser; |
| |
| /* |
| * Class can be used as base debugger class in jdi tests. |
| * Class contains common method for initializing log, debugee, pipe, vm, and several common auxiliary methods. |
| * Sublcass should implement doTest() and, if needed, doInit(parse command line parameters) and canRunTest(check if VM support tested functionality) |
| */ |
| public class TestDebuggerType2 { |
| public class EventListenerThread extends Thread { |
| private EventRequest eventRequest; |
| |
| private Event event; |
| |
| private Wicket wicket = new Wicket(); |
| |
| public EventListenerThread(EventRequest eventRequest) { |
| this.eventRequest = eventRequest; |
| } |
| |
| public void run() { |
| wicket.unlock(); |
| |
| try { |
| event = debuggee.waitingEvent(eventRequest, argHandler.getWaitTime() * 60000); |
| } catch (InterruptedException e) { |
| // ignore |
| } |
| } |
| |
| public void waitStartListen() { |
| wicket.waitFor(); |
| } |
| |
| public Event getEvent() { |
| try { |
| // wait when EventListenerThread complete execution |
| this.join(); |
| } catch (InterruptedException e) { |
| setSuccess(false); |
| log.complain("Unexpected exception: " + e); |
| } |
| |
| return event; |
| } |
| } |
| |
| protected ArgumentHandler argHandler; |
| |
| protected Log log; |
| |
| protected IOPipe pipe; |
| |
| protected Debugee debuggee; |
| |
| protected VirtualMachine vm; |
| |
| /* |
| * this method is called from nsk.share.jdi.SerialExecutionDebugger to set for debugger |
| * already created instances of ArgumentHandler, Log, IOPipe, Debugee, VirtualMachine |
| */ |
| public void initDebugger(ArgumentHandler argHandler, Log log, IOPipe pipe, Debugee debuggee, VirtualMachine vm) { |
| this.argHandler = argHandler; |
| this.log = log; |
| this.pipe = pipe; |
| this.debuggee = debuggee; |
| this.vm = vm; |
| } |
| |
| private boolean success = true; |
| |
| protected void setSuccess(boolean value) { |
| success = value; |
| } |
| |
| protected boolean getSuccess() { |
| return success; |
| } |
| |
| // class name used during initialization |
| protected String debuggeeClassName() { |
| return null; |
| } |
| |
| // select only class name if debuggeeClassName() returns className + debuggee parameters |
| protected String debuggeeClassNameWithoutArgs() { |
| String className = debuggeeClassName(); |
| |
| int index = className.indexOf(' '); |
| if (index > 0) { |
| return className.substring(0, index); |
| } else |
| return className; |
| } |
| |
| protected String classpath; |
| |
| protected String testWorkDir; |
| |
| // initialize test and remove unsupported by nsk.share.jdi.ArgumentHandler arguments |
| // (ArgumentHandler constructor throws BadOption exception if command line contains unrecognized by ArgumentHandler options) |
| // support -testClassPath parameter: path to find classes for custom classloader in debuggee VM |
| // (note that in this method stressOptions and stresser are created, so if subclasses override this method |
| // overrided version should first call super.doInit()) |
| protected String[] doInit(String args[], PrintStream out) { |
| stressOptions = new StressOptions(args); |
| stresser = new Stresser(stressOptions); |
| |
| ArrayList<String> standardArgs = new ArrayList<String>(); |
| |
| for (int i = 0; i < args.length; i++) { |
| if (args[i].equals("-testClassPath") && (i < args.length - 1)) { |
| classpath = args[i + 1]; |
| i++; |
| } else if (args[i].equals("-testWorkDir") && (i < args.length - 1)) { |
| testWorkDir = args[i + 1]; |
| |
| if (testWorkDir.endsWith(File.separator)) { |
| testWorkDir = testWorkDir.substring(0, testWorkDir.length() - 1); |
| } |
| |
| i++; |
| } else |
| standardArgs.add(args[i]); |
| } |
| |
| return standardArgs.toArray(new String[] {}); |
| } |
| |
| protected void doTest() { |
| setSuccess(false); |
| throw new TestBug("TEST BUG: method doTest not implemented"); |
| } |
| |
| protected Stresser stresser; |
| protected StressOptions stressOptions; |
| |
| // initialize log, debuggee, pipe |
| public void init(String args[], PrintStream out) { |
| argHandler = new ArgumentHandler(doInit(args, out)); |
| log = new Log(out, argHandler); |
| Binder binder = new Binder(argHandler, log); |
| debuggee = binder.bindToDebugee(debuggeeClassName()); |
| pipe = debuggee.createIOPipe(); |
| debuggee.redirectStderr(log, "Debugger.err> "); |
| vm = debuggee.VM(); |
| debuggee.resume(); |
| |
| String command = pipe.readln(); |
| |
| if (!command.equals(AbstractDebuggeeTest.COMMAND_READY)) { |
| setSuccess(false); |
| log.complain("TEST BUG: unknown debuggee's command: " + command); |
| } |
| } |
| |
| // check that vm support tested functions |
| protected boolean canRunTest() { |
| return true; |
| } |
| |
| // send quit command to debuggee |
| protected void quitDebuggee() { |
| pipe.println(AbstractDebuggeeTest.COMMAND_QUIT); |
| debuggee.waitFor(); |
| |
| int debStat = debuggee.getStatus(); |
| |
| if (debStat != (Consts.JCK_STATUS_BASE + Consts.TEST_PASSED)) { |
| setSuccess(false); |
| log.complain("TEST FAILED: debuggee's process finished with status: " + debStat); |
| } else |
| log.display("Debuggee's process finished with status: " + debStat); |
| |
| } |
| |
| // init test, execute test, quit debuggee |
| protected int runIt(String args[], PrintStream out) { |
| init(args, out); |
| |
| try { |
| if (canRunTest()) |
| doTest(); |
| } catch (TestBug testBug) { |
| setSuccess(false); |
| log.complain("Test bug: " + testBug); |
| testBug.printStackTrace(log.getOutStream()); |
| } catch (Throwable t) { |
| setSuccess(false); |
| log.complain("Unexpected exception: " + t); |
| t.printStackTrace(log.getOutStream()); |
| } |
| |
| quitDebuggee(); |
| |
| if (getSuccess()) { |
| log.display("TEST PASSED"); |
| return Consts.TEST_PASSED; |
| } else { |
| log.display("TEST FAILED"); |
| return Consts.TEST_FAILED; |
| } |
| } |
| |
| // check the debuggee completed pervious command and is ready for new one |
| protected boolean isDebuggeeReady() { |
| String command = pipe.readln(); |
| |
| if (!command.equals(AbstractDebuggeeTest.COMMAND_READY)) { |
| setSuccess(false); |
| log.complain("TEST BUG: unknown debuggee's command: " + command); |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // find in debuggee VM instance of object with given class and check |
| // that there is only one instance of this class |
| protected ObjectReference findSingleObjectReference(String className) { |
| ReferenceType referenceType = debuggee.classByName(className); |
| |
| if (referenceType == null) |
| throw new TestBug("There is no class '" + className + "' in debuggee"); |
| |
| List<ObjectReference> instances = referenceType.instances(0); |
| |
| if (instances.size() == 0) |
| throw new TestBug("There are no instances of class '" + className + "' in debuggee"); |
| |
| if (instances.size() > 1) |
| throw new TestBug("There are more than one(" + instances.size() + ") instance of '" + className + " in debuggee"); |
| |
| return instances.get(0); |
| } |
| |
| protected BreakpointEvent waitForBreakpoint(BreakpointRequest breakpointRequest) { |
| BreakpointEvent breakpointEvent; |
| |
| try { |
| breakpointEvent = (BreakpointEvent) debuggee.waitingEvent(breakpointRequest, argHandler.getWaitTime() * 60000); |
| } catch (InterruptedException e) { |
| setSuccess(false); |
| e.printStackTrace(log.getOutStream()); |
| log.complain("unexpected InterruptedException: " + e); |
| |
| breakpointEvent = null; |
| } |
| |
| if (breakpointEvent == null) { |
| setSuccess(false); |
| log.complain("Didn't get expected breakpoint event"); |
| } |
| |
| return breakpointEvent; |
| } |
| |
| |
| private boolean currentSuccess = false; |
| protected void forceGC() { |
| pipe.println(AbstractDebuggeeTest.COMMAND_FORCE_GC); |
| if (!isDebuggeeReady()) |
| return; |
| currentSuccess = getSuccess(); |
| } |
| |
| // Get GC statistics |
| protected void resetStatusIfGC() { |
| pipe.println(AbstractDebuggeeTest.COMMAND_GC_COUNT); |
| String command = pipe.readln(); |
| if (command.startsWith(AbstractDebuggeeTest.COMMAND_GC_COUNT)) { |
| if (!isDebuggeeReady()) { |
| return; |
| } |
| if (Integer.valueOf(command.substring(AbstractDebuggeeTest.COMMAND_GC_COUNT.length() + 1)) > 0) { |
| log.display("WARNING: The GC worked during tests. Results are skipped."); |
| setSuccess(currentSuccess); |
| } |
| return; |
| } |
| setSuccess(false); |
| } |
| |
| |
| protected BreakpointRequest defaultBreakpointRequest; |
| |
| protected void initDefaultBreakpoint() { |
| defaultBreakpointRequest = debuggee.makeBreakpoint(debuggee.classByName(debuggeeClassNameWithoutArgs()), |
| AbstractDebuggeeTest.DEFAULT_BREAKPOINT_METHOD_NAME, AbstractDebuggeeTest.DEFAULT_BREAKPOINT_LINE); |
| |
| defaultBreakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); |
| defaultBreakpointRequest.enable(); |
| } |
| |
| protected void removeDefaultBreakpoint() { |
| defaultBreakpointRequest.disable(); |
| debuggee.getEventRequestManager().deleteEventRequest(defaultBreakpointRequest); |
| defaultBreakpointRequest = null; |
| } |
| |
| protected Value createVoidValue() { |
| return vm.mirrorOfVoid(); |
| } |
| |
| // force debuggee call 'TestDebuggeeType2.breakpointMethod()' |
| protected BreakpointEvent forceBreakpoint() { |
| pipe.println(AbstractDebuggeeTest.COMMAND_FORCE_BREAKPOINT); |
| |
| BreakpointEvent event = waitForBreakpoint(defaultBreakpointRequest); |
| |
| return event; |
| } |
| |
| protected void unexpectedException(Throwable t) { |
| setSuccess(false); |
| log.complain("Unexpected exception: " + t); |
| t.printStackTrace(log.getOutStream()); |
| } |
| |
| protected void display(String msg) { |
| log.display(msg); |
| } |
| |
| protected void complain(String msg) { |
| log.complain("debugger FAILURE> " + msg + "\n"); |
| } |
| |
| protected boolean isJFR_active() { |
| return debuggee.isJFR_active(); |
| } |
| } |