/* * Copyright (c) 2001, 2022, 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.
*/
ThreadReference mainThread; /** * We create a VMDeathRequest, SUSPEND_ALL, to sync the BE and FE.
*/ private VMDeathRequest ourVMDeathRequest = null;
/** * We create an ExceptionRequest, SUSPEND_NONE so that we can * catch it and output a msg if an exception occurs in the * debuggee.
*/ private ExceptionRequest ourExceptionRequest = null;
/** * If we do catch an uncaught exception, we set this true * so the testcase can find out if it wants to.
*/ privateboolean exceptionCaught = false;
ThreadReference vmStartThread = null; boolean vmDied = false; boolean vmDisconnected = false; final String[] args; protectedboolean testFailed = false; protectedlong startTime; publicstaticfinal String OLD_MAIN_THREAD_NAME = "old-m-a-i-n";
/** * Return true if eventSet contains the VMDeathEvent for the request in * the ourVMDeathRequest ivar.
*/ privateboolean containsOurVMDeathRequest(EventSet eventSet) { if (ourVMDeathRequest != null) {
Iterator myIter = eventSet.iterator(); while (myIter.hasNext()) {
Event myEvent = (Event)myIter.next(); if (!(myEvent instanceof VMDeathEvent)) { // We assume that an EventSet contains only VMDeathEvents // or no VMDeathEvents. break;
} if (ourVMDeathRequest.equals(myEvent.request())) { returntrue;
}
}
} returnfalse;
}
/************************************************************************ * The following methods override those in our base class, TargetAdapter.
*************************************************************************/
/** * Events handled directly by scaffold always resume (well, almost always)
*/ publicvoid eventSetComplete(EventSet set) { // The listener in connect(..) resumes after receiving our // special VMDeathEvent. We can't also do the resume // here or we will probably get a VMDisconnectedException if (!containsOurVMDeathRequest(set)) {
traceln("TS: set.resume() called");
set.resume();
}
}
/** * This method sets up default requests. * Testcases can override this to change default behavior.
*/ protectedvoid createDefaultEventRequests() {
createDefaultVMDeathRequest();
createDefaultExceptionRequest();
}
/** * We want the BE to stop when it issues a VMDeathEvent in order to * give the FE time to complete handling events that occured before * the VMDeath. When we get the VMDeathEvent for this request in * the listener in connect(), we will do a resume. * If a testcase wants to do something special with VMDeathEvent's, * then it should override this method with an empty method or * whatever in order to suppress the automatic resume. The testcase * will then be responsible for the handling of VMDeathEvents. It * has to be sure that it does a resume if it gets a VMDeathEvent * with SUSPEND_ALL, and it has to be sure that it doesn't do a * resume after getting a VMDeath with SUSPEND_NONE (the automatically * generated VMDeathEvent.)
*/ protectedvoid createDefaultVMDeathRequest() {
ourVMDeathRequest = requestManager.createVMDeathRequest();
ourVMDeathRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
ourVMDeathRequest.enable();
}
/** * This will allow us to print a warning if a debuggee gets an * unexpected exception. The unexpected exception will be handled in * the exceptionThrown method in the listener created in the connect() * method. * If a testcase does not want an uncaught exception to cause a * msg, it must override this method.
*/ protectedvoid createDefaultExceptionRequest() {
ourExceptionRequest = requestManager.createExceptionRequest(null, false, true);
// We can't afford to make this be other than SUSPEND_NONE. Otherwise, // it would have to be resumed. If our connect() listener resumes it, // what about the case where the EventSet contains other events with // SUSPEND_ALL and there are other listeners who expect the BE to still // be suspended when their handlers get called?
ourExceptionRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
ourExceptionRequest.enable();
}
if (System.getProperty("jpda.wait") != null) {
waitForInput();
} return bpr;
}
protectedvoid waitForInput() { try {
System.err.println("Press to continue");
System.in.read();
System.err.println("running...");
} catch(Exception e) {
}
}
/* * Test cases should implement tests in runTests and should * initiate testing by calling run().
*/ abstractprotectedvoid runTests() throws Exception;
/* * classpath can span two arguments so we need to handle * it specially.
*/ if (args[i].equals("-J-classpath")) {
i++;
argInfo.targetVMArgs += (args[i] + ' ');
}
} else {
argInfo.targetAppCommandLine += (args[i] + ' ');
}
} return argInfo;
}
/** * This is called to connect to a debuggee VM. It starts the VM and * installs a listener to catch VMStartEvent, our default events, and * VMDisconnectedEvent. When these events appear, that is remembered * and waiters are notified. * This is normally called in the main thread of the test case. * It starts up an EventHandler thread that gets events coming in * from the debuggee and distributes them to listeners. That thread * keeps running until a VMDisconnectedEvent occurs or some exception * occurs during its processing. * * The 'listenUntilVMDisconnect' method adds 'this' as a listener. * This means that 'this's vmDied method will get called. This has a * default impl in TargetAdapter.java which can be overridden in the * testcase. * * waitForRequestedEvent also adds an adaptor listener that listens * for the particular event it is supposed to wait for (and it also * catches VMDisconnectEvents.) This listener is removed once * its eventReceived method is called. * waitForRequestedEvent is called by most of the methods to do bkpts, * etc.
*/ publicvoid connect(String args[]) {
ArgInfo argInfo = parseArgs(args);
argInfo.targetVMArgs += VMConnection.getDebuggeeVMOptions();
connection = new VMConnection(argInfo.connectorSpec,
argInfo.traceFlags);
// Note that we want to do the above resume before // waking up any sleepers. synchronized(TestScaffold.this) {
TestScaffold.this.notifyAll();
}
}
} publicvoid eventReceived(Event event) { if (redefineAtEvents && event instanceof Locatable) {
Location loc = ((Locatable)event).location();
ReferenceType rt = loc.declaringType();
String name = rt.name(); if (name.startsWith("java.")
|| name.startsWith("sun.")
|| name.startsWith("com.")
|| name.startsWith("jdk.")) { if (mainStartClass != null) {
redefine(mainStartClass);
}
} else {
redefine(rt);
}
}
}
publicvoid vmStarted(VMStartEvent event) { synchronized(TestScaffold.this) {
vmStartThread = event.thread();
TestScaffold.this.notifyAll();
}
} /** * By default, we catch uncaught exceptions and print a msg. * The testcase must override the createDefaultExceptionRequest * method if it doesn't want this behavior.
*/ publicvoid exceptionThrown(ExceptionEvent event) { if (TestScaffold.this.ourExceptionRequest != null &&
TestScaffold.this.ourExceptionRequest.equals(
event.request())) { /* * See * 5038723: com/sun/jdi/sde/TemperatureTableTest.java: * intermittent ObjectCollectedException * Since this request was SUSPEND_NONE, the debuggee * could keep running and the calls below back into * the debuggee might not work. That is why we * have this try/catch.
*/ try {
println("Note: Unexpected Debuggee Exception: " +
event.exception().referenceType().name() + " at line " + event.location().lineNumber());
TestScaffold.this.exceptionCaught = true;
ObjectReference obj = event.exception();
ReferenceType rtt = obj.referenceType();
Field detail = rtt.fieldByName("detailMessage");
Value val = obj.getValue(detail);
println("detailMessage = " + val);
/* * This code is commented out because it needs a thread * in which to do the invokeMethod and we don't have * one. To enable this code change the request * to be SUSPEND_ALL in createDefaultExceptionRequest, * and then put this line * mainThread = bpe.thread(); * in the testcase after the line * BreakpointEvent bpe = startToMain("....");
*/ if (false) {
List lll = rtt.methodsByName("printStackTrace");
Method mm = (Method)lll.get(0);
obj.invokeMethod(mainThread, mm, new ArrayList(0), 0);
}
} catch (Exception ee) {
println("TestScaffold Exception while handling debuggee Exception: "
+ ee);
}
}
}
public Event waitForRequestedEvent(final EventRequest request) { class EventNotification {
Event event; boolean disconnected = false;
} final EventNotification en = new EventNotification();
public StepEvent stepIntoInstruction(ThreadReference thread) { return doStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_INTO);
}
public StepEvent stepIntoLine(ThreadReference thread) { return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_INTO);
}
public StepEvent stepOverInstruction(ThreadReference thread) { return doStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_OVER);
}
public StepEvent stepOverLine(ThreadReference thread) { return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_OVER);
}
public StepEvent stepOut(ThreadReference thread) { return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_OUT);
}
public BreakpointEvent resumeTo(Location loc) { return resumeTo(loc, false);
}
public BreakpointEvent resumeTo(Location loc, boolean suspendThread) { final BreakpointRequest request =
requestManager.createBreakpointRequest(loc);
request.addCountFilter(1); if (suspendThread) {
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
}
request.enable(); return (BreakpointEvent)waitForRequestedEvent(request);
}
public ReferenceType findReferenceType(String name) {
List rts = vm.classesByName(name);
Iterator iter = rts.iterator(); while (iter.hasNext()) {
ReferenceType rt = (ReferenceType)iter.next(); if (rt.name().equals(name)) { return rt;
}
} returnnull;
}
public Method findMethod(ReferenceType rt, String name, String signature) {
List methods = rt.methods();
Iterator iter = methods.iterator(); while (iter.hasNext()) {
Method method = (Method)iter.next(); if (method.name().equals(name) &&
method.signature().equals(signature)) { return method;
}
} returnnull;
}
public Location findLocation(ReferenceType rt, int lineNumber) throws AbsentInformationException {
List locs = rt.locationsOfLine(lineNumber); if (locs.size() == 0) { thrownew IllegalArgumentException("Bad line number");
} elseif (locs.size() > 1) { thrownew IllegalArgumentException("Line number has multiple locations");
}
return (Location)locs.get(0);
}
public Location findMethodLocation(ReferenceType rt, String methodName,
String methodSignature, int methodLineNumber) throws AbsentInformationException {
Method m = findMethod(rt, methodName, methodSignature); int lineNumber = m.location().lineNumber() + methodLineNumber - 1; return findLocation(rt, lineNumber);
}
if ((connection != null)) { try {
connection.disposeVM();
} catch (VMDisconnectedException e) { // Shutting down after the VM has gone away. This is // not an error, and we just ignore it.
}
} else {
traceln("TS: shutdown: disposeVM not called");
} if (message != null) {
println(message);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.