1 /* 2 * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 import com.sun.jdi.*; 26 import com.sun.jdi.connect.*; 27 import com.sun.jdi.request.EventRequestManager; 28 29 import java.util.*; 30 import java.io.*; 31 32 33 /** 34 * Manages a VM conection for the JDI test framework. 35 */ 36 class VMConnection { 37 private VirtualMachine vm; 38 private Process process = null; 39 private int outputCompleteCount = 0; 40 41 private final Connector connector; 42 private final Map connectorArgs; 43 private final int traceFlags; 44 45 /** 46 * Return a String containing VM Options to pass to the debugee 47 * or an empty string if there are none. 48 * These are read from the first non-comment line 49 * in file test/com/sun/jdi/@debuggeeVMOptions. 50 */ getDebuggeeVMOptions()51 static public String getDebuggeeVMOptions() { 52 53 // When we run under jtreg, test.src contains the pathname of 54 // the test/com/sun/jdi dir. 55 BufferedReader reader; 56 final String filename = "@debuggeeVMOptions"; 57 String srcDir = System.getProperty("test.src"); 58 59 if (srcDir == null) { 60 srcDir = System.getProperty("user.dir"); 61 } 62 srcDir = srcDir + File.separator; 63 64 File myDir = new File(srcDir); 65 66 File myFile = new File(myDir, filename); 67 if (!myFile.canRead()) { 68 try { 69 // We have some subdirs of test/com/sun/jdi so in case we 70 // are in one of them, look in our parent dir for the file. 71 myFile = new File(myDir.getCanonicalFile().getParent(), 72 filename); 73 if (!myFile.canRead()) { 74 return ""; 75 } 76 } catch (IOException ee) { 77 System.out.println("-- Error 1 trying to access file " + 78 myFile.getPath() + ": " + ee); 79 return ""; 80 } 81 } 82 String wholePath = myFile.getPath(); 83 try { 84 reader = new BufferedReader(new FileReader(myFile)); 85 } catch (FileNotFoundException ee) { 86 System.out.println("-- Error 2 trying to access file " + 87 wholePath + ": " + ee); 88 return ""; 89 } 90 91 String line; 92 String retVal = ""; 93 while (true) { 94 try { 95 line = reader.readLine(); 96 } catch (IOException ee) { 97 System.out.println("-- Error reading options from file " + 98 wholePath + ": " + ee); 99 break; 100 } 101 if (line == null) { 102 System.out.println("-- No debuggee VM options found in file " + 103 wholePath); 104 break; 105 } 106 line = line.trim(); 107 if (line.length() != 0 && !line.startsWith("#")) { 108 System.out.println("-- Added debuggeeVM options from file " + 109 wholePath + ": " + line); 110 retVal = line; 111 break; 112 } 113 // Else, read he next line. 114 } 115 try { 116 reader.close(); 117 } catch (IOException ee) { 118 } 119 return retVal; 120 } 121 findConnector(String name)122 private Connector findConnector(String name) { 123 List connectors = Bootstrap.virtualMachineManager().allConnectors(); 124 Iterator iter = connectors.iterator(); 125 while (iter.hasNext()) { 126 Connector connector = (Connector)iter.next(); 127 if (connector.name().equals(name)) { 128 return connector; 129 } 130 } 131 return null; 132 } 133 parseConnectorArgs(Connector connector, String argString)134 private Map parseConnectorArgs(Connector connector, String argString) { 135 StringTokenizer tokenizer = new StringTokenizer(argString, ","); 136 Map arguments = connector.defaultArguments(); 137 138 while (tokenizer.hasMoreTokens()) { 139 String token = tokenizer.nextToken(); 140 int index = token.indexOf('='); 141 if (index == -1) { 142 throw new IllegalArgumentException("Illegal connector argument: " + 143 token); 144 } 145 String name = token.substring(0, index); 146 String value = token.substring(index + 1); 147 Connector.Argument argument = (Connector.Argument)arguments.get(name); 148 if (argument == null) { 149 throw new IllegalArgumentException("Argument " + name + 150 "is not defined for connector: " + 151 connector.name()); 152 } 153 argument.setValue(value); 154 } 155 return arguments; 156 } 157 VMConnection(String connectSpec, int traceFlags)158 VMConnection(String connectSpec, int traceFlags) { 159 String nameString; 160 String argString; 161 int index = connectSpec.indexOf(':'); 162 if (index == -1) { 163 nameString = connectSpec; 164 argString = ""; 165 } else { 166 nameString = connectSpec.substring(0, index); 167 argString = connectSpec.substring(index + 1); 168 } 169 170 connector = findConnector(nameString); 171 if (connector == null) { 172 throw new IllegalArgumentException("No connector named: " + 173 nameString); 174 } 175 176 connectorArgs = parseConnectorArgs(connector, argString); 177 this.traceFlags = traceFlags; 178 } 179 open()180 synchronized VirtualMachine open() { 181 if (connector instanceof LaunchingConnector) { 182 vm = launchTarget(); 183 } else if (connector instanceof AttachingConnector) { 184 vm = attachTarget(); 185 } else if (connector instanceof ListeningConnector) { 186 vm = listenTarget(); 187 } else { 188 throw new InternalError("Invalid connect type"); 189 } 190 vm.setDebugTraceMode(traceFlags); 191 System.out.println("JVM version:" + vm.version()); 192 System.out.println("JDI version: " + Bootstrap.virtualMachineManager().majorInterfaceVersion() + 193 "." + Bootstrap.virtualMachineManager().minorInterfaceVersion()); 194 System.out.println("JVM description: " + vm.description()); 195 196 return vm; 197 } 198 setConnectorArg(String name, String value)199 boolean setConnectorArg(String name, String value) { 200 /* 201 * Too late if the connection already made 202 */ 203 if (vm != null) { 204 return false; 205 } 206 207 Connector.Argument argument = (Connector.Argument)connectorArgs.get(name); 208 if (argument == null) { 209 return false; 210 } 211 argument.setValue(value); 212 return true; 213 } 214 connectorArg(String name)215 String connectorArg(String name) { 216 Connector.Argument argument = (Connector.Argument)connectorArgs.get(name); 217 if (argument == null) { 218 return ""; 219 } 220 return argument.value(); 221 } 222 vm()223 public synchronized VirtualMachine vm() { 224 if (vm == null) { 225 throw new InternalError("VM not connected"); 226 } else { 227 return vm; 228 } 229 } 230 isOpen()231 boolean isOpen() { 232 return (vm != null); 233 } 234 isLaunch()235 boolean isLaunch() { 236 return (connector instanceof LaunchingConnector); 237 } 238 connector()239 Connector connector() { 240 return connector; 241 } 242 isListen()243 boolean isListen() { 244 return (connector instanceof ListeningConnector); 245 } 246 isAttach()247 boolean isAttach() { 248 return (connector instanceof AttachingConnector); 249 } 250 notifyOutputComplete()251 private synchronized void notifyOutputComplete() { 252 outputCompleteCount++; 253 notifyAll(); 254 } 255 waitOutputComplete()256 private synchronized void waitOutputComplete() { 257 // Wait for stderr and stdout 258 if (process != null) { 259 while (outputCompleteCount < 2) { 260 try {wait();} catch (InterruptedException e) {} 261 } 262 } 263 } 264 disposeVM()265 public void disposeVM() { 266 try { 267 if (vm != null) { 268 vm.dispose(); 269 vm = null; 270 } 271 } finally { 272 if (process != null) { 273 process.destroy(); 274 process = null; 275 } 276 waitOutputComplete(); 277 } 278 } 279 dumpStream(InputStream stream)280 private void dumpStream(InputStream stream) throws IOException { 281 PrintStream outStream = System.out; 282 BufferedReader in = 283 new BufferedReader(new InputStreamReader(stream)); 284 String line; 285 while ((line = in.readLine()) != null) { 286 outStream.println(line); 287 } 288 } 289 290 /** 291 * Create a Thread that will retrieve and display any output. 292 * Needs to be high priority, else debugger may exit before 293 * it can be displayed. 294 */ displayRemoteOutput(final InputStream stream)295 private void displayRemoteOutput(final InputStream stream) { 296 Thread thr = new Thread("output reader") { 297 public void run() { 298 try { 299 dumpStream(stream); 300 } catch (IOException ex) { 301 System.err.println("IOException reading output of child java interpreter:" 302 + ex.getMessage()); 303 } finally { 304 notifyOutputComplete(); 305 } 306 } 307 }; 308 thr.setPriority(Thread.MAX_PRIORITY-1); 309 thr.start(); 310 } 311 dumpFailedLaunchInfo(Process process)312 private void dumpFailedLaunchInfo(Process process) { 313 try { 314 dumpStream(process.getErrorStream()); 315 dumpStream(process.getInputStream()); 316 } catch (IOException e) { 317 System.err.println("Unable to display process output: " + 318 e.getMessage()); 319 } 320 } 321 322 /* launch child target vm */ launchTarget()323 private VirtualMachine launchTarget() { 324 LaunchingConnector launcher = (LaunchingConnector)connector; 325 try { 326 VirtualMachine vm = launcher.launch(connectorArgs); 327 process = vm.process(); 328 displayRemoteOutput(process.getErrorStream()); 329 displayRemoteOutput(process.getInputStream()); 330 return vm; 331 } catch (IOException ioe) { 332 ioe.printStackTrace(); 333 System.err.println("\n Unable to launch target VM."); 334 } catch (IllegalConnectorArgumentsException icae) { 335 icae.printStackTrace(); 336 System.err.println("\n Internal debugger error."); 337 } catch (VMStartException vmse) { 338 System.err.println(vmse.getMessage() + "\n"); 339 dumpFailedLaunchInfo(vmse.process()); 340 System.err.println("\n Target VM failed to initialize."); 341 } 342 return null; // Shuts up the compiler 343 } 344 345 /* attach to running target vm */ attachTarget()346 private VirtualMachine attachTarget() { 347 AttachingConnector attacher = (AttachingConnector)connector; 348 try { 349 return attacher.attach(connectorArgs); 350 } catch (IOException ioe) { 351 ioe.printStackTrace(); 352 System.err.println("\n Unable to attach to target VM."); 353 } catch (IllegalConnectorArgumentsException icae) { 354 icae.printStackTrace(); 355 System.err.println("\n Internal debugger error."); 356 } 357 return null; // Shuts up the compiler 358 } 359 360 /* listen for connection from target vm */ listenTarget()361 private VirtualMachine listenTarget() { 362 ListeningConnector listener = (ListeningConnector)connector; 363 try { 364 String retAddress = listener.startListening(connectorArgs); 365 System.out.println("Listening at address: " + retAddress); 366 vm = listener.accept(connectorArgs); 367 listener.stopListening(connectorArgs); 368 return vm; 369 } catch (IOException ioe) { 370 ioe.printStackTrace(); 371 System.err.println("\n Unable to attach to target VM."); 372 } catch (IllegalConnectorArgumentsException icae) { 373 icae.printStackTrace(); 374 System.err.println("\n Internal debugger error."); 375 } 376 return null; // Shuts up the compiler 377 } 378 } 379