/* * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package nsk.share.jdi; import nsk.share.*; import nsk.share.jpda.*; import com.sun.jdi.VirtualMachine; /** * Parser for JDI test's specific command-line arguments. *

* ArgumentHandler handles JDI test's specific * arguments related to launching debugee VM using JDI features * in addition to general arguments recognized by * DebugeeArgumentHandler and ArgumentParser. *

* Following is the list of specific options recognized by * AgrumentHandler: *

*

* See also list of arguments recognized by the base DebugeeArgumentHandler * and ArgumentParser classes. *

* See also description of ArgumentParser how to work with * command line arguments and options. * * @see ArgumentParser * @see DebugeeArgumentHandler */ public class ArgumentHandler extends DebugeeArgumentHandler { static private String JDI_CONNECTOR_NAME_PREFIX = "com.sun.jdi."; /** * Keep a copy of raw command-line arguments and parse them; * but throw an exception on parsing error. * * @param args Array of the raw command-line arguments. * * @throws NullPointerException If args==null. * @throws IllegalArgumentException If Binder or Log options * are set incorrectly. * * @see #setRawArguments(String[]) */ public ArgumentHandler(String args[]) { super(args); // parseArguments(); } /** * Overriden method returns transport type for JDWP connection, specified by * -transport command line option, or "default" value * by default. * * @see #getTransportName() * @see #isSocketTransport() * @see #isShmemTransport() * @see #isDefaultTransport() * @see #setRawArguments(String[]) */ public String getTransportType() { return options.getProperty("transport", "default"); } /** * Overriden method returns true if socket transport * is used either as specified or as a platform default transport. * * @see #getTransportType() */ public boolean isSocketTransport() { String transport = getTransportType(); if (transport.equals("socket")) return true; if (transport.equals("shmem")) return false; if (transport.equals("default")) { String arch = getArch(); if (arch == null) if (System.getProperty("os.arch").equals("windows-i586")) return false; else return true; else if (arch.equals("windows-i586")) return false; else return true; } throw new TestBug("Bad value of argument transport: " + transport); } /** * Overriden method returns true if shmem transport is used * either as specified or as a platform default transport. * * @see #getTransportType() */ public boolean isShmemTransport() { return ! isSocketTransport(); } /** * Overriden method returns true if transport type is default. * * @see #getTransportType() */ public boolean isDefaultTransport() { String transport = getTransportType(); return transport.equals("default"); } /** * Overriden methos returns JDI connector type, specified by * -connector. or "default" value by default. * * @see #getConnectorName() * @see #isLaunchingConnector() * @see #isAttachingConnector() * @see #isListeningConnector() * @see #isDefaultConnector() * @see #setRawArguments(String[]) */ public String getConnectorType() { return options.getProperty("connector", "default"); } /** * Overriden method returns full connector name corresponding to * the used connector and transport types. * * @see #getConnectorType() * @see #getTransportType() */ public String getConnectorName() { if (isLaunchingConnector()) { if (isRawLaunchingConnector()) return JDI_CONNECTOR_NAME_PREFIX + "RawCommandLineLaunch"; return JDI_CONNECTOR_NAME_PREFIX + "CommandLineLaunch"; } if (isAttachingConnector()) { if (isSocketTransport()) return JDI_CONNECTOR_NAME_PREFIX + "SocketAttach"; if (isShmemTransport()) return JDI_CONNECTOR_NAME_PREFIX + "SharedMemoryAttach"; return JDI_CONNECTOR_NAME_PREFIX + "SocketAttach"; } if (isListeningConnector()) { if (isSocketTransport()) return JDI_CONNECTOR_NAME_PREFIX + "SocketListen"; if (isShmemTransport()) return JDI_CONNECTOR_NAME_PREFIX + "SharedMemoryListen"; return JDI_CONNECTOR_NAME_PREFIX + "SocketListen"; } throw new Failure("Unable to find full name of connector \"" + getConnectorType() + "\" for transport \"" + getTransportType() + "\""); } /** * Overriden method returns true if connector type is default. * * @see #getConnectorType() */ public boolean isDefaultConnector() { return getConnectorType().equals("default"); } /** * Return true if connector type is launching * rawlaunching or default. * * @see #getConnectorType() */ public boolean isLaunchingConnector() { return getConnectorType().equals("launching") || getConnectorType().equals("rawlaunching") || getConnectorType().equals("default"); } /** * Return true if connector type is rawlaunching. * * @see #getConnectorType() */ public boolean isRawLaunchingConnector() { return getConnectorType().equals("rawlaunching"); } /** * Return string representation of debug trace mode, specified by * -jdi.trace command line option, or "none" * value by default. *

* Possible values for this option are the same as symbolic constants names * in com.sun.jdi.VirtualMachine interface: *
  "all", or *
  "events", or *
  "none", or *
  "objrefs", or *
  "receives", or *
  "reftypes", or *
  "sends". * * @see #getTraceMode() * @see #setRawArguments(String[]) */ public String getTraceModeString() { return options.getProperty("jdi.trace", "none"); } /** * Return integer code corresponding to debug trace mode, specified by * -jdi.trace command line option, or VirtualMachine.TRACE_NONE * value by default. *

* Possible values are the same as symbolic constant values * in com.sun.jdi.VirtualMachine interface: *

* * @see #getTraceModeString() * @see #setRawArguments(String[]) */ public int getTraceMode() { String val = getTraceModeString(); if (val == null) return VirtualMachine.TRACE_NONE; if (val.equals("none")) return VirtualMachine.TRACE_NONE; if (val.equals("all")) return VirtualMachine.TRACE_ALL; if (val.equals("events")) return VirtualMachine.TRACE_EVENTS; if (val.equals("objrefs")) return VirtualMachine.TRACE_OBJREFS; if (val.equals("receives")) return VirtualMachine.TRACE_RECEIVES; if (val.equals("reftypes")) return VirtualMachine.TRACE_REFTYPES; if (val.equals("sends")) return VirtualMachine.TRACE_SENDS; throw new TestBug("Unknown JDI trace mode string: " + val); } // delay between connection attempts, used in connectors tests public int getConnectionDelay() { String value = options.getProperty("connectionDelay", "4000"); try { return Integer.parseInt(value); } catch (NumberFormatException e) { throw new TestBug("Not integer value of \"connectionDelay\" argument: " + value); } } /** * Return true if the test should pass in any case i.e. * an entity specified by the arguments entry[] is * not implemented on the tested platform. Name of the tested * platform is resolved from the "-arch" option. * * @param entry Array with the arguments which are specifing * the entity. * * @throws Oddity If test parameter-arch * has not been set. * * @see #setRawArguments(String[]) */ public boolean shouldPass(String entry[]) { String arch; boolean found = false; if ((arch=getArch()) == null) throw new Oddity("Test parameter -arch should be set"); for (int i=0; i < CheckedFeatures.notImplemented.length; i++) { if (CheckedFeatures.notImplemented[i][0].equals(arch) && CheckedFeatures.notImplemented[i].length == (entry.length+1)) { for (int j=1; j < (entry.length+1); j++) { if (CheckedFeatures.notImplemented[i][j].equals(entry[j-1])) found = true; else { found = false; break; } } if (found) return true; // the entry[] is not implemented } } return false; // the entry[] is implemented } /** * Return true if the test should pass in any case i.e. * an entity specified by the argument entry is * not implemented on the tested platform. Name of the tested * platform is resolved from the "-arch" option. * * @param entry String with the argument which is specifing * the entity. * * @throws Oddity If test parameter-arch * has not been set. * * @see #setRawArguments(String[]) */ public boolean shouldPass(String entry) { return (shouldPass(new String[] {entry})); } /** * Return true if the test should pass in any case i.e. * an entity specified by the arguments entry1 and * entry2 is not implemented on the tested platform. * The entry is considered to be not implemented if exact entry * "entry1, entry2" or its main entry "entry1" is not implemented. * * Name of the tested platform is resolved from the "-arch" * option. * * @param entry1 String with the argument 1 which is specifing * the entity. * * @param entry2 String with the argument 2 which is specifing * the entity. * * @throws Oddity If test parameter-arch * has not been set. * * @see #setRawArguments(String[]) */ public boolean shouldPass(String entry1, String entry2) { return ( shouldPass(new String[] {entry1, entry2}) || shouldPass(new String[] {entry1}) ); } /** * Check if an option is admissible and has proper value. * This method is invoked by parseArguments() * * @param option option name * @param value string representation of value (could be an empty string) * null if this option has no value * @return true if option is admissible and has proper value * false if otion is not admissible * * @throws BadOption if option has illegal value * * @see #parseArguments() */ protected boolean checkOption(String option, String value) { // check options with enumerated values if (option.equals("connectionDelay")) { try { int number = Integer.parseInt(value); if (number <= 0) { throw new BadOption(option + ": must be a positive integer"); } } catch (NumberFormatException e) { throw new BadOption(option + ": must be an integer"); } return true; } if (option.equals("connector")) { if ((!value.equals("launching")) && (!value.equals("rawlaunching")) && (!value.equals("attaching")) && (!value.equals("listening")) && (!value.equals("default"))) { throw new BadOption(option + ": value must be one of: " + "launching, attaching, listening, default"); } return true; } if (option.equals("transport")) { if ((!value.equals("socket")) && (!value.equals("shmem")) && (!value.equals("default"))) { throw new BadOption(option + ": must be one of: " + "socket, shmem, default"); } return true; } if (option.equals("jdi.trace")) { if ((!value.equals("all")) && (!value.equals("none")) && (!value.equals("events")) && (!value.equals("receives")) && (!value.equals("sends")) && (!value.equals("reftypes")) && (!value.equals("objrefs"))) { throw new BadOption(option + ": value must be one of: " + "none, all, events, receives, sends, reftypes, objrefs"); } return true; } return super.checkOption(option, value); } /** * Check options against inconcistence. * This method is invoked by parseArguments() * * @see #parseArguments() */ protected void checkOptions() { /* if (isTransportAddressDynamic() && (!isDefaultConnector() && isRawLaunchingConnector())) { throw new BadOption("-transport.address=dynamic should NOT be used with" + " -connector=rawlaunching"); } */ 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()) { throw new BadOption("inconsistent options: " + "-connector=" + getConnectorType() + " and -transport=" + getTransportType()); } if (! isLaunchingConnector() && isDefaultTransport()) { throw new BadOption("inconsistent options: " + "-connector=" + getConnectorType() + " and -transport=" + getTransportType()); } if (! isDefaultJVMDIStrictMode()) { throw new BadOption("unsupported options: " + "jvmdi.strict: non default JVMDI strict mode is not supported now" + getJVMDIStrictMode()); } /* if (! isLaunchedLocally() && ! isDefaultJVMDIStrictMode()) { throw new BadOption("inconsistent options: " + "-launch.mode=" + getLaunchMode() + " and -jvmdi.strict=" + getJVMDIStrictMode()); } */ super.checkOptions(); } } /** * This is an auxiliary class intended for ArgumentHandler. * The following information is used by the ArgumentHandler * for resolving features (i.e., JDI connectors and transport names) * which are not implemented on given platform (the first column). * This list is actual for JDK 1.3.x, 1.4.x, 1.5.0, 1.6.0. * * @see ArgumentHandler */ class CheckedFeatures { static final String[][] notImplemented = { // attaching connectors /* * From docs/technotes/guides/jpda/conninv.html: * " * This connector can be used by a debugger application to attach to * a currently running target VM through the shared memory transport. It is * available only on the Microsoft Windows platform. * " */ {"linux-i586", "com.sun.jdi.SharedMemoryAttach"}, {"linux-ia64", "com.sun.jdi.SharedMemoryAttach"}, {"linux-amd64", "com.sun.jdi.SharedMemoryAttach"}, {"linux-x64", "com.sun.jdi.SharedMemoryAttach"}, {"linux-aarch64", "com.sun.jdi.SharedMemoryAttach"}, {"linux-arm", "com.sun.jdi.SharedMemoryAttach"}, {"linux-ppc64", "com.sun.jdi.SharedMemoryAttach"}, {"linux-ppc64le", "com.sun.jdi.SharedMemoryAttach"}, {"linux-s390x", "com.sun.jdi.SharedMemoryAttach"}, {"macosx-amd64", "com.sun.jdi.SharedMemoryAttach"}, {"mac-x64", "com.sun.jdi.SharedMemoryAttach"}, {"aix-ppc64", "com.sun.jdi.SharedMemoryAttach"}, // listening connectors /* * From docs/technotes/guides/jpda/conninv.html: * " * This connector can be used by a debugger application to accept a * connection from a separately invoked target VM through the shared memory * transport. * It is available only on the Microsoft Windows platform. * " */ {"linux-i586", "com.sun.jdi.SharedMemoryListen"}, {"linux-ia64", "com.sun.jdi.SharedMemoryListen"}, {"linux-amd64", "com.sun.jdi.SharedMemoryListen"}, {"linux-x64", "com.sun.jdi.SharedMemoryListen"}, {"linux-aarch64", "com.sun.jdi.SharedMemoryListen"}, {"linux-arm", "com.sun.jdi.SharedMemoryListen"}, {"linux-ppc64", "com.sun.jdi.SharedMemoryListen"}, {"linux-ppc64le", "com.sun.jdi.SharedMemoryListen"}, {"linux-s390x", "com.sun.jdi.SharedMemoryListen"}, {"macosx-amd64", "com.sun.jdi.SharedMemoryListen"}, {"mac-x64", "com.sun.jdi.SharedMemoryListen"}, {"aix-ppc64", "com.sun.jdi.SharedMemoryListen"}, // launching connectors /* * From docs/technotes/guides/jpda/conninv.html: * " * Sun Command Line Launching Connector * This connector can be used by a debugger application to launch a * Sun VM or any other VM which supports the same invocation options with * respect to debugging. The details of launching the VM and specifying the * necessary debug options are handled by the connector. The underlying * transport used by this connector depends on the platform. On Microsoft * Windows, the shared memory transport is used. On Linux the socket transport is used. * " */ {"linux-i586", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"linux-i586", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"linux-ia64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"linux-ia64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"linux-amd64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"linux-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"linux-x64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"linux-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"linux-aarch64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"linux-aarch64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"linux-arm", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"linux-arm", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"linux-ppc64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"linux-ppc64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"linux-ppc64le", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"linux-ppc64le", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"linux-s390x", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"linux-s390x", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"windows-i586", "com.sun.jdi.CommandLineLaunch", "dt_socket"}, {"windows-i586", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"}, {"windows-ia64", "com.sun.jdi.CommandLineLaunch", "dt_socket"}, {"windows-ia64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"}, {"windows-amd64", "com.sun.jdi.CommandLineLaunch", "dt_socket"}, {"windows-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"}, {"windows-x64", "com.sun.jdi.CommandLineLaunch", "dt_socket"}, {"windows-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"}, {"macosx-amd64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"macosx-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"mac-x64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"mac-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, {"aix-ppc64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, {"aix-ppc64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, // shared memory transport is implemented only on windows platform {"linux-i586", "dt_shmem"}, {"linux-ia64", "dt_shmem"}, {"linux-amd64", "dt_shmem"}, {"linux-x64", "dt_shmem"}, {"linux-aarch64", "dt_shmem"}, {"linux-arm", "dt_shmem"}, {"linux-ppc64", "dt_shmem"}, {"linux-ppc64le", "dt_shmem"}, {"linux-s390x", "dt_shmem"}, {"macosx-amd64", "dt_shmem"}, {"mac-x64", "dt_shmem"}, {"aix-ppc64", "dt_shmem"}, }; }