blob: 1d5f9b2faa54f093b2caf64567ec1748b0a3c831 [file] [log] [blame]
/*
* Copyright (c) 2001, 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 nsk.share.*;
import nsk.share.jpda.*;
import com.sun.jdi.*;
import com.sun.jdi.connect.*;
import com.sun.jdi.connect.Connector.Argument;
import java.io.*;
import java.net.*;
import java.util.*;
/**
* This class provides debugger with connection to debugee VM
* using JDI connectors.
*<p>
* This class provides abilities to launch and bind to debugee VM
* as described for base <code>DebugeeBinder</code> class,
* using JDI connectors and <code>com.sun.VirtualMachine</code> mirror.
* <p>
* When <code>Binder</code> is asked to bind to debugee by invoking
* <code>bindToBebugee()</code> method it uses
* <code>com.sun.jdi.Connector</code> object corresponding to
* value of command line options <code>-connector</code> and
* <code>-transport</code> to launch and connect to debugee VM.
* After debugee is launched and connection is established
* <code>Binder</code> uses <code>com.sun.jdi.VirtualMachine</code>
* object to construct <code>Debugee</code> object, that
* provides abilities to interact with debugee VM.
*
* @see Debugee
* @see DebugeeBinder
*/
public class Binder extends DebugeeBinder {
/**
* Default message prefix for <code>Binder</code> object.
*/
public static final String LOG_PREFIX = "binder> ";
/**
* Get version string.
*/
public static String getVersion () {
return "@(#)Binder.java 1.14 03/10/08";
}
// -------------------------------------------------- //
/**
* Handler of command line arguments.
*/
private ArgumentHandler argumentHandler = null;
/**
* Return <code>argumentHandler</code> of this binder.
*/
public ArgumentHandler getArgumentHandler() {
return argumentHandler;
}
// -------------------------------------------------- //
/**
* Make <code>Binder</code> object and pass raw command line arguments.
*
* @deprecated Use newer
* <code>Binder(ArgumentHandler,Log)</code>
* constructor.
*/
public Binder (String args[]) {
this(args, new Log(System.err));
}
/**
* Make <code>Binder</code> object for raw command line arguments
* and specified <code>log</code> object.
*
* @deprecated Use newer
* <code>Binder(ArgumentHandler,Log)</code>
* constructor.
*/
public Binder (String args[], Log log) {
this(new ArgumentHandler(args), log);
}
/**
* Make <code>Binder</code> object for specified command line arguments
* and <code>log</code> object.
*/
public Binder (ArgumentHandler argumentHandler, Log log) {
super(argumentHandler, log);
this.argumentHandler = argumentHandler;
}
// -------------------------------------------------- //
/**
* Make initial <code>Debugee</code> object for local debuggee process
* started with launching connector.
*/
public Debugee makeLocalDebugee(Process process) {
LocalLaunchedDebugee debugee = new LocalLaunchedDebugee(process, this);
Finalizer finalizer = new Finalizer(debugee);
finalizer.activate();
return debugee;
}
/**
* Launch local debuggee process with specified command line
* and make initial <code>Debugee</code> object.
*/
public Debugee startLocalDebugee(String cmd) {
Process process = null;
try {
process = launchProcess(cmd);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while launching local debuggee VM process:\n\t"
+ e);
}
return makeLocalDebugee(process);
}
/**
* Make debuggee wrapper for already launched debuggee VM.
* After enwraping debugee's output is redirected to Binder's log,
* VMStartEvent is received and debuggee is initialized.
*/
public Debugee enwrapDebugee(VirtualMachine vm, Process proc) {
Debugee debugee = makeLocalDebugee(proc);
display("Redirecting VM output");
debugee.redirectOutput(log);
debugee.setupVM(vm);
long timeout = argumentHandler.getWaitTime() * 60 * 1000; // milliseconds
display("Waiting for VM initialized");
debugee.waitForVMInit(timeout);
return debugee;
}
/**
* Launch debugee VM and establish connection to it without waiting for VMStartEvent.
* After launching debugee's output is redirected to Binder's log,
* but VMStartEvent is not received and so debuggee is not fully initialized.
*
* @see #bindToDebugee(String)
*/
public Debugee bindToDebugeeNoWait(String classToExecute) {
VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
display("VirtualMachineManager: version "
+ vmm.majorInterfaceVersion() + "."
+ vmm.minorInterfaceVersion());
Debugee debugee = null;
String classPath = null;
// classPath = System.getProperty("java.class.path");
prepareForPipeConnection(argumentHandler);
if (argumentHandler.isLaunchedLocally()) {
if (argumentHandler.isDefaultConnector()) {
debugee = localDefaultLaunchDebugee(vmm, classToExecute, classPath);
} else if (argumentHandler.isRawLaunchingConnector()) {
debugee = localRawLaunchDebugee(vmm, classToExecute, classPath);
} else if (argumentHandler.isLaunchingConnector()) {
debugee = localLaunchDebugee(vmm, classToExecute, classPath);
} else if (argumentHandler.isAttachingConnector()) {
debugee = localLaunchAndAttachDebugee(vmm, classToExecute, classPath);
} else if (argumentHandler.isLaunchingConnector()) {
debugee = localLaunchDebugee(vmm, classToExecute, classPath);
} else if (argumentHandler.isListeningConnector()) {
debugee = localLaunchAndListenDebugee(vmm, classToExecute, classPath);
} else {
throw new TestBug("Unexpected connector type for local debugee launch mode"
+ argumentHandler.getConnectorType());
}
} else if (argumentHandler.isLaunchedRemotely()) {
connectToBindServer(classToExecute);
if (argumentHandler.isAttachingConnector()) {
debugee = remoteLaunchAndAttachDebugee(vmm, classToExecute, classPath);
} else if (argumentHandler.isListeningConnector()) {
debugee = remoteLaunchAndListenDebugee(vmm, classToExecute, classPath);
} else {
throw new TestBug("Unexpected connector type for remote debugee launch mode"
+ argumentHandler.getConnectorType());
}
} else if (argumentHandler.isLaunchedManually()) {
if (argumentHandler.isAttachingConnector()) {
debugee = manualLaunchAndAttachDebugee(vmm, classToExecute, classPath);
} else if (argumentHandler.isListeningConnector()) {
debugee = manualLaunchAndListenDebugee(vmm, classToExecute, classPath);
} else {
throw new TestBug("Unexpected connector type for manual debugee launch mode"
+ argumentHandler.getConnectorType());
}
} else {
throw new Failure("Unexpected debugee launching mode: " + argumentHandler.getLaunchMode());
}
return debugee;
}
/**
* Launch debugee VM and establish JDI connection.
* After launching debugee's output is redirected to Binder's log,
* VMStart event is received and debuggee is initialized.
*
* @see #bindToDebugeeNoWait(String)
*/
public Debugee bindToDebugee(String classToExecute) {
Debugee debugee = bindToDebugeeNoWait(classToExecute);
if(argumentHandler.getOptions().getProperty("traceAll") != null)
debugee.VM().setDebugTraceMode(VirtualMachine.TRACE_ALL);
long timeout = argumentHandler.getWaitTime() * 60 * 1000; // milliseconds
display("Waiting for VM initialized");
debugee.waitForVMInit(timeout);
return debugee;
}
// -------------------------------------------------- //
/**
* Launch debugee locally via the default LaunchingConnector.
*/
private Debugee localDefaultLaunchDebugee (VirtualMachineManager vmm,
String classToExecute,
String classPath) {
display("Finding connector: " + "default" );
LaunchingConnector connector = vmm.defaultConnector();
Map<String,? extends Argument> arguments = setupLaunchingConnector(connector, classToExecute, classPath);
VirtualMachine vm;
try {
display("Launching debugee");
vm = connector.launch(arguments);
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e);
} catch (VMStartException e) {
e.printStackTrace(log.getOutStream());
String msg = readVMStartExceptionOutput(e, log.getOutStream());
throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\n" + msg);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while launching debugee VM:\n\t" + e);
};
Process process = vm.process();
Debugee debugee = makeLocalDebugee(process);
debugee.redirectOutput(log);
debugee.setupVM(vm);
return debugee;
}
/**
* Launch debugee locally via the default LaunchingConnector.
*/
private Debugee localLaunchDebugee (VirtualMachineManager vmm,
String classToExecute,
String classPath) {
display("Finding connector: " + argumentHandler.getConnectorName() );
LaunchingConnector connector =
(LaunchingConnector) findConnector(argumentHandler.getConnectorName(),
vmm.launchingConnectors());
Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupLaunchingConnector(connector, classToExecute, classPath);
VirtualMachine vm;
try {
display("Launching debugee");
vm = connector.launch(arguments);
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e);
} catch (VMStartException e) {
e.printStackTrace(log.getOutStream());
String msg = readVMStartExceptionOutput(e, log.getOutStream());
throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\nProcess output:\n\t" + msg);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while launching debugee VM:\n\t" + e);
};
Process process = vm.process();
Debugee debugee = makeLocalDebugee(process);
debugee.redirectOutput(log);
debugee.setupVM(vm);
return debugee;
}
/**
* Launch debugee locally via the RawLaunchingConnector.
*/
private Debugee localRawLaunchDebugee (VirtualMachineManager vmm,
String classToExecute,
String classPath) {
display("Finding connector: " + argumentHandler.getConnectorName() );
LaunchingConnector connector =
(LaunchingConnector) findConnector(argumentHandler.getConnectorName(),
vmm.launchingConnectors());
Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupRawLaunchingConnector(connector, classToExecute, classPath);
VirtualMachine vm;
try {
display("Launching debugee");
vm = connector.launch(arguments);
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e);
} catch (VMStartException e) {
e.printStackTrace(log.getOutStream());
String msg = readVMStartExceptionOutput(e, log.getOutStream());
throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\nProcess output:\n\t" + msg);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while launching debugee VM:\n\t" + e);
};
Process process = vm.process();
Debugee debugee = makeLocalDebugee(process);
debugee.redirectOutput(log);
debugee.setupVM(vm);
return debugee;
}
/**
* Launch debugee VM locally as a local process and connect to it using
* <code>AttachingConnector</code>.
*/
private Debugee localLaunchAndAttachDebugee (VirtualMachineManager vmm,
String classToExecute,
String classPath) {
display("FindingConnector: " + argumentHandler.getConnectorName() );
AttachingConnector connector =
(AttachingConnector) findConnector(argumentHandler.getConnectorName(),
vmm.attachingConnectors());
Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupAttachingConnector(connector, classToExecute, classPath);
String address = makeTransportAddress();
String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);
String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
display("Starting java process:\n\t" + javaCmdLine);
Debugee debugee = startLocalDebugee(cmdLineArgs);
debugee.redirectOutput(log);
display("Attaching to debugee");
VirtualMachine vm = null;
IOException ioe = null;
for (int i = 0; i < CONNECT_TRIES; i++) {
try {
vm = connector.attach(arguments);
display("Debugee attached");
debugee.setupVM(vm);
return debugee;
} catch (IOException e) {
display("Attempt #" + i + " to connect to debugee VM failed:\n\t" + e);
ioe = e;
if (debugee.terminated()) {
throw new Failure("Unable to connect to debuggee VM: VM process is terminated");
}
try {
Thread.currentThread().sleep(CONNECT_TRY_DELAY);
} catch (InterruptedException ie) {
ie.printStackTrace(log.getOutStream());
throw new Failure("Thread interrupted while pausing connection attempts:\n\t"
+ ie);
}
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e);
}
}
throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES
+ " tries:\n\t" + ioe);
}
/**
* Launch debugee VM locally as a local process and connect to it using
* <code>ListeningConnector</code>.
*/
private Debugee localLaunchAndListenDebugee (VirtualMachineManager vmm,
String classToExecute,
String classPath) {
display("Finding connector: " + argumentHandler.getConnectorName() );
ListeningConnector connector =
(ListeningConnector) findConnector(argumentHandler.getConnectorName(),
vmm.listeningConnectors());
Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupListeningConnector(connector, classToExecute, classPath);
String address = null;
try {
display("Listening for connection from debugee");
address = connector.startListening(arguments);
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while starting listening debugee VM:\n\t" + e);
};
String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);
String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
display("Starting java process:\n\t" + javaCmdLine);
Debugee debugee = startLocalDebugee(cmdLineArgs);
debugee.redirectOutput(log);
display("Waiting for connection from debugee");
VirtualMachine vm = null;
IOException ioe = null;
for (int i = 0; i < CONNECT_TRIES; i++) {
try {
vm = connector.accept(arguments);
connector.stopListening(arguments);
display("Debugee attached");
debugee.setupVM(vm);
return debugee;
} catch (IOException e) {
display("Attempt #" + i + " to listen debugee VM failed:\n\t" + e);
ioe = e;
if (debugee.terminated()) {
throw new Failure("Unable to connect to debuggee VM: VM process is terminated");
}
try {
Thread.currentThread().sleep(CONNECT_TRY_DELAY);
} catch (InterruptedException ie) {
ie.printStackTrace(log.getOutStream());
throw new Failure("Thread interrupted while pausing connection attempts:\n\t"
+ ie);
}
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);
}
}
throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES
+ " tries:\n\t" + ioe);
}
// -------------------------------------------------- //
/**
* Launch debugee VM remotely via <code>BindServer</code> and connect to it using
* <code>AttachingConnector</code>.
*/
private Debugee remoteLaunchAndAttachDebugee (VirtualMachineManager vmm,
String classToExecute,
String classPath) {
display("Finding connector: " + argumentHandler.getConnectorName() );
AttachingConnector connector =
(AttachingConnector) findConnector(argumentHandler.getConnectorName(),
vmm.attachingConnectors());
Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupAttachingConnector(connector, classToExecute, classPath);
String address = makeTransportAddress();
String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);
String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
display("Starting remote java process:\n\t" + javaCmdLine);
Debugee debugee = startRemoteDebugee(cmdLineArgs);
display("Attaching to debugee");
VirtualMachine vm;
IOException ioe = null;
for (int i = 0; i < CONNECT_TRIES; i++) {
try {
vm = connector.attach(arguments);
display("Debugee attached");
debugee.setupVM(vm);
return debugee;
} catch (IOException e) {
display("Attempt #" + i + " to connect to debugee VM failed:\n\t" + e);
ioe = e;
if (debugee.terminated()) {
throw new Failure("Unable to connect to debuggee VM: VM process is terminated");
}
try {
Thread.currentThread().sleep(CONNECT_TRY_DELAY);
} catch (InterruptedException ie) {
ie.printStackTrace(log.getOutStream());
throw new Failure("Thread interrupted while pausing connection attempts:\n\t"
+ ie);
}
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e);
}
}
throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES
+ " tries:\n\t" + ioe);
}
/**
* Launch debugee VM remotely via <code>BindServer</code> and connect to it using
* <code>ListeningConnector</code>.
*/
private Debugee remoteLaunchAndListenDebugee (VirtualMachineManager vmm,
String classToExecute,
String classPath) {
display("Finding connector: " + argumentHandler.getConnectorName() );
ListeningConnector connector =
(ListeningConnector) findConnector(argumentHandler.getConnectorName(),
vmm.listeningConnectors());
Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupListeningConnector(connector, classToExecute, classPath);
String address = null;
try {
display("Listening for connection from debugee");
address = connector.startListening(arguments);
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while starting listening debugee VM:\n\t" + e);
};
String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);
String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
display("Starting remote java process:\n\t" + javaCmdLine);
Debugee debugee = startRemoteDebugee(cmdLineArgs);
display("Waiting for connection from debugee");
VirtualMachine vm;
IOException ioe = null;
for (int i = 0; i < CONNECT_TRIES; i++) {
try {
vm = connector.accept(arguments);
connector.stopListening(arguments);
display("Debugee attached");
debugee.setupVM(vm);
return debugee;
} catch (IOException e) {
display("Attempt #" + i + " to listen debugee VM failed:\n\t" + e);
ioe = e;
if (debugee.terminated()) {
throw new Failure("Unable to connect to debuggee VM: VM process is terminated");
}
try {
Thread.currentThread().sleep(CONNECT_TRY_DELAY);
} catch (InterruptedException ie) {
ie.printStackTrace(log.getOutStream());
throw new Failure("Thread interrupted while pausing connection attempts:\n\t"
+ ie);
}
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);
}
}
throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES
+ " tries:\n\t" + ioe);
}
// -------------------------------------------------- //
/**
* Prompt to manually launch debugee VM and connect to it using
* <code>AttachingConnector</code>.
*/
private Debugee manualLaunchAndAttachDebugee (VirtualMachineManager vmm,
String classToExecute,
String classPath) {
display("Finding connector: " + argumentHandler.getConnectorName() );
AttachingConnector connector =
(AttachingConnector) findConnector(argumentHandler.getConnectorName(),
vmm.attachingConnectors());
Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupAttachingConnector(connector, classToExecute, classPath);
String address = makeTransportAddress();
String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
display("Starting manual java process:\n\t" + javaCmdLine);
ManualLaunchedDebugee debugee = startManualDebugee(javaCmdLine);
VirtualMachine vm;
try {
display("Attaching to debugee");
vm = connector.attach(arguments);
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while attaching to debugee VM:\n\t" + e);
};
display("Debugee attached");
debugee.setupVM(vm);
return debugee;
}
/**
* Prompt to manually launch debugee VM and connect to it using
* <code>ListeningConnector</code>.
*/
private Debugee manualLaunchAndListenDebugee (VirtualMachineManager vmm,
String classToExecute,
String classPath) {
display("Finding connector: " + argumentHandler.getConnectorName() );
ListeningConnector connector =
(ListeningConnector) findConnector(argumentHandler.getConnectorName(),
vmm.listeningConnectors());
Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupListeningConnector(connector, classToExecute, classPath);
VirtualMachine vm;
try {
display("Listening for connection from debugee");
String address = connector.startListening(arguments);
String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
display("Starting manual java process:\n\t" + javaCmdLine);
ManualLaunchedDebugee debugee = startManualDebugee(javaCmdLine);
display("Waiting for connection from debugee");
vm = connector.accept(arguments);
display("Debugee attached");
connector.stopListening(arguments);
debugee.setupVM(vm);
return debugee;
} catch (IllegalConnectorArgumentsException e) {
e.printStackTrace(log.getOutStream());
throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while listening to debugee VM:\n\t" + e);
}
}
// -------------------------------------------------- //
/**
* Make proper arguments for LaunchingConnector.
*/
private Map<String,? extends Argument> setupLaunchingConnector(LaunchingConnector connector,
String classToExecute,
String classPath) {
display("LaunchingConnector:");
display(" name: " + connector.name());
display(" description: " + connector.description());
display(" transport: " + connector.transport());
Hashtable<String,? extends Argument> arguments = new Hashtable<String,Argument>(connector.defaultArguments());
Connector.Argument arg;
arg = (Connector.StringArgument) arguments.get("quote");
String quote = arg.value();
String cmdline = classToExecute + " " +
ArgumentHandler.joinArguments(argumentHandler.getRawArguments(), quote);
arg = (Connector.StringArgument) arguments.get("main");
arg.setValue(cmdline);
if (! argumentHandler.willDebugeeSuspended()) {
Connector.BooleanArgument barg = (Connector.BooleanArgument) arguments.get("suspend");
barg.setValue(true);
}
/*
if (! argumentHandler.isJVMDIStrictMode()) {
arg = (Connector.StringArgument) arguments.get("options");
arg.setValue("strict=y");
}
*/
if (! argumentHandler.isDefaultDebugeeJavaHome()) {
arg = (Connector.StringArgument) arguments.get("home");
arg.setValue(argumentHandler.getDebugeeJavaHome());
}
if (! argumentHandler.isDefaultLaunchExecName()) {
arg = (Connector.StringArgument) arguments.get("vmexec");
arg.setValue(argumentHandler.getLaunchExecName());
}
String vmArgs = "";
String vmUserArgs = argumentHandler.getLaunchOptions();
if (vmUserArgs != null) {
vmArgs = vmUserArgs;
}
/*
if (classPath != null) {
vmArgs += " -classpath " + quote + classPath + quote;
}
*/
if (vmArgs.length() > 0) {
arg = (Connector.StringArgument) arguments.get("options");
arg.setValue(vmArgs);
}
display("Connector arguments:");
Iterator iterator = arguments.values().iterator();
while (iterator.hasNext()) {
display(" " + iterator.next());
}
return arguments;
}
/**
* Make proper arguments for RawLaunchingConnector.
*/
private Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> setupRawLaunchingConnector(LaunchingConnector connector,
String classToExecute,
String classPath) {
display("RawLaunchingConnector:");
display(" name: " + connector.name());
display(" description: " + connector.description());
display(" transport: " + connector.transport());
Hashtable<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = new Hashtable<java.lang.String, com.sun.jdi.connect.Connector.Argument>(connector.defaultArguments());
String connectorAddress;
String vmAddress;
if (argumentHandler.isSocketTransport()) {
connectorAddress = argumentHandler.getTransportPort();
vmAddress = argumentHandler.getDebugeeHost()
+ ":" + argumentHandler.getTransportPort();
} else if (argumentHandler.isShmemTransport() ) {
connectorAddress = argumentHandler.getTransportSharedName();
vmAddress=connectorAddress;
} else {
throw new TestBug("Undefined transport type for AttachingConnector");
}
Connector.Argument arg;
arg = (Connector.StringArgument) arguments.get("quote");
String quote = arg.value();
String javaCmdLine = makeCommandLineString(classToExecute, quote);
arg = (Connector.StringArgument) arguments.get("command");
arg.setValue(javaCmdLine);
arg = (Connector.StringArgument) arguments.get("address");
arg.setValue(connectorAddress);
display("Connector arguments:");
Iterator iterator = arguments.values().iterator();
while (iterator.hasNext()) {
display(" " + iterator.next());
}
return arguments;
}
/**
* Make proper arguments for AttachingConnector.
*/
private Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> setupAttachingConnector(AttachingConnector connector,
String classToExecute,
String classPath) {
display("AttachingConnector:");
display(" name: " + connector.name());
display(" description: " + connector.description());
display(" transport: " + connector.transport());
Hashtable<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = new Hashtable<java.lang.String,com.sun.jdi.connect.Connector.Argument>(connector.defaultArguments());
Connector.Argument arg;
if (argumentHandler.isSocketTransport()) {
arg = (Connector.StringArgument) arguments.get("hostname");
arg.setValue(argumentHandler.getDebugeeHost());
Connector.IntegerArgument iarg = (Connector.IntegerArgument) arguments.get("port");
iarg.setValue(argumentHandler.getTransportPortNumber());
} else {
arg = (Connector.StringArgument) arguments.get("name");
arg.setValue(argumentHandler.getTransportSharedName());
}
display("Connector arguments:");
Iterator iterator = arguments.values().iterator();
while (iterator.hasNext()) {
display(" " + iterator.next());
}
return arguments;
}
/**
* Make proper arguments for ListeningConnector.
*/
private Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> setupListeningConnector(ListeningConnector connector,
String classToExecute,
String classPath) {
display("ListeningConnector:");
display(" name: " + connector.name());
display(" description: " + connector.description());
display(" transport: " + connector.transport());
Hashtable<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = new Hashtable<java.lang.String,com.sun.jdi.connect.Connector.Argument>(connector.defaultArguments());
Connector.Argument arg;
if (argumentHandler.isSocketTransport()) {
if (!argumentHandler.isTransportAddressDynamic()) {
int port = argumentHandler.getTransportPortNumber();
Connector.IntegerArgument iarg = (Connector.IntegerArgument) arguments.get("port");
iarg.setValue(port);
}
} else {
String sharedName = argumentHandler.getTransportSharedName();
arg = (Connector.StringArgument) arguments.get("name");
arg.setValue(sharedName);
}
display("Connector arguments:");
Iterator iterator = arguments.values().iterator();
while (iterator.hasNext()) {
display(" " + iterator.next());
}
return arguments;
}
// -------------------------------------------------- //
/**
* Find connector by name from given connectors list.
*/
private Connector findConnector(String connectorName, List connectors) {
Iterator iter = connectors.iterator();
while (iter.hasNext()) {
Connector connector = (Connector) iter.next();
if (connector.name().equals(connectorName)) {
return connector;
}
}
throw new Failure("JDI connector not found: " + connectorName);
}
// -------------------------------------------------- //
/**
* Launch local debuggee process with specified command line arguments
* and make initial <code>Debugee</code> mirror.
*/
protected Debugee startLocalDebugee(String[] cmdArgs) {
Process process = null;
try {
process = launchProcess(cmdArgs);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while launching local debuggee VM process:\n\t"
+ e);
}
return makeLocalDebugee(process);
}
/**
* Launch remote debuggee process with specified command line arguments
* and make initial <code>Debugee</code> mirror.
*/
protected RemoteLaunchedDebugee startRemoteDebugee(String[] cmdArgs) {
try {
launchRemoteProcess(cmdArgs);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while launching remote debuggee VM process:\n\t"
+ e);
}
RemoteLaunchedDebugee debugee = new RemoteLaunchedDebugee(this);
Finalizer finalizer = new Finalizer(debugee);
finalizer.activate();
return debugee;
}
/**
* Launch manual debuggee process with specified command line arguments
* and make initial <code>Debugee</code> mirror.
*/
protected ManualLaunchedDebugee startManualDebugee(String cmd) {
ManualLaunchedDebugee debugee = new ManualLaunchedDebugee(this);
debugee.launchDebugee(cmd);
Finalizer finalizer = new Finalizer(debugee);
finalizer.activate();
return debugee;
}
public static String readVMStartExceptionOutput(VMStartException e, PrintStream log) {
StringBuffer msg = new StringBuffer();
try (InputStream is = e.process().getInputStream()) {
msg.append("\tstdout: ").append(new String(readAllBytes(is))).append('\n');
} catch (IOException e1) {
log.println("Could not read normal output from launched process:" + e1);
}
try (InputStream is = e.process().getErrorStream()) {
msg.append("\tstderr: ").append(new String(readAllBytes(is)));
} catch (IOException e1) {
log.println("Could not read error output from launched process:" + e1);
}
return msg.toString();
}
/**
* Copied from the JDK 9 implementation in InputStream.java
*/
private static byte[] readAllBytes(InputStream is) throws IOException {
final int DEFAULT_BUFFER_SIZE = 8192;
final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
int capacity = buf.length;
int nread = 0;
int n;
for (;;) {
// read to EOF which may read more or less than initial buffer size
while ((n = is.read(buf, nread, capacity - nread)) > 0)
nread += n;
// if the last call to read returned -1, then we're done
if (n < 0)
break;
// need to allocate a larger buffer
if (capacity <= MAX_BUFFER_SIZE - capacity) {
capacity = capacity << 1;
} else {
if (capacity == MAX_BUFFER_SIZE)
throw new OutOfMemoryError("Required array size too large");
capacity = MAX_BUFFER_SIZE;
}
buf = Arrays.copyOf(buf, capacity);
}
return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
}
}
/**
* Mirror of locally launched debugee.
*/
final class LocalLaunchedDebugee extends Debugee {
/** Enwrap the locally started VM process. */
public LocalLaunchedDebugee (Process process, Binder binder) {
super(binder);
this.process = process;
checkTermination = true;
}
// ---------------------------------------------- //
/** Return exit status of the debugee VM. */
public int getStatus () {
return process.exitValue();
}
/** Check whether the debugee VM has been terminated. */
public boolean terminated () {
if (process == null)
return true;
try {
int value = process.exitValue();
return true;
} catch (IllegalThreadStateException e) {
return false;
}
}
// ---------------------------------------------- //
/** Kill the debugee VM. */
protected void killDebugee () {
super.killDebugee();
if (!terminated()) {
log.display("Killing debugee VM process");
process.destroy();
}
}
/** Wait until the debugee VM shutdown or crash. */
protected int waitForDebugee () throws InterruptedException {
int code = process.waitFor();
return code;
}
/** Get a pipe to write to the debugee's stdin stream. */
protected OutputStream getInPipe () {
return process.getOutputStream();
}
/** Get a pipe to read the debugee's stdout stream. */
protected InputStream getOutPipe () {
return process.getInputStream();
}
/** Get a pipe to read the debugee's stderr stream. */
protected InputStream getErrPipe () {
return process.getErrorStream();
}
}
/**
* Mirror of remotely launched debugee.
*/
final class RemoteLaunchedDebugee extends Debugee {
/** Enwrap the remotely started VM process. */
public RemoteLaunchedDebugee (Binder binder) {
super(binder);
}
// ---------------------------------------------- //
/** Return exit status of the debugee VM. */
public int getStatus () {
return binder.getRemoteProcessStatus();
}
/** Check whether the debugee VM has been terminated. */
public boolean terminated () {
return binder.isRemoteProcessTerminated();
}
// ---------------------------------------------- //
/** Kill the debugee VM. */
protected void killDebugee () {
super.killDebugee();
if (!terminated()) {
binder.killRemoteProcess();
}
}
/** Wait until the debugee VM shutdown or crash. */
protected int waitForDebugee () {
return binder.waitForRemoteProcess();
}
/** Get a pipe to write to the debugee's stdin stream. */
protected OutputStream getInPipe () {
return null;
}
/** Get a pipe to read the debugee's stdout stream. */
protected InputStream getOutPipe () {
return null;
}
/** Get a pipe to read the debugee's stderr stream. */
protected InputStream getErrPipe () {
return null;
}
public void redirectStdout(OutputStream out) {
}
public void redirectStdout(Log log, String prefix) {
}
public void redirectStderr(OutputStream out) {
}
public void redirectStderr(Log log, String prefix) {
}
}
/**
* Mirror of manually launched debugee.
*/
final class ManualLaunchedDebugee extends Debugee {
/** Enwrap the manually started VM process. */
public ManualLaunchedDebugee (Binder binder) {
super(binder);
makeInputReader();
}
// ---------------------------------------------- //
private int exitCode = 0;
private boolean finished = false;
private static BufferedReader bin = null;
public void launchDebugee(String commandLine) {
makeInputReader();
putMessage("Launch target VM using such command line:\n"
+ commandLine);
String answer = askQuestion("Has the VM successfully started? (yes/no)", "yes");
for ( ; ; ) {
if (answer.equals("yes"))
break;
if (answer.equals("no"))
throw new Failure ("Unable to manually launch debugee VM");
answer = askQuestion("Wrong answer. Please type yes or no", "yes");
}
}
private static void makeInputReader() {
if (bin == null) {
bin = new BufferedReader(new InputStreamReader(System.in));
}
}
private static void destroyInputReader() {
if (bin != null) {
try {
bin.close();
} catch (IOException e) {
// e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while closing input stream:\n\t" + e);
}
bin = null;
}
}
private static void putMessage(String msg) {
System.out.println("\n>>> " + msg);
}
private static String askQuestion(String question, String defaultAnswer) {
try {
System.out.print("\n>>> " + question);
System.out.print(" [" + defaultAnswer + "] ");
System.out.flush();
String answer = bin.readLine();
if (answer.equals(""))
return defaultAnswer;
return answer;
} catch (IOException e) {
// e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while reading answer:\n\t" + e);
}
}
/** Return exit status of the debugee VM. */
public int getStatus () {
if (! finished) {
throw new Failure("Unable to get status of debugee VM: process still alive");
}
return exitCode;
}
/** Check whether the debugee VM has been terminated. */
public boolean terminated () {
return finished;
}
// ---------------------------------------------- //
/** Kill the debugee VM. */
protected void killDebugee () {
super.killDebugee();
if (!terminated()) {
putMessage("Kill launched VM");
String answer = askQuestion("Has the VM successfully terminated? (yes/no)", "yes");
for ( ; ; ) {
if (answer.equals("yes")) {
finished = true;
break;
}
if (answer.equals("no"))
throw new Failure ("Unable to manually kill debugee VM");
answer = askQuestion("Wrong answer. Please type yes or no", "yes");
}
}
}
/** Wait until the debugee VM shutdown or crash. */
protected int waitForDebugee () {
putMessage("Wait for launched VM to exit.");
String answer = askQuestion("What is VM exit code?", "95");
for ( ; ; ) {
try {
exitCode = Integer.parseInt(answer);
break;
} catch (NumberFormatException e) {
answer = askQuestion("Wrong answer. Please type integer value", "95");
}
}
finished = true;
return exitCode;
}
/** Get a pipe to write to the debugee's stdin stream. */
protected OutputStream getInPipe () {
return null;
}
/** Get a pipe to read the debugee's stdout stream. */
protected InputStream getOutPipe () {
return null;
}
/** Get a pipe to read the debugee's stderr stream. */
protected InputStream getErrPipe () {
return null;
}
public void redirectStdout(OutputStream out) {
}
public void redirectStdout(Log log, String prefix) {
}
public void redirectStderr(OutputStream out) {
}
public void redirectStderr(Log log, String prefix) {
}
public void close() {
destroyInputReader();
super.close();
}
}