Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Binder.java
41161 views
/*1* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package nsk.share.jdi;2425import jdk.test.lib.Platform;26import nsk.share.*;27import nsk.share.jpda.*;2829import com.sun.jdi.*;30import com.sun.jdi.connect.*;3132import com.sun.jdi.connect.Connector.Argument;33import java.io.*;34import java.net.*;35import java.util.*;3637/**38* This class provides debugger with connection to debugee VM39* using JDI connectors.40*<p>41* This class provides abilities to launch and bind to debugee VM42* as described for base <code>DebugeeBinder</code> class,43* using JDI connectors and <code>com.sun.VirtualMachine</code> mirror.44* <p>45* When <code>Binder</code> is asked to bind to debugee by invoking46* <code>bindToBebugee()</code> method it uses47* <code>com.sun.jdi.Connector</code> object corresponding to48* value of command line options <code>-connector</code> and49* <code>-transport</code> to launch and connect to debugee VM.50* After debugee is launched and connection is established51* <code>Binder</code> uses <code>com.sun.jdi.VirtualMachine</code>52* object to construct <code>Debugee</code> object, that53* provides abilities to interact with debugee VM.54*55* @see Debugee56* @see DebugeeBinder57*/58public class Binder extends DebugeeBinder {5960/**61* Default message prefix for <code>Binder</code> object.62*/63public static final String LOG_PREFIX = "binder> ";6465/**66* Get version string.67*/68public static String getVersion () {69return "@(#)Binder.java 1.14 03/10/08";70}7172// -------------------------------------------------- //7374/**75* Handler of command line arguments.76*/77private ArgumentHandler argumentHandler = null;7879/**80* Return <code>argumentHandler</code> of this binder.81*/82public ArgumentHandler getArgumentHandler() {83return argumentHandler;84}8586// -------------------------------------------------- //8788/**89* Make <code>Binder</code> object and pass raw command line arguments.90*91* @deprecated Use newer92* <code>Binder(ArgumentHandler,Log)</code>93* constructor.94*/95@Deprecated96public Binder (String args[]) {97this(args, new Log(System.err));98}99100/**101* Make <code>Binder</code> object for raw command line arguments102* and specified <code>log</code> object.103*104* @deprecated Use newer105* <code>Binder(ArgumentHandler,Log)</code>106* constructor.107*/108@Deprecated109public Binder (String args[], Log log) {110this(new ArgumentHandler(args), log);111}112113/**114* Make <code>Binder</code> object for specified command line arguments115* and <code>log</code> object.116*/117public Binder (ArgumentHandler argumentHandler, Log log) {118super(argumentHandler, log);119this.argumentHandler = argumentHandler;120}121122// -------------------------------------------------- //123124/**125* Make initial <code>Debugee</code> object for local debuggee process126* started with launching connector.127*/128public Debugee makeLocalDebugee(Process process) {129LocalLaunchedDebugee debugee = new LocalLaunchedDebugee(process, this);130131Finalizer finalizer = new Finalizer(debugee);132finalizer.activate();133134return debugee;135}136137/**138* Launch local debuggee process with specified command line139* and make initial <code>Debugee</code> object.140*/141public Debugee startLocalDebugee(String cmd) {142Process process = null;143144try {145process = launchProcess(cmd);146} catch (IOException e) {147e.printStackTrace(log.getOutStream());148throw new Failure("Caught exception while launching local debuggee VM process:\n\t"149+ e);150}151152return makeLocalDebugee(process);153}154155/**156* Make debuggee wrapper for already launched debuggee VM.157* After enwraping debugee's output is redirected to Binder's log,158* VMStartEvent is received and debuggee is initialized.159*/160public Debugee enwrapDebugee(VirtualMachine vm, Process proc) {161Debugee debugee = makeLocalDebugee(proc);162163display("Redirecting VM output");164debugee.redirectOutput(log);165debugee.setupVM(vm);166167long timeout = argumentHandler.getWaitTime() * 60 * 1000; // milliseconds168169display("Waiting for VM initialized");170debugee.waitForVMInit(timeout);171172return debugee;173}174175/**176* Launch debugee VM and establish connection to it without waiting for VMStartEvent.177* After launching debugee's output is redirected to Binder's log,178* but VMStartEvent is not received and so debuggee is not fully initialized.179*180* @see #bindToDebugee(String)181*/182public Debugee bindToDebugeeNoWait(String classToExecute) {183184VirtualMachineManager vmm = Bootstrap.virtualMachineManager();185display("VirtualMachineManager: version "186+ vmm.majorInterfaceVersion() + "."187+ vmm.minorInterfaceVersion());188189Debugee debugee = null;190191String classPath = null;192// classPath = System.getProperty("java.class.path");193194prepareForPipeConnection(argumentHandler);195196if (argumentHandler.isLaunchedLocally()) {197198if (argumentHandler.isDefaultConnector()) {199debugee = localDefaultLaunchDebugee(vmm, classToExecute, classPath);200} else if (argumentHandler.isRawLaunchingConnector()) {201debugee = localRawLaunchDebugee(vmm, classToExecute, classPath);202} else if (argumentHandler.isLaunchingConnector()) {203debugee = localLaunchDebugee(vmm, classToExecute, classPath);204} else if (argumentHandler.isAttachingConnector()) {205debugee = localLaunchAndAttachDebugee(vmm, classToExecute, classPath);206} else if (argumentHandler.isListeningConnector()) {207debugee = localLaunchAndListenDebugee(vmm, classToExecute, classPath);208} else {209throw new TestBug("Unexpected connector type for local debugee launch mode"210+ argumentHandler.getConnectorType());211}212213} else if (argumentHandler.isLaunchedRemotely()) {214215connectToBindServer(classToExecute);216217if (argumentHandler.isAttachingConnector()) {218debugee = remoteLaunchAndAttachDebugee(vmm, classToExecute, classPath);219} else if (argumentHandler.isListeningConnector()) {220debugee = remoteLaunchAndListenDebugee(vmm, classToExecute, classPath);221} else {222throw new TestBug("Unexpected connector type for remote debugee launch mode"223+ argumentHandler.getConnectorType());224}225226} else if (argumentHandler.isLaunchedManually()) {227228if (argumentHandler.isAttachingConnector()) {229debugee = manualLaunchAndAttachDebugee(vmm, classToExecute, classPath);230} else if (argumentHandler.isListeningConnector()) {231debugee = manualLaunchAndListenDebugee(vmm, classToExecute, classPath);232} else {233throw new TestBug("Unexpected connector type for manual debugee launch mode"234+ argumentHandler.getConnectorType());235}236237} else {238throw new Failure("Unexpected debugee launching mode: " + argumentHandler.getLaunchMode());239}240241return debugee;242}243244/**245* Launch debugee VM and establish JDI connection.246* After launching debugee's output is redirected to Binder's log,247* VMStart event is received and debuggee is initialized.248*249* @see #bindToDebugeeNoWait(String)250*/251public Debugee bindToDebugee(String classToExecute) {252Debugee debugee = bindToDebugeeNoWait(classToExecute);253254if(argumentHandler.getOptions().getProperty("traceAll") != null)255debugee.VM().setDebugTraceMode(VirtualMachine.TRACE_ALL);256257long timeout = argumentHandler.getWaitTime() * 60 * 1000; // milliseconds258259display("Waiting for VM initialized");260debugee.waitForVMInit(timeout);261262return debugee;263}264265// -------------------------------------------------- //266267/**268* Launch debugee locally via the default LaunchingConnector.269*/270private Debugee localDefaultLaunchDebugee (VirtualMachineManager vmm,271String classToExecute,272String classPath) {273display("Finding connector: " + "default" );274LaunchingConnector connector = vmm.defaultConnector();275Map<String,? extends Argument> arguments = setupLaunchingConnector(connector, classToExecute, classPath);276277VirtualMachine vm;278try {279display("Launching debugee");280vm = connector.launch(arguments);281} catch (IllegalConnectorArgumentsException e) {282e.printStackTrace(log.getOutStream());283throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e);284} catch (VMStartException e) {285e.printStackTrace(log.getOutStream());286String msg = readVMStartExceptionOutput(e, log.getOutStream());287throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\n" + msg);288} catch (IOException e) {289e.printStackTrace(log.getOutStream());290throw new Failure("Caught exception while launching debugee VM:\n\t" + e);291};292293Process process = vm.process();294Debugee debugee = makeLocalDebugee(process);295debugee.redirectOutput(log);296debugee.setupVM(vm);297298return debugee;299}300301302/**303* Launch debugee locally via the default LaunchingConnector.304*/305private Debugee localLaunchDebugee (VirtualMachineManager vmm,306String classToExecute,307String classPath) {308309display("Finding connector: " + argumentHandler.getConnectorName() );310LaunchingConnector connector =311(LaunchingConnector) findConnector(argumentHandler.getConnectorName(),312vmm.launchingConnectors());313Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupLaunchingConnector(connector, classToExecute, classPath);314315VirtualMachine vm;316try {317display("Launching debugee");318vm = connector.launch(arguments);319} catch (IllegalConnectorArgumentsException e) {320e.printStackTrace(log.getOutStream());321throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e);322} catch (VMStartException e) {323e.printStackTrace(log.getOutStream());324String msg = readVMStartExceptionOutput(e, log.getOutStream());325throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\nProcess output:\n\t" + msg);326} catch (IOException e) {327e.printStackTrace(log.getOutStream());328throw new Failure("Caught exception while launching debugee VM:\n\t" + e);329};330331Process process = vm.process();332Debugee debugee = makeLocalDebugee(process);333debugee.redirectOutput(log);334debugee.setupVM(vm);335336return debugee;337}338339/**340* Launch debugee locally via the RawLaunchingConnector.341*/342private Debugee localRawLaunchDebugee (VirtualMachineManager vmm,343String classToExecute,344String classPath) {345display("Finding connector: " + argumentHandler.getConnectorName() );346LaunchingConnector connector =347(LaunchingConnector) findConnector(argumentHandler.getConnectorName(),348vmm.launchingConnectors());349Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupRawLaunchingConnector(connector, classToExecute, classPath);350351VirtualMachine vm;352try {353display("Launching debugee");354vm = connector.launch(arguments);355} catch (IllegalConnectorArgumentsException e) {356e.printStackTrace(log.getOutStream());357throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e);358} catch (VMStartException e) {359e.printStackTrace(log.getOutStream());360String msg = readVMStartExceptionOutput(e, log.getOutStream());361throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\nProcess output:\n\t" + msg);362} catch (IOException e) {363e.printStackTrace(log.getOutStream());364throw new Failure("Caught exception while launching debugee VM:\n\t" + e);365};366367Process process = vm.process();368Debugee debugee = makeLocalDebugee(process);369debugee.redirectOutput(log);370debugee.setupVM(vm);371372return debugee;373}374375/**376* Launch debugee VM locally as a local process and connect to it using377* <code>AttachingConnector</code>.378*/379private Debugee localLaunchAndAttachDebugee (VirtualMachineManager vmm,380String classToExecute,381String classPath) {382display("FindingConnector: " + argumentHandler.getConnectorName() );383AttachingConnector connector =384(AttachingConnector) findConnector(argumentHandler.getConnectorName(),385vmm.attachingConnectors());386Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupAttachingConnector(connector, classToExecute, classPath);387388String address = makeTransportAddress();389String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);390String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");391392display("Starting java process:\n\t" + javaCmdLine);393Debugee debugee = startLocalDebugee(cmdLineArgs);394debugee.redirectOutput(log);395396display("Attaching to debugee");397VirtualMachine vm = null;398IOException ioe = null;399for (int i = 0; i < CONNECT_TRIES; i++) {400try {401vm = connector.attach(arguments);402display("Debugee attached");403debugee.setupVM(vm);404return debugee;405} catch (IOException e) {406display("Attempt #" + i + " to connect to debugee VM failed:\n\t" + e);407ioe = e;408if (debugee.terminated()) {409throw new Failure("Unable to connect to debuggee VM: VM process is terminated");410}411try {412Thread.currentThread().sleep(CONNECT_TRY_DELAY);413} catch (InterruptedException ie) {414ie.printStackTrace(log.getOutStream());415throw new Failure("Thread interrupted while pausing connection attempts:\n\t"416+ ie);417}418} catch (IllegalConnectorArgumentsException e) {419e.printStackTrace(log.getOutStream());420throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e);421}422}423throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES424+ " tries:\n\t" + ioe);425}426427/**428* Launch debugee VM locally as a local process and connect to it using429* <code>ListeningConnector</code>.430*/431private Debugee localLaunchAndListenDebugee (VirtualMachineManager vmm,432String classToExecute,433String classPath) {434display("Finding connector: " + argumentHandler.getConnectorName() );435ListeningConnector connector =436(ListeningConnector) findConnector(argumentHandler.getConnectorName(),437vmm.listeningConnectors());438Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupListeningConnector(connector, classToExecute, classPath);439440String address = null;441try {442display("Listening for connection from debugee");443address = connector.startListening(arguments);444} catch (IllegalConnectorArgumentsException e) {445e.printStackTrace(log.getOutStream());446throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);447} catch (IOException e) {448e.printStackTrace(log.getOutStream());449throw new Failure("Caught exception while starting listening debugee VM:\n\t" + e);450};451452String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);453String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");454455display("Starting java process:\n\t" + javaCmdLine);456Debugee debugee = startLocalDebugee(cmdLineArgs);457debugee.redirectOutput(log);458459display("Waiting for connection from debugee");460VirtualMachine vm = null;461IOException ioe = null;462for (int i = 0; i < CONNECT_TRIES; i++) {463try {464vm = connector.accept(arguments);465connector.stopListening(arguments);466display("Debugee attached");467debugee.setupVM(vm);468return debugee;469} catch (IOException e) {470display("Attempt #" + i + " to listen debugee VM failed:\n\t" + e);471ioe = e;472if (debugee.terminated()) {473throw new Failure("Unable to connect to debuggee VM: VM process is terminated");474}475try {476Thread.currentThread().sleep(CONNECT_TRY_DELAY);477} catch (InterruptedException ie) {478ie.printStackTrace(log.getOutStream());479throw new Failure("Thread interrupted while pausing connection attempts:\n\t"480+ ie);481}482} catch (IllegalConnectorArgumentsException e) {483e.printStackTrace(log.getOutStream());484throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);485}486}487throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES488+ " tries:\n\t" + ioe);489}490491// -------------------------------------------------- //492493/**494* Launch debugee VM remotely via <code>BindServer</code> and connect to it using495* <code>AttachingConnector</code>.496*/497private Debugee remoteLaunchAndAttachDebugee (VirtualMachineManager vmm,498String classToExecute,499String classPath) {500display("Finding connector: " + argumentHandler.getConnectorName() );501AttachingConnector connector =502(AttachingConnector) findConnector(argumentHandler.getConnectorName(),503vmm.attachingConnectors());504505Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupAttachingConnector(connector, classToExecute, classPath);506507String address = makeTransportAddress();508String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);509String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");510511display("Starting remote java process:\n\t" + javaCmdLine);512Debugee debugee = startRemoteDebugee(cmdLineArgs);513514display("Attaching to debugee");515VirtualMachine vm;516IOException ioe = null;517for (int i = 0; i < CONNECT_TRIES; i++) {518try {519vm = connector.attach(arguments);520display("Debugee attached");521debugee.setupVM(vm);522return debugee;523} catch (IOException e) {524display("Attempt #" + i + " to connect to debugee VM failed:\n\t" + e);525ioe = e;526if (debugee.terminated()) {527throw new Failure("Unable to connect to debuggee VM: VM process is terminated");528}529try {530Thread.currentThread().sleep(CONNECT_TRY_DELAY);531} catch (InterruptedException ie) {532ie.printStackTrace(log.getOutStream());533throw new Failure("Thread interrupted while pausing connection attempts:\n\t"534+ ie);535}536} catch (IllegalConnectorArgumentsException e) {537e.printStackTrace(log.getOutStream());538throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e);539}540}541throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES542+ " tries:\n\t" + ioe);543}544545/**546* Launch debugee VM remotely via <code>BindServer</code> and connect to it using547* <code>ListeningConnector</code>.548*/549private Debugee remoteLaunchAndListenDebugee (VirtualMachineManager vmm,550String classToExecute,551String classPath) {552display("Finding connector: " + argumentHandler.getConnectorName() );553ListeningConnector connector =554(ListeningConnector) findConnector(argumentHandler.getConnectorName(),555vmm.listeningConnectors());556Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupListeningConnector(connector, classToExecute, classPath);557558String address = null;559try {560display("Listening for connection from debugee");561address = connector.startListening(arguments);562} catch (IllegalConnectorArgumentsException e) {563e.printStackTrace(log.getOutStream());564throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);565} catch (IOException e) {566e.printStackTrace(log.getOutStream());567throw new Failure("Caught exception while starting listening debugee VM:\n\t" + e);568};569570String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);571String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");572573display("Starting remote java process:\n\t" + javaCmdLine);574Debugee debugee = startRemoteDebugee(cmdLineArgs);575576display("Waiting for connection from debugee");577VirtualMachine vm;578IOException ioe = null;579for (int i = 0; i < CONNECT_TRIES; i++) {580try {581vm = connector.accept(arguments);582connector.stopListening(arguments);583display("Debugee attached");584debugee.setupVM(vm);585return debugee;586} catch (IOException e) {587display("Attempt #" + i + " to listen debugee VM failed:\n\t" + e);588ioe = e;589if (debugee.terminated()) {590throw new Failure("Unable to connect to debuggee VM: VM process is terminated");591}592try {593Thread.currentThread().sleep(CONNECT_TRY_DELAY);594} catch (InterruptedException ie) {595ie.printStackTrace(log.getOutStream());596throw new Failure("Thread interrupted while pausing connection attempts:\n\t"597+ ie);598}599} catch (IllegalConnectorArgumentsException e) {600e.printStackTrace(log.getOutStream());601throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);602}603}604throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES605+ " tries:\n\t" + ioe);606}607608// -------------------------------------------------- //609610/**611* Prompt to manually launch debugee VM and connect to it using612* <code>AttachingConnector</code>.613*/614private Debugee manualLaunchAndAttachDebugee (VirtualMachineManager vmm,615String classToExecute,616String classPath) {617display("Finding connector: " + argumentHandler.getConnectorName() );618AttachingConnector connector =619(AttachingConnector) findConnector(argumentHandler.getConnectorName(),620vmm.attachingConnectors());621Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupAttachingConnector(connector, classToExecute, classPath);622623String address = makeTransportAddress();624String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");625626display("Starting manual java process:\n\t" + javaCmdLine);627ManualLaunchedDebugee debugee = startManualDebugee(javaCmdLine);628629VirtualMachine vm;630try {631display("Attaching to debugee");632vm = connector.attach(arguments);633} catch (IllegalConnectorArgumentsException e) {634e.printStackTrace(log.getOutStream());635throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e);636} catch (IOException e) {637e.printStackTrace(log.getOutStream());638throw new Failure("Caught exception while attaching to debugee VM:\n\t" + e);639};640display("Debugee attached");641642debugee.setupVM(vm);643return debugee;644}645646/**647* Prompt to manually launch debugee VM and connect to it using648* <code>ListeningConnector</code>.649*/650private Debugee manualLaunchAndListenDebugee (VirtualMachineManager vmm,651String classToExecute,652String classPath) {653display("Finding connector: " + argumentHandler.getConnectorName() );654ListeningConnector connector =655(ListeningConnector) findConnector(argumentHandler.getConnectorName(),656vmm.listeningConnectors());657Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupListeningConnector(connector, classToExecute, classPath);658659VirtualMachine vm;660try {661display("Listening for connection from debugee");662String address = connector.startListening(arguments);663String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");664display("Starting manual java process:\n\t" + javaCmdLine);665ManualLaunchedDebugee debugee = startManualDebugee(javaCmdLine);666display("Waiting for connection from debugee");667vm = connector.accept(arguments);668display("Debugee attached");669connector.stopListening(arguments);670debugee.setupVM(vm);671return debugee;672} catch (IllegalConnectorArgumentsException e) {673e.printStackTrace(log.getOutStream());674throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);675} catch (IOException e) {676e.printStackTrace(log.getOutStream());677throw new Failure("Caught exception while listening to debugee VM:\n\t" + e);678}679}680681// -------------------------------------------------- //682683/**684* Make proper arguments for LaunchingConnector.685*/686private Map<String,? extends Argument> setupLaunchingConnector(LaunchingConnector connector,687String classToExecute,688String classPath) {689display("LaunchingConnector:");690display(" name: " + connector.name());691display(" description: " + connector.description());692display(" transport: " + connector.transport());693694Hashtable<String,? extends Argument> arguments = new Hashtable<String,Argument>(connector.defaultArguments());695696Connector.Argument arg;697698arg = (Connector.StringArgument) arguments.get("quote");699String quote = "\0";700arg.setValue(quote);701702String[] rawArgs = argumentHandler.getRawArguments();703if (Platform.isWindows()) {704// " has to be escaped on windows705rawArgs = Arrays.stream(rawArgs)706.map(s -> s.replace("\"", "\\\""))707.toArray(String[]::new);708}709710String cmdline = classToExecute + " " + ArgumentHandler.joinArguments(rawArgs, quote);711712arg = (Connector.StringArgument) arguments.get("main");713arg.setValue(cmdline);714715if (! argumentHandler.willDebugeeSuspended()) {716Connector.BooleanArgument barg = (Connector.BooleanArgument) arguments.get("suspend");717barg.setValue(true);718}719720/*721if (! argumentHandler.isJVMDIStrictMode()) {722arg = (Connector.StringArgument) arguments.get("options");723arg.setValue("strict=y");724}725*/726727if (! argumentHandler.isDefaultDebugeeJavaHome()) {728arg = (Connector.StringArgument) arguments.get("home");729arg.setValue(argumentHandler.getDebugeeJavaHome());730}731732if (! argumentHandler.isDefaultLaunchExecName()) {733arg = (Connector.StringArgument) arguments.get("vmexec");734arg.setValue(argumentHandler.getLaunchExecName());735}736737String vmArgs = "";738739String vmUserArgs = argumentHandler.getLaunchOptions();740741if (vmUserArgs != null) {742vmArgs = vmUserArgs;743}744745/*746if (classPath != null) {747vmArgs += " -classpath " + quote + classPath + quote;748}749*/750751if (vmArgs.length() > 0) {752arg = (Connector.StringArgument) arguments.get("options");753arg.setValue(vmArgs);754}755756display("Connector arguments:");757Iterator iterator = arguments.values().iterator();758while (iterator.hasNext()) {759display(" " + iterator.next());760}761return arguments;762}763764/**765* Make proper arguments for RawLaunchingConnector.766*/767private Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> setupRawLaunchingConnector(LaunchingConnector connector,768String classToExecute,769String classPath) {770display("RawLaunchingConnector:");771display(" name: " + connector.name());772display(" description: " + connector.description());773display(" transport: " + connector.transport());774775Hashtable<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = new Hashtable<java.lang.String, com.sun.jdi.connect.Connector.Argument>(connector.defaultArguments());776777String connectorAddress;778String vmAddress;779780if (argumentHandler.isSocketTransport()) {781connectorAddress = argumentHandler.getTransportPort();782vmAddress = argumentHandler.getDebugeeHost()783+ ":" + argumentHandler.getTransportPort();784} else if (argumentHandler.isShmemTransport() ) {785connectorAddress = argumentHandler.getTransportSharedName();786vmAddress=connectorAddress;787} else {788throw new TestBug("Undefined transport type for AttachingConnector");789}790791Connector.Argument arg;792793arg = (Connector.StringArgument) arguments.get("quote");794String quote = arg.value();795796String javaCmdLine = makeCommandLineString(classToExecute, quote);797798arg = (Connector.StringArgument) arguments.get("command");799arg.setValue(javaCmdLine);800801arg = (Connector.StringArgument) arguments.get("address");802arg.setValue(connectorAddress);803804display("Connector arguments:");805Iterator iterator = arguments.values().iterator();806while (iterator.hasNext()) {807display(" " + iterator.next());808}809return arguments;810}811812/**813* Make proper arguments for AttachingConnector.814*/815private Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> setupAttachingConnector(AttachingConnector connector,816String classToExecute,817String classPath) {818display("AttachingConnector:");819display(" name: " + connector.name());820display(" description: " + connector.description());821display(" transport: " + connector.transport());822823Hashtable<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = new Hashtable<java.lang.String,com.sun.jdi.connect.Connector.Argument>(connector.defaultArguments());824825Connector.Argument arg;826if (argumentHandler.isSocketTransport()) {827arg = (Connector.StringArgument) arguments.get("hostname");828arg.setValue(argumentHandler.getDebugeeHost());829Connector.IntegerArgument iarg = (Connector.IntegerArgument) arguments.get("port");830iarg.setValue(argumentHandler.getTransportPortNumber());831} else {832arg = (Connector.StringArgument) arguments.get("name");833arg.setValue(argumentHandler.getTransportSharedName());834}835836display("Connector arguments:");837Iterator iterator = arguments.values().iterator();838while (iterator.hasNext()) {839display(" " + iterator.next());840}841return arguments;842}843844/**845* Make proper arguments for ListeningConnector.846*/847private Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> setupListeningConnector(ListeningConnector connector,848String classToExecute,849String classPath) {850display("ListeningConnector:");851display(" name: " + connector.name());852display(" description: " + connector.description());853display(" transport: " + connector.transport());854855Hashtable<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = new Hashtable<java.lang.String,com.sun.jdi.connect.Connector.Argument>(connector.defaultArguments());856857Connector.Argument arg;858if (argumentHandler.isSocketTransport()) {859if (!argumentHandler.isTransportAddressDynamic()) {860int port = argumentHandler.getTransportPortNumber();861Connector.IntegerArgument iarg = (Connector.IntegerArgument) arguments.get("port");862iarg.setValue(port);863}864} else {865String sharedName = argumentHandler.getTransportSharedName();866arg = (Connector.StringArgument) arguments.get("name");867arg.setValue(sharedName);868}869870display("Connector arguments:");871Iterator iterator = arguments.values().iterator();872while (iterator.hasNext()) {873display(" " + iterator.next());874}875return arguments;876}877878// -------------------------------------------------- //879880/**881* Find connector by name from given connectors list.882*/883private Connector findConnector(String connectorName, List connectors) {884Iterator iter = connectors.iterator();885886while (iter.hasNext()) {887Connector connector = (Connector) iter.next();888if (connector.name().equals(connectorName)) {889return connector;890}891}892throw new Failure("JDI connector not found: " + connectorName);893}894895// -------------------------------------------------- //896897/**898* Launch local debuggee process with specified command line arguments899* and make initial <code>Debugee</code> mirror.900*/901protected Debugee startLocalDebugee(String[] cmdArgs) {902Process process = null;903904try {905process = launchProcess(cmdArgs);906} catch (IOException e) {907e.printStackTrace(log.getOutStream());908throw new Failure("Caught exception while launching local debuggee VM process:\n\t"909+ e);910}911912return makeLocalDebugee(process);913}914915/**916* Launch remote debuggee process with specified command line arguments917* and make initial <code>Debugee</code> mirror.918*/919protected RemoteLaunchedDebugee startRemoteDebugee(String[] cmdArgs) {920try {921launchRemoteProcess(cmdArgs);922} catch (IOException e) {923e.printStackTrace(log.getOutStream());924throw new Failure("Caught exception while launching remote debuggee VM process:\n\t"925+ e);926}927928RemoteLaunchedDebugee debugee = new RemoteLaunchedDebugee(this);929930Finalizer finalizer = new Finalizer(debugee);931finalizer.activate();932933return debugee;934}935936/**937* Launch manual debuggee process with specified command line arguments938* and make initial <code>Debugee</code> mirror.939*/940protected ManualLaunchedDebugee startManualDebugee(String cmd) {941ManualLaunchedDebugee debugee = new ManualLaunchedDebugee(this);942debugee.launchDebugee(cmd);943944Finalizer finalizer = new Finalizer(debugee);945finalizer.activate();946947return debugee;948}949950public static String readVMStartExceptionOutput(VMStartException e, PrintStream log) {951StringBuffer msg = new StringBuffer();952try (InputStream is = e.process().getInputStream()) {953msg.append("\tstdout: ").append(new String(readAllBytes(is))).append('\n');954} catch (IOException e1) {955log.println("Could not read normal output from launched process:" + e1);956}957try (InputStream is = e.process().getErrorStream()) {958msg.append("\tstderr: ").append(new String(readAllBytes(is)));959} catch (IOException e1) {960log.println("Could not read error output from launched process:" + e1);961}962return msg.toString();963}964965/**966* Copied from the JDK 9 implementation in InputStream.java967*/968private static byte[] readAllBytes(InputStream is) throws IOException {969final int DEFAULT_BUFFER_SIZE = 8192;970final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;971972byte[] buf = new byte[DEFAULT_BUFFER_SIZE];973int capacity = buf.length;974int nread = 0;975int n;976for (;;) {977// read to EOF which may read more or less than initial buffer size978while ((n = is.read(buf, nread, capacity - nread)) > 0)979nread += n;980981// if the last call to read returned -1, then we're done982if (n < 0)983break;984985// need to allocate a larger buffer986if (capacity <= MAX_BUFFER_SIZE - capacity) {987capacity = capacity << 1;988} else {989if (capacity == MAX_BUFFER_SIZE)990throw new OutOfMemoryError("Required array size too large");991capacity = MAX_BUFFER_SIZE;992}993buf = Arrays.copyOf(buf, capacity);994}995return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);996}997998}99910001001/**1002* Mirror of locally launched debugee.1003*/1004final class LocalLaunchedDebugee extends Debugee {10051006/** Enwrap the locally started VM process. */1007public LocalLaunchedDebugee (Process process, Binder binder) {1008super(binder);1009this.process = process;1010checkTermination = true;1011}10121013// ---------------------------------------------- //10141015/** Return exit status of the debugee VM. */1016public int getStatus () {1017return process.exitValue();1018}10191020/** Check whether the debugee VM has been terminated. */1021public boolean terminated () {1022if (process == null)1023return true;10241025try {1026int value = process.exitValue();1027return true;1028} catch (IllegalThreadStateException e) {1029return false;1030}1031}10321033// ---------------------------------------------- //10341035/** Kill the debugee VM. */1036protected void killDebugee () {1037super.killDebugee();1038if (!terminated()) {1039log.display("Killing debugee VM process");1040process.destroy();1041}1042}10431044/** Wait until the debugee VM shutdown or crash. */1045protected int waitForDebugee () throws InterruptedException {1046int code = process.waitFor();1047return code;1048}10491050/** Get a pipe to write to the debugee's stdin stream. */1051protected OutputStream getInPipe () {1052return process.getOutputStream();1053}10541055/** Get a pipe to read the debugee's stdout stream. */1056protected InputStream getOutPipe () {1057return process.getInputStream();1058}10591060/** Get a pipe to read the debugee's stderr stream. */1061protected InputStream getErrPipe () {1062return process.getErrorStream();1063}1064}106510661067/**1068* Mirror of remotely launched debugee.1069*/1070final class RemoteLaunchedDebugee extends Debugee {10711072/** Enwrap the remotely started VM process. */1073public RemoteLaunchedDebugee (Binder binder) {1074super(binder);1075}10761077// ---------------------------------------------- //10781079/** Return exit status of the debugee VM. */1080public int getStatus () {1081return binder.getRemoteProcessStatus();1082}10831084/** Check whether the debugee VM has been terminated. */1085public boolean terminated () {1086return binder.isRemoteProcessTerminated();1087}10881089// ---------------------------------------------- //10901091/** Kill the debugee VM. */1092protected void killDebugee () {1093super.killDebugee();1094if (!terminated()) {1095binder.killRemoteProcess();1096}1097}10981099/** Wait until the debugee VM shutdown or crash. */1100protected int waitForDebugee () {1101return binder.waitForRemoteProcess();1102}11031104/** Get a pipe to write to the debugee's stdin stream. */1105protected OutputStream getInPipe () {1106return null;1107}11081109/** Get a pipe to read the debugee's stdout stream. */1110protected InputStream getOutPipe () {1111return null;1112}11131114/** Get a pipe to read the debugee's stderr stream. */1115protected InputStream getErrPipe () {1116return null;1117}11181119public void redirectStdout(OutputStream out) {1120}11211122public void redirectStdout(Log log, String prefix) {1123}11241125public void redirectStderr(OutputStream out) {1126}11271128public void redirectStderr(Log log, String prefix) {1129}1130}113111321133/**1134* Mirror of manually launched debugee.1135*/1136final class ManualLaunchedDebugee extends Debugee {1137/** Enwrap the manually started VM process. */1138public ManualLaunchedDebugee (Binder binder) {1139super(binder);1140makeInputReader();1141}11421143// ---------------------------------------------- //11441145private int exitCode = 0;1146private boolean finished = false;1147private static BufferedReader bin = null;11481149public void launchDebugee(String commandLine) {1150makeInputReader();11511152putMessage("Launch target VM using such command line:\n"1153+ commandLine);1154String answer = askQuestion("Has the VM successfully started? (yes/no)", "yes");1155for ( ; ; ) {1156if (answer.equals("yes"))1157break;1158if (answer.equals("no"))1159throw new Failure ("Unable to manually launch debugee VM");1160answer = askQuestion("Wrong answer. Please type yes or no", "yes");1161}1162}11631164private static void makeInputReader() {1165if (bin == null) {1166bin = new BufferedReader(new InputStreamReader(System.in));1167}1168}11691170private static void destroyInputReader() {1171if (bin != null) {1172try {1173bin.close();1174} catch (IOException e) {1175// e.printStackTrace(log.getOutStream());1176throw new Failure("Caught exception while closing input stream:\n\t" + e);1177}1178bin = null;1179}1180}11811182private static void putMessage(String msg) {1183System.out.println("\n>>> " + msg);1184}11851186private static String askQuestion(String question, String defaultAnswer) {1187try {1188System.out.print("\n>>> " + question);1189System.out.print(" [" + defaultAnswer + "] ");1190System.out.flush();1191String answer = bin.readLine();1192if (answer.equals(""))1193return defaultAnswer;1194return answer;1195} catch (IOException e) {1196// e.printStackTrace(log.getOutStream());1197throw new Failure("Caught exception while reading answer:\n\t" + e);1198}1199}12001201/** Return exit status of the debugee VM. */1202public int getStatus () {1203if (! finished) {1204throw new Failure("Unable to get status of debugee VM: process still alive");1205}1206return exitCode;1207}12081209/** Check whether the debugee VM has been terminated. */1210public boolean terminated () {1211return finished;1212}12131214// ---------------------------------------------- //12151216/** Kill the debugee VM. */1217protected void killDebugee () {1218super.killDebugee();1219if (!terminated()) {1220putMessage("Kill launched VM");1221String answer = askQuestion("Has the VM successfully terminated? (yes/no)", "yes");1222for ( ; ; ) {1223if (answer.equals("yes")) {1224finished = true;1225break;1226}1227if (answer.equals("no"))1228throw new Failure ("Unable to manually kill debugee VM");1229answer = askQuestion("Wrong answer. Please type yes or no", "yes");1230}1231}1232}12331234/** Wait until the debugee VM shutdown or crash. */1235protected int waitForDebugee () {1236putMessage("Wait for launched VM to exit.");1237String answer = askQuestion("What is VM exit code?", "95");1238for ( ; ; ) {1239try {1240exitCode = Integer.parseInt(answer);1241break;1242} catch (NumberFormatException e) {1243answer = askQuestion("Wrong answer. Please type integer value", "95");1244}1245}1246finished = true;1247return exitCode;1248}12491250/** Get a pipe to write to the debugee's stdin stream. */1251protected OutputStream getInPipe () {1252return null;1253}12541255/** Get a pipe to read the debugee's stdout stream. */1256protected InputStream getOutPipe () {1257return null;1258}12591260/** Get a pipe to read the debugee's stderr stream. */1261protected InputStream getErrPipe () {1262return null;1263}12641265public void redirectStdout(OutputStream out) {1266}12671268public void redirectStdout(Log log, String prefix) {1269}12701271public void redirectStderr(OutputStream out) {1272}12731274public void redirectStderr(Log log, String prefix) {1275}12761277public void close() {1278destroyInputReader();1279super.close();1280}1281}128212831284