8333117: Remove support of remote and manual debuggee launchers

Reviewed-by: cjplummer
This commit is contained in:
Leonid Mesnik 2024-06-20 15:43:44 +00:00
parent 9ef86da5f8
commit 99e4d77aac
10 changed files with 105 additions and 1534 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,55 +30,15 @@ import nsk.share.jdi.ArgumentHandler;
import java.io.*; import java.io.*;
/** /**
* Interface defining methods to control mirror of debuggee (i.e. debugged VM). * Class defining methods to control mirror of debuggee (i.e. debugged VM).
*/ */
public interface Debuggee { public class Debuggee extends LocalProcess {
/** Default prefix for log messages. */ /** Default prefix for log messages. */
public static final String LOG_PREFIX = "debuggee> "; public static final String LOG_PREFIX = "debuggee> ";
public static final String DEBUGEE_STDOUT_LOG_PREFIX = "debuggee.stdout> "; public static final String DEBUGEE_STDOUT_LOG_PREFIX = "debuggee.stdout> ";
public static final String DEBUGEE_STDERR_LOG_PREFIX = "debuggee.stderr> "; public static final String DEBUGEE_STDERR_LOG_PREFIX = "debuggee.stderr> ";
/**
* Launch debuggee.
*
* @throws IOException
*/
public void launch (String[] args) throws IOException;
/** Return exit status. */
public int getStatus ();
/** Check whether the process has been terminated. */
public boolean terminated();
/** Kill the debuggee VM. */
public void killDebuggee ();
/** Wait until the debuggee VM shutdown or crash. */
public int waitForDebuggee () throws InterruptedException;
/** Get a pipe to write to the debuggee's stdin stream. */
public OutputStream getInPipe ();
/** Get a pipe to read the debuggee's stdout stream. */
public InputStream getOutPipe ();
/** Get a pipe to read the debuggee's stderr stream. */
public InputStream getErrPipe ();
/** Redirect stdout stream to <code>Log</code> */
public void redirectStdout(Log log, String prefix);
/** Redirect stderr stream to <code>Log</code> */
public void redirectStderr(Log log, String prefix);
}
/**
* Mirror of locally launched debuggee.
*/
final class LocalLaunchedDebuggee extends LocalProcess implements Debuggee {
private IORedirector stdoutRedirector = null; private IORedirector stdoutRedirector = null;
private IORedirector stderrRedirector = null; private IORedirector stderrRedirector = null;
private IORedirector stdinRedirector = null; private IORedirector stdinRedirector = null;
@ -90,7 +50,7 @@ final class LocalLaunchedDebuggee extends LocalProcess implements Debuggee {
private Launcher launcher = null; private Launcher launcher = null;
/** Enwrap the existing <code>VM</code> mirror. */ /** Enwrap the existing <code>VM</code> mirror. */
LocalLaunchedDebuggee (Launcher launcher) { Debuggee(Launcher launcher) {
super(); super();
this.launcher = launcher; this.launcher = launcher;
} }
@ -235,70 +195,3 @@ final class LocalLaunchedDebuggee extends LocalProcess implements Debuggee {
} }
/**
* Mirror of remotely launched debuggee.
*/
final class RemoteLaunchedDebuggee implements Debuggee {
/** Launcher that creates this debuggee. */
private Launcher launcher = null;
/** Enwrap the existing <code>VM</code> mirror. */
RemoteLaunchedDebuggee (Launcher launcher) {
super();
this.launcher = launcher;
}
/**
* Launch debugee on remote host via <code>Launcher</code> object.
*/
public void launch(String[] args) throws IOException {
String cmdLine = ArgumentHandler.joinArguments(args, "\"");
launcher.display("Starting remote java process:\n" + cmdLine);
launcher.launchRemoteProcess(args);
}
/** Return exit status of the debuggee VM. */
public int getStatus () {
return launcher.getRemoteProcessStatus();
}
/** Check whether the debuggee VM has been terminated. */
public boolean terminated () {
return launcher.isRemoteProcessTerminated();
}
// ---------------------------------------------- //
/** Kill the debuggee VM. */
public void killDebuggee () {
launcher.killRemoteProcess();
}
/** Wait until the debuggee VM shutdown or crash. */
public int waitForDebuggee () {
return launcher.waitForRemoteProcess();
}
/** Get a pipe to write to the debuggee's stdin stream. */
public OutputStream getInPipe () {
return null;
}
/** Get a pipe to read the debuggee's stdout stream. */
public InputStream getOutPipe () {
return null;
}
/** Get a pipe to read the debuggee's stderr stream. */
public InputStream getErrPipe () {
return null;
}
public void redirectStdout(Log log, String prefix) {
}
public void redirectStderr(Log log, String prefix) {
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -103,52 +103,21 @@ public class Launcher extends DebugeeBinder {
String[] jdbCmdArgs = makeJdbCmdLine(classToExecute); String[] jdbCmdArgs = makeJdbCmdLine(classToExecute);
if (argumentHandler.isLaunchedLocally()) { if (argumentHandler.isDefaultConnector()) {
localDefaultLaunch(jdbCmdArgs, classToExecute);
if (argumentHandler.isDefaultConnector()) { } else if (argumentHandler.isRawLaunchingConnector()) {
localRawLaunch(jdbCmdArgs, classToExecute);
localDefaultLaunch(jdbCmdArgs, classToExecute); } else if (argumentHandler.isLaunchingConnector()) {
localLaunch(jdbCmdArgs, classToExecute);
} else if (argumentHandler.isRawLaunchingConnector()) { } else if (argumentHandler.isAttachingConnector()) {
localLaunchAndAttach(jdbCmdArgs, classToExecute);
localRawLaunch(jdbCmdArgs, classToExecute); } else if (argumentHandler.isListeningConnector()) {
localLaunchAndListen(jdbCmdArgs, classToExecute);
} else if (argumentHandler.isLaunchingConnector()) {
localLaunch(jdbCmdArgs, classToExecute);
} else if (argumentHandler.isAttachingConnector()) {
localLaunchAndAttach(jdbCmdArgs, classToExecute);
} else if (argumentHandler.isListeningConnector()) {
localLaunchAndListen(jdbCmdArgs, classToExecute);
} else {
throw new TestBug("Unexpected connector type for local launch mode"
+ argumentHandler.getConnectorType());
}
} else if (argumentHandler.isLaunchedRemotely()) {
connectToBindServer(classToExecute);
if (argumentHandler.isAttachingConnector()) {
remoteLaunchAndAttach(jdbCmdArgs, classToExecute);
} else if (argumentHandler.isListeningConnector()) {
remoteLaunchAndListen(jdbCmdArgs, classToExecute);
} else {
throw new TestBug("Unexpected connector type for remote launch mode"
+ argumentHandler.getConnectorType());
}
} else { } else {
throw new Failure("Unexpected launching mode: " + argumentHandler.getLaunchMode()); throw new TestBug("Unexpected connector type for local launch mode"
+ argumentHandler.getConnectorType());
} }
} }
/** /**
@ -198,11 +167,7 @@ public class Launcher extends DebugeeBinder {
if (argumentHandler.isRawLaunchingConnector()) { if (argumentHandler.isRawLaunchingConnector()) {
if (argumentHandler.isSocketTransport()) { if (argumentHandler.isSocketTransport()) {
if (argumentHandler.isLaunchedLocally()) { connectorAddress = argumentHandler.getTransportPort();
connectorAddress = argumentHandler.getTransportPort();
} else {
connectorAddress = argumentHandler.getDebugeeHost() + ":" + argumentHandler.getTransportPort();
}
} else if (argumentHandler.isShmemTransport() ) { } else if (argumentHandler.isShmemTransport() ) {
connectorAddress = argumentHandler.getTransportSharedName(); connectorAddress = argumentHandler.getTransportSharedName();
} else { } else {
@ -247,8 +212,6 @@ public class Launcher extends DebugeeBinder {
if (argumentHandler.isSocketTransport()) { if (argumentHandler.isSocketTransport()) {
connect.append("port=" + argumentHandler.getTransportPort().trim()); connect.append("port=" + argumentHandler.getTransportPort().trim());
if (argumentHandler.isLaunchedRemotely())
connect.append(",hostname=" + argumentHandler.getDebugeeHost().trim());
} else if (argumentHandler.isShmemTransport()) { } else if (argumentHandler.isShmemTransport()) {
connect.append("name=" + argumentHandler.getTransportSharedName().trim()); connect.append("name=" + argumentHandler.getTransportSharedName().trim());
} else { } else {
@ -324,7 +287,7 @@ public class Launcher extends DebugeeBinder {
private void localLaunchAndAttach private void localLaunchAndAttach
(String[] jdbCmdArgs, String classToExecute) throws IOException { (String[] jdbCmdArgs, String classToExecute) throws IOException {
debuggee = new LocalLaunchedDebuggee(this); debuggee = new Debuggee(this);
String address = makeTransportAddress(); String address = makeTransportAddress();
String[] javaCmdArgs = makeCommandLineArgs(classToExecute, address); String[] javaCmdArgs = makeCommandLineArgs(classToExecute, address);
debuggee.launch(javaCmdArgs); debuggee.launch(javaCmdArgs);
@ -346,57 +309,12 @@ public class Launcher extends DebugeeBinder {
String address = jdb.waitForListeningJdb(); String address = jdb.waitForListeningJdb();
display("Listening address found: " + address); display("Listening address found: " + address);
debuggee = new LocalLaunchedDebuggee(this); debuggee = new Debuggee(this);
String[] javaCmdArgs = makeCommandLineArgs(classToExecute, address); String[] javaCmdArgs = makeCommandLineArgs(classToExecute, address);
debuggee.launch(javaCmdArgs); debuggee.launch(javaCmdArgs);
// jdb.waitForPrompt(0, false); // jdb.waitForPrompt(0, false);
} }
/**
* Run test in remote mode using attaching connector.
*/
private void remoteLaunchAndAttach
(String[] jdbCmdArgs, String classToExecute) throws IOException {
debuggee = new RemoteLaunchedDebuggee(this);
String address = makeTransportAddress();
String[] javaCmdArgs = makeCommandLineArgs(classToExecute, address);
try {
debuggee.launch(javaCmdArgs);
} catch (IOException e) {
throw new Failure("Caught exception while launching debuggee VM process:\n\t"
+ e);
};
display("Start jdb attaching to remote debuggee");
jdb = Jdb.startAttachingJdb (this, jdbCmdArgs, JDB_STARTED);
// jdb.waitForPrompt(0, false);
}
/**
* Run test in remote mode using listening connector.
*/
private void remoteLaunchAndListen
(String[] jdbCmdArgs, String classToExecute) throws IOException {
jdb = new Jdb(this);
display("Starting jdb listening to remote debuggee");
jdb.launch(jdbCmdArgs);
String address = jdb.waitForListeningJdb();
display("Listening address found: " + address);
debuggee = new RemoteLaunchedDebuggee(this);
String[] javaCmdArgs = makeCommandLineArgs(classToExecute);
try {
debuggee.launch(javaCmdArgs);
} catch (IOException e) {
throw new Failure("Caught exception while launching debuggee VM process:\n\t"
+ e);
};
jdb.waitForMessage(0, JDB_STARTED);
// jdb.waitForPrompt(0, false);
}
} // End of Launcher } // End of Launcher

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -457,18 +457,6 @@ public class ArgumentHandler extends DebugeeArgumentHandler {
} }
*/ */
if (! isLaunchedLocally() && ! isDefaultDebugeeSuspendMode()) {
throw new BadOption("inconsistent options: "
+ "-debugee.launch=" + getLaunchMode()
+ " and -debugee.suspend=" + getDebugeeSuspendMode());
}
if (! isLaunchedLocally() && isLaunchingConnector()) {
throw new BadOption("inconsistent options: "
+ "-debugee.launch=" + getLaunchMode()
+ " and -connector=" + getConnectorType());
}
if (isLaunchingConnector() && ! isDefaultTransport()) { if (isLaunchingConnector() && ! isDefaultTransport()) {
throw new BadOption("inconsistent options: " throw new BadOption("inconsistent options: "
+ "-connector=" + getConnectorType() + "-connector=" + getConnectorType()

View File

@ -127,8 +127,7 @@ public class Binder extends DebugeeBinder {
* started with launching connector. * started with launching connector.
*/ */
public Debugee makeLocalDebugee(Process process) { public Debugee makeLocalDebugee(Process process) {
LocalLaunchedDebugee debugee = new LocalLaunchedDebugee(process, this); return new Debugee(process, this);
return debugee;
} }
/** /**
@ -189,51 +188,22 @@ public class Binder extends DebugeeBinder {
prepareForPipeConnection(argumentHandler); prepareForPipeConnection(argumentHandler);
if (argumentHandler.isLaunchedLocally()) { if (argumentHandler.isDefaultConnector()) {
debugee = localDefaultLaunchDebugee(vmm, classToExecute, classPath);
if (argumentHandler.isDefaultConnector()) { } else if (argumentHandler.isRawLaunchingConnector()) {
debugee = localDefaultLaunchDebugee(vmm, classToExecute, classPath); debugee = localRawLaunchDebugee(vmm, classToExecute, classPath);
} else if (argumentHandler.isRawLaunchingConnector()) { } else if (argumentHandler.isLaunchingConnector()) {
debugee = localRawLaunchDebugee(vmm, classToExecute, classPath); debugee = localLaunchDebugee(vmm, classToExecute, classPath);
} else if (argumentHandler.isLaunchingConnector()) { } else if (argumentHandler.isAttachingConnector()) {
debugee = localLaunchDebugee(vmm, classToExecute, classPath); debugee = localLaunchAndAttachDebugee(vmm, classToExecute, classPath);
} else if (argumentHandler.isAttachingConnector()) { } else if (argumentHandler.isListeningConnector()) {
debugee = localLaunchAndAttachDebugee(vmm, classToExecute, classPath); debugee = localLaunchAndListenDebugee(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 { } else {
throw new Failure("Unexpected debugee launching mode: " + argumentHandler.getLaunchMode()); throw new TestBug("Unexpected connector type for local debugee launch mode"
+ argumentHandler.getConnectorType());
} }
return debugee; return debugee;
} }
@ -486,194 +456,6 @@ public class Binder extends DebugeeBinder {
// -------------------------------------------------- // // -------------------------------------------------- //
/**
* 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);
}
}
// -------------------------------------------------- // // -------------------------------------------------- //
/** /**
@ -920,33 +702,6 @@ public class Binder extends DebugeeBinder {
return makeLocalDebugee(process); 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);
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);
return debugee;
}
public static String readVMStartExceptionOutput(VMStartException e, PrintStream log) { public static String readVMStartExceptionOutput(VMStartException e, PrintStream log) {
StringBuffer msg = new StringBuffer(); StringBuffer msg = new StringBuffer();
try (InputStream is = e.process().getInputStream()) { try (InputStream is = e.process().getInputStream()) {
@ -995,287 +750,4 @@ public class Binder extends DebugeeBinder {
return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); 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();
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -47,7 +47,7 @@ import java.util.*;
* @see Binder * @see Binder
* @see DebugeeProcess * @see DebugeeProcess
*/ */
abstract public class Debugee extends DebugeeProcess { public class Debugee extends DebugeeProcess {
/** /**
* Mirror of the debugee VM. This must be initialized by every * Mirror of the debugee VM. This must be initialized by every
@ -68,6 +68,13 @@ abstract public class Debugee extends DebugeeProcess {
this.argumentHandler = (ArgumentHandler)binder.getArgumentHandler(); this.argumentHandler = (ArgumentHandler)binder.getArgumentHandler();
} }
protected Debugee (Process process, Binder binder) {
super(binder);
this.process = process;
this.binder = binder;
this.argumentHandler = (ArgumentHandler)binder.getArgumentHandler();
}
/** Setup <code>Debugee</code> object with given VM mirror. */ /** Setup <code>Debugee</code> object with given VM mirror. */
public void setupVM(VirtualMachine vm) { public void setupVM(VirtualMachine vm) {
if (this.vm != null) { if (this.vm != null) {

View File

@ -98,13 +98,8 @@ final public class Binder extends DebugeeBinder {
prepareForPipeConnection(argumentHandler); prepareForPipeConnection(argumentHandler);
if (argumentHandler.isLaunchedRemotely()) { debugee = launchDebugee(classToExecute);
connectToBindServer(classToExecute); debugee.redirectOutput(log);
debugee = launchDebugee(classToExecute);
} else {
debugee = launchDebugee(classToExecute);
debugee.redirectOutput(log);
}
Transport transport = debugee.connect(); Transport transport = debugee.connect();
@ -117,334 +112,16 @@ final public class Binder extends DebugeeBinder {
public Debugee launchDebugee (String classToExecute) { public Debugee launchDebugee (String classToExecute) {
try { try {
Debugee debugee = new Debugee(this);
if (argumentHandler.isLaunchedLocally()) { String address = debugee.prepareTransport(argumentHandler);
LocalLaunchedDebugee debugee = new LocalLaunchedDebugee(this); if (address == null)
String address = debugee.prepareTransport(argumentHandler); address = makeTransportAddress();
if (address == null) String[] argsArray = makeCommandLineArgs(classToExecute, address);
address = makeTransportAddress(); debugee.launch(argsArray);
String[] argsArray = makeCommandLineArgs(classToExecute, address); return debugee;
debugee.launch(argsArray);
return debugee;
}
if (argumentHandler.isLaunchedRemotely()) {
RemoteLaunchedDebugee debugee = new RemoteLaunchedDebugee(this);
String address = debugee.prepareTransport(argumentHandler);
if (address == null)
address = makeTransportAddress();
String[] argsArray = makeCommandLineArgs(classToExecute, address);
debugee.launch(argsArray);
return debugee;
}
if (argumentHandler.isLaunchedManually()) {
ManualLaunchedDebugee debugee = new ManualLaunchedDebugee(this);
String address = debugee.prepareTransport(argumentHandler);
if (address == null)
address = makeTransportAddress();
String cmdLine = makeCommandLineString(classToExecute, address, "\"");
debugee.launch(cmdLine);
return debugee;
}
throw new TestBug("Unexpected launching mode: "
+ argumentHandler.getLaunchMode());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(log.getOutStream()); e.printStackTrace(log.getOutStream());
throw new Failure("Caught exception while launching debugee:\n\t" + e); throw new Failure("Caught exception while launching debugee:\n\t" + e);
} }
} }
}
}
/**
* Mirror of locally launched debugee.
*/
final class LocalLaunchedDebugee extends Debugee {
/** Enwrap the existing <code>VM</code> mirror. */
public LocalLaunchedDebugee (Binder binder) {
super(binder);
checkTermination = true;
}
// ---------------------------------------------- //
public void launch(String[] args) throws IOException {
String cmdLine = ArgumentHandler.joinArguments(args, "\"");
display("Starting java process:\n" + cmdLine);
process = binder.launchProcess(args);
}
/** 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 {
return process.waitFor();
}
/** 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 existing <code>VM</code> mirror. */
public RemoteLaunchedDebugee (Binder binder) {
super(binder);
}
// ---------------------------------------------- //
public void launch(String[] args) throws IOException {
String cmdLine = ArgumentHandler.joinArguments(args, "\"");
display("Starting remote java process:\n" + cmdLine);
binder.launchRemoteProcess(args);
}
/** 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()) {
log.display("Killing debugee VM process");
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 {
private int exitCode = 0;
private boolean finished = false;
private static BufferedReader bin = new BufferedReader(new InputStreamReader(System.in));
/** Enwrap the existing <code>VM</code> mirror. */
public ManualLaunchedDebugee (Binder binder) {
super(binder);
}
// ---------------------------------------------- //
public void launch(String commandLine) throws IOException {
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 void putMessage(String msg) {
System.out.println("\n>>> " + msg);
}
private 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 (! terminated()) {
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 () {
if(! finished) {
String answer = askQuestion("Has the VM exited?", "no");
for ( ; ; ) {
if (answer.equals("no"))
return false;
if (answer.equals("yes")) {
finished = true;
waitForDebugee();
break;
}
answer = askQuestion("Wrong answer. Please type yes or no", "yes");
}
}
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() {
try {
bin.close();
} catch (IOException e) {
log.display("WARNING: Caught IOException while closing InputStream");
}
bin = null;
super.close();
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -46,7 +46,7 @@ import java.io.*;
* @see Transport * @see Transport
* @see DebugeeProcess * @see DebugeeProcess
*/ */
abstract public class Debugee extends DebugeeProcess { public class Debugee extends DebugeeProcess {
/** Binder that creates this debugee. */ /** Binder that creates this debugee. */
protected Binder binder = null; protected Binder binder = null;
@ -63,6 +63,12 @@ abstract public class Debugee extends DebugeeProcess {
prefix = "Debugee> "; prefix = "Debugee> ";
} }
public void launch(String[] args) throws IOException {
String cmdLine = ArgumentHandler.joinArguments(args, "\"");
display("Starting java process:\n" + cmdLine);
process = binder.launchProcess(args);
}
/** Return <code>Binder</code> of the debugee object. */ /** Return <code>Binder</code> of the debugee object. */
public Binder getBinder() { public Binder getBinder() {
return binder; return binder;

View File

@ -57,8 +57,6 @@ import java.net.ServerSocket;
* (this works only with <code>-connector=listening</code> and <code>-transport=socket</code>) * (this works only with <code>-connector=listening</code> and <code>-transport=socket</code>)
* <li> <code>-debugee.suspend=[yes|no|default]</code> - * <li> <code>-debugee.suspend=[yes|no|default]</code> -
* should debugee start in suspend mode or not * should debugee start in suspend mode or not
* <li> <code>-debugee.launch=[local|remote|manual]</code> -
* launch and bind to debugee VM locally, remotely (via BindSever) or manually
* <li> <code>-debugee.vmhome=</code>&lt;<i>path</i>&gt; - * <li> <code>-debugee.vmhome=</code>&lt;<i>path</i>&gt; -
* path to JDK used for launching debugee VM * path to JDK used for launching debugee VM
* <li> <code>-debugee.vmkind=</code>&lt;<i>name</i>&gt; - * <li> <code>-debugee.vmkind=</code>&lt;<i>name</i>&gt; -
@ -275,11 +273,8 @@ public class DebugeeArgumentHandler extends ArgumentParser {
* @see #isDefaultDebugeeSuspendMode() * @see #isDefaultDebugeeSuspendMode()
*/ */
public boolean willDebugeeSuspended() { public boolean willDebugeeSuspended() {
if (isLaunchedLocally()) { String mode = getDebugeeSuspendMode();
String mode = getDebugeeSuspendMode(); return mode.equals("no");
return mode.equals("no");
}
return true;
} }
private boolean pipePortInited = false; private boolean pipePortInited = false;
@ -337,54 +332,6 @@ public class DebugeeArgumentHandler extends ArgumentParser {
setOption("-", "pipe.port", value); setOption("-", "pipe.port", value);
} }
/**
* Return debugee VM launching mode, specified by
* <code>-launch.mode</code> command line option, or
* "<i>local</i>" string by default.
*
* Possible values for this option are:
* <ul>
* <li> "<code>local</code>"
* <li> "<code>remote</code>"
* <li> "<code>manual</code>"
* </ul>
*
* @see #isLaunchedLocally()
* @see #isLaunchedRemotely()
* @see #isLaunchedManually()
* @see #setRawArguments(String[])
*/
public String getLaunchMode() {
return options.getProperty("debugee.launch", "local");
}
/**
* Return <i>true</i> if debugee should be launched locally.
*
* @see #getLaunchMode()
*/
public boolean isLaunchedLocally() {
return getLaunchMode().equals("local");
}
/**
* Return <i>true</i> if debugee should be launched remotely via
* BindServer.
*
* @see #getLaunchMode()
*/
public boolean isLaunchedRemotely() {
return getLaunchMode().equals("remote");
}
/**
* Return <i>true</i> if debugee should be launched manually by user.
*
* @see #getLaunchMode()
*/
public boolean isLaunchedManually() {
return getLaunchMode().equals("manual");
}
/** /**
* Return additional options for launching debugee VM, specified by * Return additional options for launching debugee VM, specified by
@ -710,9 +657,7 @@ public class DebugeeArgumentHandler extends ArgumentParser {
} }
// option with any nonempty string value // option with any nonempty string value
if (option.equals("test.host") if (option.equals("debugee.vmkind")
|| option.equals("debugee.host")
|| option.equals("debugee.vmkind")
|| option.equals("debugee.vmhome") || option.equals("debugee.vmhome")
|| option.equals("transport.shname")) { || option.equals("transport.shname")) {
if (value.length() <= 0) { if (value.length() <= 0) {
@ -748,14 +693,10 @@ public class DebugeeArgumentHandler extends ArgumentParser {
return true; return true;
} }
if (option.equals("debugee.launch")) { if (option.equals("debugee.launch")
if ((!value.equals("local")) || option.equals("debugee.host")
&& (!value.equals("remote")) || option.equals("test.host")) {
&& (!value.equals("manual"))) { throw new RuntimeException("option " + option + " is not supported.");
throw new BadOption(option + ": must be one of: "
+ "local, remote, manual " + value);
}
return true;
} }
if (option.equals("jvmdi.strict")) { if (option.equals("jvmdi.strict")) {

View File

@ -35,15 +35,6 @@ import java.util.*;
* debuggee VM and to make connection to it using JDI connector or * debuggee VM and to make connection to it using JDI connector or
* JDWP transport. * JDWP transport.
* <p> * <p>
* The present version of <code>Binder</code> allows
* to launch debuggee VM either on local machine (<i>local</i> launch mode),
* or on remote host using <code>BindServer</code> utility
* (<i>remote</i> launch mode). Also there is an ability to launch
* debuggee VM manually as a separate process on local or remote machine
* (<i>manual</i> launch mode), which is usefull for debugging.
* All these launching modes are specified by command line option
* <code>-debugee.launch</code> recognized by <code>DebugeeArgumentHandler</code>.
* <p>
* <code>Binder</code> also makes it possible to establish TCP/IP * <code>Binder</code> also makes it possible to establish TCP/IP
* connection between debugger and debuggee throw <code>IOPipe</code> * connection between debugger and debuggee throw <code>IOPipe</code>
* object. This connection allows debugger to communicate with debuggee * object. This connection allows debugger to communicate with debuggee
@ -105,8 +96,6 @@ public class DebugeeBinder extends Log.Logger {
} }
// -------------------------------------------------- // // -------------------------------------------------- //
private BindServerListener bindServerListener = null;
private ServerSocket pipeServerSocket = null; private ServerSocket pipeServerSocket = null;
// -------------------------------------------------- // // -------------------------------------------------- //
@ -386,356 +375,12 @@ public class DebugeeBinder extends Log.Logger {
return makeCommandLineArgs(classToExecute, makeTransportAddress()); return makeCommandLineArgs(classToExecute, makeTransportAddress());
} }
/**
* Make connection to remote BindServer and start BindServerListener thread.
*
* @throws IOException if I/O error occured while connecting
*/
public void connectToBindServer(String taskID) {
if (bindServerListener != null) {
throw new Failure("Connection to BindServer already exists");
}
try {
bindServerListener = new BindServerListener(this);
bindServerListener.setDaemon(true);
bindServerListener.connect(taskID);
bindServerListener.start();
} catch (IOException e) {
e.printStackTrace(getOutStream());
throw new Failure("Caught exception while connecting to BindServer:\n\t" + e);
}
}
/**
* Split string into list of substrings using specified separator.
*/
private static String[] splitString(String givenString, String separator) {
Vector<String> tmpList = new Vector<String>();
StringTokenizer tokenizer = new StringTokenizer(givenString, separator);
while(tokenizer.hasMoreTokens()) {
tmpList.add(tokenizer.nextToken());
}
String[] list = new String[tmpList.size()];
for (int i = 0; i < tmpList.size(); i++) {
list[i] = tmpList.elementAt(i);
}
return list;
}
/**
* Send command to remote <code>BindServer</code> and receive reply.
*
* @throws IOException if I/O error occured while launching process
*/
public synchronized Object sendRemoteCommand(Object command) {
try {
bindServerListener.sendCommand(command);
Object reply = bindServerListener.getReply();
return reply;
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Unexpected exception while sending command to BindServer:\n\t"
+ e);
}
}
/**
* Launch remote process using request to <code>BindServer</code>.
*
* @throws IOException if I/O error occured
*/
public void launchRemoteProcess(String[] args) throws IOException {
String pathSeparator = System.getProperty("path.separator");
BindServer.LaunchDebugee command =
new BindServer.LaunchDebugee(args,
System.getProperty("file.separator"),
System.getProperty("user.dir"),
splitString(System.getProperty("java.library.path"), pathSeparator),
splitString(System.getProperty("java.class.path"), pathSeparator),
splitString(System.getProperty("java.library.path"), pathSeparator));
Object reply = sendRemoteCommand(command);
if (reply instanceof BindServer.OK) {
// do nothing
} else if (reply instanceof BindServer.RequestFailed) {
BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
throw new Failure("BindServer error: " + castedReply.reason);
} else {
throw new Failure("Wrong reply from BindServer: " + reply);
}
}
/**
* Return exit status of the remotely launched process
* using request to <code>BindServer</code>.
*/
public int getRemoteProcessStatus () {
Object reply = sendRemoteCommand(new BindServer.DebugeeExitCode());
if (reply instanceof BindServer.OK) {
BindServer.OK castedReply = (BindServer.OK)reply;
return (int)castedReply.info;
} else if (reply instanceof BindServer.CaughtException) {
BindServer.CaughtException castedReply = (BindServer.CaughtException)reply;
throw new IllegalThreadStateException(castedReply.reason);
} else if (reply instanceof BindServer.RequestFailed) {
BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
throw new Failure("BindServer error: " + castedReply.reason);
} else {
throw new Failure("Wrong reply from BindServer: " + reply);
}
}
/**
* Check whether the remotely launched process has been terminated
* using request to <code>BindServer</code>.
*/
public boolean isRemoteProcessTerminated () {
try {
int value = getRemoteProcessStatus();
return true;
} catch (IllegalThreadStateException e) {
return false;
}
}
// ---------------------------------------------- //
/**
* Kill the remotely launched process
* using request to <code>BindServer</code>.
*/
public void killRemoteProcess () {
Object reply = sendRemoteCommand(new BindServer.KillDebugee());
if (reply instanceof BindServer.OK) {
return;
} else if (reply instanceof BindServer.RequestFailed) {
BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
throw new Failure("BindServer error: " + castedReply.reason);
} else {
throw new Failure("Wrong reply from BindServer: " + reply);
}
}
/**
* Wait until the remotely launched process exits or crashes
* using request to <code>BindServer</code>.
*/
public int waitForRemoteProcess () {
Object reply = sendRemoteCommand(new BindServer.WaitForDebugee(0));
if (reply instanceof BindServer.OK) {
BindServer.OK castedReply = (BindServer.OK)reply;
return (int)castedReply.info;
} else if (reply instanceof BindServer.RequestFailed) {
BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
throw new Failure("BindServer error: " + castedReply.reason);
} else {
throw new Failure("Wrong reply from BindServer: " + reply);
}
}
/** /**
* Close binder by closing all started threads. * Close binder by closing all started threads.
*/ */
public void close() { public void close() {
if (bindServerListener != null) {
bindServerListener.close();
}
closePipeServerSocket(); closePipeServerSocket();
} }
/**
* Separate thread for listening connection from <code>BindServer</code>.
*/
private class BindServerListener extends Thread {
private SocketConnection connection = null;
private Log.Logger logger = null;
/** List of received responses from <code>BindServer</code>. */
private LinkedList<BindServer.Response> replies = new LinkedList<BindServer.Response>();
/**
* Make thread.
*/
public BindServerListener(Log.Logger logger) {
this.logger = logger;
}
/**
* Establish connection to <code>BindServer</code>.
*/
public void connect(String taskID) throws IOException {
String host = argumentHandler.getDebugeeHost();
int port = argumentHandler.getBindPortNumber();
display("Connecting to BindServer: " + host + ":" + port);
connection = new SocketConnection(logger, "BindServer");
// connection.setPingTimeout(DebugeeBinder.PING_TIMEOUT);
connection.attach(host, port);
handshake(taskID);
}
/**
* Receive OK(version) from BindServer and check received version number.
*/
private void handshake(String taskID) {
// receive OK(version)
trace(TRACE_LEVEL_ACTIONS, "Waiting for initial OK(version) from BindServer");
Object reply = connection.readObject();
trace(TRACE_LEVEL_ACTIONS, "Got initial OK(version) from BindServer: " + reply);
if (reply instanceof BindServer.RequestFailed) {
BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
trace(TRACE_LEVEL_ACTIONS, "Reply is RequestFailed: throw Failure");
throw new Failure("BindServer error: " + castedReply.reason);
} else if (reply instanceof BindServer.OK) {
BindServer.OK castedReply = (BindServer.OK)reply;
trace(TRACE_LEVEL_ACTIONS, "Reply is OK: check BindServer version");
if (castedReply.info != BindServer.VERSION) {
throw new Failure("Wrong version of BindServer: " + castedReply.info
+ " (expected: " + BindServer.VERSION + ")");
}
display("Connected to BindServer: version " + castedReply.info);
} else {
trace(TRACE_LEVEL_ACTIONS, "Reply is unknown: throw Failure");
throw new Failure("Wrong reply from BindServer: " + reply);
}
// send TaskID(id)
try {
trace(TRACE_LEVEL_ACTIONS, "Sending TaskID(id) to BindServer");
sendCommand(new BindServer.TaskID(taskID));
trace(TRACE_LEVEL_ACTIONS, "Sent TaskID(id) to BindServer");
} catch (IOException e) {
throw new Failure("Caught IOException while sending TaskID(id) to BindServer:\n\t"
+ e);
}
}
/**
* Check if thread is connected to <code>BindServer</code>.
*/
public boolean isConnected() {
return (connection != null && connection.isConnected());
}
/**
* Send a command to </code>BindServer</code>.
*/
public synchronized void sendCommand(Object command) throws IOException {
connection.writeObject(command);
}
/**
* Receive response from <code>BindServer</code>.
*/
public Object getReply() {
synchronized (replies) {
while (replies.isEmpty()) {
if (!isConnected()) {
throw new Failure("No reply from BindServer: connection lost");
}
try {
replies.wait(TRY_DELAY);
} catch (InterruptedException e) {
e.printStackTrace(getOutStream());
throw new Failure("Thread interrupted while waiting for reply from BindServer:\n\t"
+ e);
}
}
Object reply = replies.removeFirst();
if (reply == null) {
throw new Failure("No reply from BindServer: connection lost");
}
return reply;
}
}
/**
* Add response object to the list of received responses.
*/
private void addReply(BindServer.Response reply) {
synchronized (replies) {
replies.add(reply);
replies.notifyAll();
}
}
/**
* Read packets from <code>BindServer<code> connection and
* notify waiting thread if response or IOPipe message received.
* Received lines of redirected streams are put into log.
*/
public void run() {
trace(TRACE_LEVEL_THREADS, "BindServerListener thread started");
try {
for (;;) {
Object reply = connection.readObject();
if (reply == null) {
break;
} else if (reply instanceof BindServer.Disconnect) {
reply = null;
trace(TRACE_LEVEL_ACTIONS, "Packet is Disconnect: close connection");
break;
} else if (reply instanceof BindServer.RedirectedStream) {
BindServer.RedirectedStream castedReply = (BindServer.RedirectedStream)reply;
trace(TRACE_LEVEL_ACTIONS, "Packet is RedirectedStream: put message into log");
log.println(castedReply.line);
} else if (reply instanceof BindServer.Response) {
BindServer.Response castedReply = (BindServer.Response)reply;
trace(TRACE_LEVEL_ACTIONS, "Packet is reply: notify all threads waiting for reply");
addReply(castedReply);
} else {
trace(TRACE_LEVEL_ACTIONS, "Packet is unknown: throw Failure");
throw new Failure("Wrong reply from BindServer: " + reply);
}
}
} catch (Exception e) {
e.printStackTrace(getOutStream());
complain("Caught exception while reading packets from BindServer:\n\t" + e);
} finally {
closeConnection();
addReply(null);
trace(TRACE_LEVEL_THREADS, "BindServerListener thread finished");
}
}
/**
* Send Disconnect command to </code>BindServer</code>.
*/
public void disconnect() {
if (connection == null) return;
try {
sendCommand(new BindServer.Disconnect());
} catch (IOException e) {
display("Caught IOException while requesting disconnection with BindServer");
}
}
/**
* Close socket connection.
*/
public void closeConnection() {
if (connection != null) {
connection.close();
}
}
/**
* Wait for thread finished in the specified timeout or interrupt it.
*/
public void waitForThread(long millis) {
DebugeeBinder.waitForThread(this, millis, logger);
}
/**
* Close this thread by waiting for it finishes or interrupt it
* and close socket connection.
*/
public void close() {
disconnect();
waitForThread(DebugeeBinder.THREAD_TIMEOUT);
closeConnection();
}
} // BindServerListener
} // DebugeeBinder } // DebugeeBinder

View File

@ -74,8 +74,8 @@ abstract public class DebugeeProcess {
/** Argument handler from binder. */ /** Argument handler from binder. */
protected DebugeeArgumentHandler argumentHandler = null; protected DebugeeArgumentHandler argumentHandler = null;
/** Need or not to check debuggee process termination at exit. */ /** Need or not to check debuggee process termination. */
protected boolean checkTermination = false; private boolean checkTermination = true;
/** Debugee VM process or <i>null</i> if not available. */ /** Debugee VM process or <i>null</i> if not available. */
protected Process process = null; protected Process process = null;
@ -164,26 +164,50 @@ abstract public class DebugeeProcess {
// --------------------------------------------------- // // --------------------------------------------------- //
/** Wait until the debugee VM shutdown or crash. */ /** Wait until the debugee VM shutdown or crash. */
abstract protected int waitForDebugee () throws InterruptedException; protected int waitForDebugee() throws InterruptedException {
return process.waitFor();
}
/** Kill the debugee VM. */ /** Kill the debugee VM. */
abstract protected void killDebugee (); protected void killDebugee() {
if (!terminated()) {
log.display("Killing debugee VM process");
process.destroy();
}
}
/** Check whether the debugee VM has been terminated. */ /** Check whether the debugee VM has been terminated. */
abstract public boolean terminated (); public boolean terminated() {
if (process == null)
return true;
try {
int value = process.exitValue();
return true;
} catch (IllegalThreadStateException e) {
return false;
}
}
/** Return the debugee VM exit status. */ /** Return the debugee VM exit status. */
abstract public int getStatus (); public int getStatus() {
return process.exitValue();
}
/** Get a pipe to write to the debugee's stdin stream. */ /** Get a pipe to write to the debugee's stdin stream. */
abstract protected OutputStream getInPipe (); protected OutputStream getInPipe() {
return process.getOutputStream();
}
/** Get a pipe to read the debugee's stdout stream. */ /** Get a pipe to read the debugee's stdout stream. */
abstract protected InputStream getOutPipe (); protected InputStream getOutPipe() {
return process.getInputStream();
}
/** Get a pipe to read the debugee's stderr stream. */ /** Get a pipe to read the debugee's stderr stream. */
abstract protected InputStream getErrPipe (); protected InputStream getErrPipe() {
return process.getErrorStream();
}
// --------------------------------------------------- // // --------------------------------------------------- //
/** /**