duke@435: /* duke@435: * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: import com.sun.jdi.*; duke@435: import com.sun.jdi.connect.*; duke@435: import com.sun.jdi.request.EventRequestManager; duke@435: duke@435: import java.util.*; duke@435: import java.io.*; duke@435: duke@435: duke@435: /** duke@435: * Manages a VM conection for the JDI test framework. duke@435: */ duke@435: class VMConnection { duke@435: private VirtualMachine vm; duke@435: private Process process = null; duke@435: private int outputCompleteCount = 0; duke@435: duke@435: private final Connector connector; duke@435: private final Map connectorArgs; duke@435: private final int traceFlags; duke@435: duke@435: /** duke@435: * Return a String containing VM Options to pass to the debugee duke@435: * or an empty string if there are none. duke@435: * These are read from the first non-comment line duke@435: * in file test/com/sun/jdi/@debuggeeVMOptions. duke@435: */ duke@435: static public String getDebuggeeVMOptions() { duke@435: duke@435: // When we run under jtreg, test.src contains the pathname of duke@435: // the test/com/sun/jdi dir. duke@435: BufferedReader reader; duke@435: final String filename = "@debuggeeVMOptions"; duke@435: String srcDir = System.getProperty("test.src"); duke@435: duke@435: if (srcDir == null) { duke@435: srcDir = System.getProperty("user.dir"); duke@435: } duke@435: srcDir = srcDir + File.separator; duke@435: duke@435: File myDir = new File(srcDir); duke@435: duke@435: File myFile = new File(myDir, filename); duke@435: if (!myFile.canRead()) { duke@435: try { duke@435: // We have some subdirs of test/com/sun/jdi so in case we duke@435: // are in one of them, look in our parent dir for the file. duke@435: myFile = new File(myDir.getCanonicalFile().getParent(), duke@435: filename); duke@435: if (!myFile.canRead()) { duke@435: return ""; duke@435: } duke@435: } catch (IOException ee) { duke@435: System.out.println("-- Error 1 trying to access file " + duke@435: myFile.getPath() + ": " + ee); duke@435: return ""; duke@435: } duke@435: } duke@435: String wholePath = myFile.getPath(); duke@435: try { duke@435: reader = new BufferedReader(new FileReader(myFile)); duke@435: } catch (FileNotFoundException ee) { duke@435: System.out.println("-- Error 2 trying to access file " + duke@435: wholePath + ": " + ee); duke@435: return ""; duke@435: } duke@435: duke@435: String line; duke@435: String retVal = ""; duke@435: while (true) { duke@435: try { duke@435: line = reader.readLine(); duke@435: } catch (IOException ee) { duke@435: System.out.println("-- Error reading options from file " + duke@435: wholePath + ": " + ee); duke@435: break; duke@435: } duke@435: if (line == null) { duke@435: System.out.println("-- No debuggee VM options found in file " + duke@435: wholePath); duke@435: break; duke@435: } duke@435: line = line.trim(); duke@435: if (line.length() != 0 && !line.startsWith("#")) { duke@435: System.out.println("-- Added debuggeeVM options from file " + duke@435: wholePath + ": " + line); duke@435: retVal = line; duke@435: break; duke@435: } duke@435: // Else, read he next line. duke@435: } duke@435: try { duke@435: reader.close(); duke@435: } catch (IOException ee) { duke@435: } duke@435: return retVal; duke@435: } duke@435: duke@435: private Connector findConnector(String name) { duke@435: List connectors = Bootstrap.virtualMachineManager().allConnectors(); duke@435: Iterator iter = connectors.iterator(); duke@435: while (iter.hasNext()) { duke@435: Connector connector = (Connector)iter.next(); duke@435: if (connector.name().equals(name)) { duke@435: return connector; duke@435: } duke@435: } duke@435: return null; duke@435: } duke@435: duke@435: private Map parseConnectorArgs(Connector connector, String argString) { duke@435: StringTokenizer tokenizer = new StringTokenizer(argString, ","); duke@435: Map arguments = connector.defaultArguments(); duke@435: duke@435: while (tokenizer.hasMoreTokens()) { duke@435: String token = tokenizer.nextToken(); duke@435: int index = token.indexOf('='); duke@435: if (index == -1) { duke@435: throw new IllegalArgumentException("Illegal connector argument: " + duke@435: token); duke@435: } duke@435: String name = token.substring(0, index); duke@435: String value = token.substring(index + 1); duke@435: Connector.Argument argument = (Connector.Argument)arguments.get(name); duke@435: if (argument == null) { duke@435: throw new IllegalArgumentException("Argument " + name + duke@435: "is not defined for connector: " + duke@435: connector.name()); duke@435: } duke@435: argument.setValue(value); duke@435: } duke@435: return arguments; duke@435: } duke@435: duke@435: VMConnection(String connectSpec, int traceFlags) { duke@435: String nameString; duke@435: String argString; duke@435: int index = connectSpec.indexOf(':'); duke@435: if (index == -1) { duke@435: nameString = connectSpec; duke@435: argString = ""; duke@435: } else { duke@435: nameString = connectSpec.substring(0, index); duke@435: argString = connectSpec.substring(index + 1); duke@435: } duke@435: duke@435: connector = findConnector(nameString); duke@435: if (connector == null) { duke@435: throw new IllegalArgumentException("No connector named: " + duke@435: nameString); duke@435: } duke@435: duke@435: connectorArgs = parseConnectorArgs(connector, argString); duke@435: this.traceFlags = traceFlags; duke@435: } duke@435: duke@435: synchronized VirtualMachine open() { duke@435: if (connector instanceof LaunchingConnector) { duke@435: vm = launchTarget(); duke@435: } else if (connector instanceof AttachingConnector) { duke@435: vm = attachTarget(); duke@435: } else if (connector instanceof ListeningConnector) { duke@435: vm = listenTarget(); duke@435: } else { duke@435: throw new InternalError("Invalid connect type"); duke@435: } duke@435: vm.setDebugTraceMode(traceFlags); duke@435: System.out.println("JVM version:" + vm.version()); duke@435: System.out.println("JDI version: " + Bootstrap.virtualMachineManager().majorInterfaceVersion() + duke@435: "." + Bootstrap.virtualMachineManager().minorInterfaceVersion()); duke@435: System.out.println("JVM description: " + vm.description()); duke@435: duke@435: return vm; duke@435: } duke@435: duke@435: boolean setConnectorArg(String name, String value) { duke@435: /* duke@435: * Too late if the connection already made duke@435: */ duke@435: if (vm != null) { duke@435: return false; duke@435: } duke@435: duke@435: Connector.Argument argument = (Connector.Argument)connectorArgs.get(name); duke@435: if (argument == null) { duke@435: return false; duke@435: } duke@435: argument.setValue(value); duke@435: return true; duke@435: } duke@435: duke@435: String connectorArg(String name) { duke@435: Connector.Argument argument = (Connector.Argument)connectorArgs.get(name); duke@435: if (argument == null) { duke@435: return ""; duke@435: } duke@435: return argument.value(); duke@435: } duke@435: duke@435: public synchronized VirtualMachine vm() { duke@435: if (vm == null) { duke@435: throw new InternalError("VM not connected"); duke@435: } else { duke@435: return vm; duke@435: } duke@435: } duke@435: duke@435: boolean isOpen() { duke@435: return (vm != null); duke@435: } duke@435: duke@435: boolean isLaunch() { duke@435: return (connector instanceof LaunchingConnector); duke@435: } duke@435: duke@435: Connector connector() { duke@435: return connector; duke@435: } duke@435: duke@435: boolean isListen() { duke@435: return (connector instanceof ListeningConnector); duke@435: } duke@435: duke@435: boolean isAttach() { duke@435: return (connector instanceof AttachingConnector); duke@435: } duke@435: duke@435: private synchronized void notifyOutputComplete() { duke@435: outputCompleteCount++; duke@435: notifyAll(); duke@435: } duke@435: duke@435: private synchronized void waitOutputComplete() { duke@435: // Wait for stderr and stdout duke@435: if (process != null) { duke@435: while (outputCompleteCount < 2) { duke@435: try {wait();} catch (InterruptedException e) {} duke@435: } duke@435: } duke@435: } duke@435: duke@435: public void disposeVM() { duke@435: try { duke@435: if (vm != null) { duke@435: vm.dispose(); duke@435: vm = null; duke@435: } duke@435: } finally { duke@435: if (process != null) { duke@435: process.destroy(); duke@435: process = null; duke@435: } duke@435: waitOutputComplete(); duke@435: } duke@435: } duke@435: duke@435: private void dumpStream(InputStream stream) throws IOException { duke@435: PrintStream outStream = System.out; duke@435: BufferedReader in = duke@435: new BufferedReader(new InputStreamReader(stream)); duke@435: String line; duke@435: while ((line = in.readLine()) != null) { duke@435: outStream.println(line); duke@435: } duke@435: } duke@435: duke@435: /** duke@435: * Create a Thread that will retrieve and display any output. duke@435: * Needs to be high priority, else debugger may exit before duke@435: * it can be displayed. duke@435: */ duke@435: private void displayRemoteOutput(final InputStream stream) { duke@435: Thread thr = new Thread("output reader") { duke@435: public void run() { duke@435: try { duke@435: dumpStream(stream); duke@435: } catch (IOException ex) { duke@435: System.err.println("IOException reading output of child java interpreter:" duke@435: + ex.getMessage()); duke@435: } finally { duke@435: notifyOutputComplete(); duke@435: } duke@435: } duke@435: }; duke@435: thr.setPriority(Thread.MAX_PRIORITY-1); duke@435: thr.start(); duke@435: } duke@435: duke@435: private void dumpFailedLaunchInfo(Process process) { duke@435: try { duke@435: dumpStream(process.getErrorStream()); duke@435: dumpStream(process.getInputStream()); duke@435: } catch (IOException e) { duke@435: System.err.println("Unable to display process output: " + duke@435: e.getMessage()); duke@435: } duke@435: } duke@435: duke@435: /* launch child target vm */ duke@435: private VirtualMachine launchTarget() { duke@435: LaunchingConnector launcher = (LaunchingConnector)connector; duke@435: try { duke@435: VirtualMachine vm = launcher.launch(connectorArgs); duke@435: process = vm.process(); duke@435: displayRemoteOutput(process.getErrorStream()); duke@435: displayRemoteOutput(process.getInputStream()); duke@435: return vm; duke@435: } catch (IOException ioe) { duke@435: ioe.printStackTrace(); duke@435: System.err.println("\n Unable to launch target VM."); duke@435: } catch (IllegalConnectorArgumentsException icae) { duke@435: icae.printStackTrace(); duke@435: System.err.println("\n Internal debugger error."); duke@435: } catch (VMStartException vmse) { duke@435: System.err.println(vmse.getMessage() + "\n"); duke@435: dumpFailedLaunchInfo(vmse.process()); duke@435: System.err.println("\n Target VM failed to initialize."); duke@435: } duke@435: return null; // Shuts up the compiler duke@435: } duke@435: duke@435: /* attach to running target vm */ duke@435: private VirtualMachine attachTarget() { duke@435: AttachingConnector attacher = (AttachingConnector)connector; duke@435: try { duke@435: return attacher.attach(connectorArgs); duke@435: } catch (IOException ioe) { duke@435: ioe.printStackTrace(); duke@435: System.err.println("\n Unable to attach to target VM."); duke@435: } catch (IllegalConnectorArgumentsException icae) { duke@435: icae.printStackTrace(); duke@435: System.err.println("\n Internal debugger error."); duke@435: } duke@435: return null; // Shuts up the compiler duke@435: } duke@435: duke@435: /* listen for connection from target vm */ duke@435: private VirtualMachine listenTarget() { duke@435: ListeningConnector listener = (ListeningConnector)connector; duke@435: try { duke@435: String retAddress = listener.startListening(connectorArgs); duke@435: System.out.println("Listening at address: " + retAddress); duke@435: vm = listener.accept(connectorArgs); duke@435: listener.stopListening(connectorArgs); duke@435: return vm; duke@435: } catch (IOException ioe) { duke@435: ioe.printStackTrace(); duke@435: System.err.println("\n Unable to attach to target VM."); duke@435: } catch (IllegalConnectorArgumentsException icae) { duke@435: icae.printStackTrace(); duke@435: System.err.println("\n Internal debugger error."); duke@435: } duke@435: return null; // Shuts up the compiler duke@435: } duke@435: }