changeset 40891:8010999ff6d0

8148103: add more tests for task "Update JDI and JDWP for modules" Summary: A new JDWP test Reviewed-by: sspitsyn
author akulyakh
date Tue, 30 Aug 2016 12:48:03 +0300
parents 6ac37e8b717a
children 330a02d935ad
files hotspot/test/serviceability/jdwp/AllModulesCommandTest.java hotspot/test/serviceability/jdwp/AllModulesCommandTestDebuggee.java hotspot/test/serviceability/jdwp/DebuggeeLauncher.java hotspot/test/serviceability/jdwp/JdwpAllModulesCmd.java hotspot/test/serviceability/jdwp/JdwpAllModulesReply.java hotspot/test/serviceability/jdwp/JdwpCanReadCmd.java hotspot/test/serviceability/jdwp/JdwpCanReadReply.java hotspot/test/serviceability/jdwp/JdwpChannel.java hotspot/test/serviceability/jdwp/JdwpClassLoaderCmd.java hotspot/test/serviceability/jdwp/JdwpClassLoaderReply.java hotspot/test/serviceability/jdwp/JdwpCmd.java hotspot/test/serviceability/jdwp/JdwpExitCmd.java hotspot/test/serviceability/jdwp/JdwpModNameCmd.java hotspot/test/serviceability/jdwp/JdwpModNameReply.java hotspot/test/serviceability/jdwp/JdwpReply.java hotspot/test/serviceability/jdwp/StreamHandler.java
diffstat 16 files changed, 1045 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.Set;
+import java.util.HashSet;
+import static jdk.test.lib.Asserts.assertTrue;
+
+/**
+ * @test
+ * @summary Tests AllModules JDWP command
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @compile AllModulesCommandTestDebuggee.java
+ * @run main/othervm AllModulesCommandTest
+ */
+public class AllModulesCommandTest implements DebuggeeLauncher.Listener {
+
+    private DebuggeeLauncher launcher;
+    private JdwpChannel channel;
+    private CountDownLatch jdwpLatch = new CountDownLatch(1);
+    private Set<String> jdwpModuleNames = new HashSet<>();
+    private Set<String> javaModuleNames = new HashSet<>();
+
+    public static void main(String[] args) throws Throwable {
+        new AllModulesCommandTest().doTest();
+    }
+
+    private void doTest() throws Throwable {
+        launcher = new DebuggeeLauncher(this);
+        launcher.launchDebuggee();
+        // Await till the debuggee sends all the necessary modules info to check against
+        // then start the JDWP session
+        jdwpLatch.await();
+        doJdwp();
+    }
+
+    @Override
+    public void onDebuggeeModuleInfo(String modName) {
+        // The debuggee has sent out info about a loaded module
+        javaModuleNames.add(modName);
+    }
+
+    @Override
+    public void onDebuggeeSendingCompleted() {
+        // The debuggee has completed sending all the info
+        // We can start the JDWP session
+        jdwpLatch.countDown();
+    }
+
+    @Override
+    public void onDebuggeeError(String message) {
+        System.err.println("Debuggee error: '" + message + "'");
+        System.exit(1);
+    }
+
+    private void doJdwp() throws Exception {
+        try {
+            // Establish JDWP socket connection
+            channel = new JdwpChannel();
+            channel.connect();
+            // Send out ALLMODULES JDWP command
+            // and verify the reply
+            JdwpAllModulesReply reply = new JdwpAllModulesCmd().send(channel);
+            assertReply(reply);
+            for (int i = 0; i < reply.getModulesCount(); ++i) {
+                long modId = reply.getModuleId(i);
+                // For each module reported by JDWP get its name using the JDWP  NAME command
+                getModuleName(modId);
+                // Assert the JDWP CANREAD and CLASSLOADER commands
+                assertCanRead(modId);
+                assertClassLoader(modId);
+            }
+
+            System.out.println("Module names reported by JDWP: " + Arrays.toString(jdwpModuleNames.toArray()));
+            System.out.println("Module names reported by Java: " + Arrays.toString(javaModuleNames.toArray()));
+
+            // Modules reported by the JDWP should be the same as reported by the Java API
+            if (!jdwpModuleNames.equals(javaModuleNames)) {
+                throw new RuntimeException("Modules info reported by Java API differs from that reported by JDWP.");
+            } else {
+                System.out.println("Test passed!");
+            }
+
+        } finally {
+            launcher.terminateDebuggee();
+            try {
+                new JdwpExitCmd(0).send(channel);
+                channel.disconnect();
+            } catch (Exception x) {
+            }
+        }
+    }
+
+    private void getModuleName(long modId) throws IOException {
+        // Send out the JDWP NAME command and store the reply
+        JdwpModNameReply reply = new JdwpModNameCmd(modId).send(channel);
+        assertReply(reply);
+        String modName = reply.getModuleName();
+        if (modName != null) { // JDWP reports unnamed modules, ignore them
+            jdwpModuleNames.add(modName);
+        }
+    }
+
+    private void assertReply(JdwpReply reply) {
+        // Simple assert for any JDWP reply
+        if (reply.getErrorCode() != 0) {
+            throw new RuntimeException("Unexpected reply error code " + reply.getErrorCode() + " for reply " + reply);
+        }
+    }
+
+    private void assertCanRead(long modId) throws IOException {
+        // Simple assert for the CANREAD command
+        JdwpCanReadReply reply = new JdwpCanReadCmd(modId, modId).send(channel);
+        assertReply(reply);
+        assertTrue(reply.canRead(), "canRead() reports false for reading from the same module");
+    }
+
+    private void assertClassLoader(long modId) throws IOException {
+        // Simple assert for the CLASSLOADER command
+        JdwpClassLoaderReply reply = new JdwpClassLoaderCmd(modId).send(channel);
+        assertReply(reply);
+        long clId = reply.getClassLoaderId();
+        assertTrue(clId >= 0, "bad classloader refId " + clId + " for module id " + modId);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/AllModulesCommandTestDebuggee.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.lang.reflect.Module;
+import java.lang.reflect.Layer;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * The debuggee to be launched by the test
+ * Sends out the info about the loaded modules
+ * then stays to respond to the JDWP commands
+ */
+public class AllModulesCommandTestDebuggee {
+
+    public static void main(String[] args) throws InterruptedException {
+
+        int modCount = Layer.boot().modules().size();
+
+        // Send all modules names via the process output
+        for (Module mod : Layer.boot().modules()) {
+            String info = String.format("module %s", mod.getName());
+            write(info);
+        }
+        // Signal that the sending is done
+        write("ready");
+        Thread.sleep(Long.MAX_VALUE);
+    }
+
+    private static void write(String s) {
+        System.out.println(s);
+        System.out.flush();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/DebuggeeLauncher.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.StringTokenizer;
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.Utils;
+import static jdk.test.lib.Asserts.assertFalse;
+
+/**
+ * Launches the debuggee with the necessary JDWP options and handles the output
+ */
+public class DebuggeeLauncher implements StreamHandler.Listener {
+
+    public interface Listener {
+
+        /**
+         * Callback to use when a module name is received from the debuggee
+         *
+         * @param modName module name reported by the debuggee
+         */
+        void onDebuggeeModuleInfo(String modName);
+
+        /**
+         * Callback to use when the debuggee completes sending out the info
+         */
+        void onDebuggeeSendingCompleted();
+
+        /**
+         * Callback to handle any debuggee error
+         *
+         * @param line line from the debuggee's stderr
+         */
+        void onDebuggeeError(String line);
+    }
+
+    private static int jdwpPort = -1;
+    private static final String CLS_DIR = System.getProperty("test.classes", "").trim();
+    private static final String DEBUGGEE = "AllModulesCommandTestDebuggee";
+    private Process p;
+    private final Listener listener;
+    private StreamHandler inputHandler;
+    private StreamHandler errorHandler;
+
+    /**
+     * @param listener the listener we report the debuggee events to
+     */
+    public DebuggeeLauncher(Listener listener) {
+        this.listener = listener;
+    }
+
+    /**
+     * Starts the debuggee with the necessary JDWP options and handles the
+     * debuggee's stdout and stderr outputs
+     *
+     * @throws Throwable
+     */
+    public void launchDebuggee() throws Throwable {
+
+        ProcessBuilder pb = new ProcessBuilder(getCommand());
+        p = pb.start();
+        inputHandler = new StreamHandler(p.getInputStream(), this);
+        errorHandler = new StreamHandler(p.getErrorStream(), this);
+        inputHandler.start();
+        errorHandler.start();
+    }
+
+    /**
+     * Command to start the debuggee with the JDWP options and using the JDK
+     * under test
+     *
+     * @return the command
+     */
+    private String[] getCommand() {
+        return new String[]{
+            JDKToolFinder.getTestJDKTool("java"),
+            getJdwpOptions(),
+            "-cp",
+            CLS_DIR,
+            DEBUGGEE
+        };
+    }
+
+    /**
+     * Terminates the debuggee
+     */
+    public void terminateDebuggee() {
+        if (p.isAlive()) {
+            p.destroyForcibly();
+        }
+    }
+
+    /**
+     * Debuggee JDWP options
+     *
+     * @return the JDWP options to start the debuggee with
+     */
+    private static String getJdwpOptions() {
+        return "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=" + getJdwpPort();
+    }
+
+    /**
+     * Find an available port for the JDWP session
+     *
+     * @return JDWP port
+     */
+    public static int getJdwpPort() {
+        if (jdwpPort == -1) {
+            jdwpPort = findFreePort();
+            assertFalse(jdwpPort == -1, "Can not find vailbale port for JDWP");
+        }
+        return jdwpPort;
+    }
+
+    private static int findFreePort() {
+        try (ServerSocket socket = new ServerSocket(0)) {
+            return socket.getLocalPort();
+        } catch (IOException e) {
+        }
+        return -1;
+    }
+
+    @Override
+    public void onStringRead(StreamHandler handler, String line) {
+        if (handler.equals(errorHandler)) {
+            terminateDebuggee();
+            listener.onDebuggeeError(line);
+        } else {
+            processDebuggeeOutput(line);
+        }
+    }
+
+    private void processDebuggeeOutput(String line) {
+        StringTokenizer st = new StringTokenizer(line);
+        String token = st.nextToken();
+        switch (token) {
+            case "module":
+                listener.onDebuggeeModuleInfo(st.nextToken());
+                break;
+            case "ready":
+                listener.onDebuggeeSendingCompleted();
+                break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpAllModulesCmd.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/**
+ * The JDWP ALLMODULES command
+ */
+public class JdwpAllModulesCmd extends JdwpCmd<JdwpAllModulesReply> {
+
+    public JdwpAllModulesCmd() {
+        super(22, 1, JdwpAllModulesReply.class, 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpAllModulesReply.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * The JDWP reply to the ALLMODULES command
+ */
+public class JdwpAllModulesReply extends JdwpReply {
+
+    private int modulesCount;
+    private long[] modulesId;
+
+    protected void parseData(DataInputStream ds) throws IOException {
+        modulesCount = ds.readInt();
+        modulesId = new long[modulesCount];
+        for (int nmod = 0; nmod < modulesCount; ++nmod) {
+            modulesId[nmod] = readRefId(ds);
+        }
+    }
+
+    /**
+     * Number of modules reported
+     *
+     * @return modules count
+     */
+    public int getModulesCount() {
+        return modulesCount;
+    }
+
+    /**
+     * The id of a module reported
+     *
+     * @param ndx module index in the array of the reported ids
+     * @return module id
+     */
+    public long getModuleId(int ndx) {
+        return modulesId[ndx];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpCanReadCmd.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/**
+ * The JDWP CANREAD command
+ */
+public class JdwpCanReadCmd extends JdwpCmd<JdwpCanReadReply> {
+
+    public JdwpCanReadCmd(long modId, long srcModId) {
+        super(3, 18, JdwpCanReadReply.class, 2 * refLen());
+        putRefId(modId);
+        putRefId(srcModId);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpCanReadReply.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * The reply to the JDWP CANREAD command
+ */
+public class JdwpCanReadReply extends JdwpReply {
+
+    private boolean canRead;
+
+    protected void parseData(DataInputStream ds) throws IOException {
+        canRead = ds.read() == 1;
+    }
+
+    public boolean canRead() {
+        return canRead;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpChannel.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.util.Arrays;
+
+/**
+ * JDWP socket transport
+ */
+public class JdwpChannel {
+
+    private Socket sock;
+
+    public void connect() throws IOException {
+        sock = new Socket("localhost", DebuggeeLauncher.getJdwpPort());
+        handshake();
+    }
+
+    /**
+     * Sends JDWP handshake and verifies the reply
+     * @throws IOException
+     */
+    private void handshake() throws IOException {
+        final byte[] HANDSHAKE = "JDWP-Handshake".getBytes();
+        sock.getOutputStream().write(HANDSHAKE, 0, HANDSHAKE.length);
+
+        byte[] reply = new byte[14];
+        sock.getInputStream().read(reply, 0, 14);
+        if (!Arrays.equals(HANDSHAKE, reply)) {
+            throw new RuntimeException("Error during handshake. Reply was: " + new String(reply) + " expected " + new String(HANDSHAKE));
+        }
+    }
+
+    public void disconnect() {
+        try {
+            sock.close();
+        } catch (IOException x) {
+        }
+    }
+
+    public void write(byte[] data, int length) throws IOException {
+        sock.getOutputStream().write(data, 0, length);
+    }
+
+    public InputStream getInputStream() throws IOException {
+        return sock.getInputStream();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpClassLoaderCmd.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/**
+ * The JDWP CLASSLOADER command
+ */
+public class JdwpClassLoaderCmd extends JdwpCmd<JdwpClassLoaderReply> {
+
+    public JdwpClassLoaderCmd(long modId) {
+        super(2, 18, JdwpClassLoaderReply.class, refLen());
+        putRefId(modId);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpClassLoaderReply.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * The JDWP CLASSLOADER reply
+ */
+public class JdwpClassLoaderReply extends JdwpReply {
+
+    private long refId;
+
+    protected void parseData(DataInputStream ds) throws IOException {
+        refId = readRefId(ds);
+    }
+
+    public long getClassLoaderId() {
+        return refId;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpCmd.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Generic JDWP command
+ * @param <T> the corresponding JDWP reply class, to construct a reply object
+ */
+public abstract class JdwpCmd<T extends JdwpReply> {
+
+    private ByteBuffer data;
+    private static int id = 1;
+    private final byte FLAGS = 0;
+    private T reply;
+    private final int dataLen;
+    private final int HEADER_LEN = 11;
+
+    /**
+     * JDWWp command
+     * @param cmd command code
+     * @param cmdSet command set
+     * @param replyClz command reply class
+     * @param dataLen length of additional data for the command
+     */
+    JdwpCmd(int cmd, int cmdSet, Class<T> replyClz, int dataLen) {
+        this.dataLen = dataLen;
+        data = ByteBuffer.allocate(HEADER_LEN + dataLen);
+        data.putInt(HEADER_LEN + dataLen);
+        data.putInt(id++);
+        data.put(FLAGS);
+        data.put((byte) cmdSet);
+        data.put((byte) cmd);
+        if (replyClz != null) {
+            try {
+                reply = replyClz.newInstance();
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    JdwpCmd(int cmd, int cmdSet, Class<T> replyClz) {
+        this(cmd, cmdSet, replyClz, 0);
+    }
+
+    int getDataLength() {
+        return dataLen;
+    }
+
+    public final T send(JdwpChannel channel) throws IOException {
+        System.err.println("Sending command: " + this);
+        channel.write(data.array(), HEADER_LEN + getDataLength());
+        if (reply != null) {
+            reply.initFromStream(channel.getInputStream());
+        }
+        return (T) reply;
+    }
+
+    protected void putRefId(long refId) {
+        data.putLong(refId);
+    }
+
+    protected void putInt(int val) {
+        data.putInt(val);
+    }
+
+    protected static int refLen() {
+        return 8;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpExitCmd.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/**
+ * The JDWP EXIT command to terminate the debuggee
+ */
+public class JdwpExitCmd extends JdwpCmd {
+
+    public JdwpExitCmd(int exitCode) {
+        super(10, 1, null, 4);
+        putInt(exitCode);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpModNameCmd.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/**
+ * The JDWP NAME command
+ */
+public class JdwpModNameCmd extends JdwpCmd<JdwpModNameReply> {
+
+    public JdwpModNameCmd(long modId) {
+        super(1, 18, JdwpModNameReply.class, refLen());
+        putRefId(modId);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpModNameReply.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * JDWP reply to the NAME command
+ */
+public class JdwpModNameReply extends JdwpReply {
+
+    private byte[] name;
+
+    protected void parseData(DataInputStream ds) throws IOException {
+        name = readJdwpString(ds);
+    }
+
+    public String getModuleName() {
+        return name == null ? null : new String(name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/JdwpReply.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Generic JDWP reply
+ */
+public abstract class JdwpReply {
+
+    protected final static int HEADER_LEN = 11;
+    private byte[] errCode = new byte[2];
+    private byte[] data;
+
+    public final void initFromStream(InputStream is) throws IOException {
+        DataInputStream ds = new DataInputStream(is);
+
+        int length = ds.readInt();
+        int id = ds.readInt();
+        byte flags = (byte) ds.read();
+
+        ds.read(errCode, 0, 2);
+
+        int dataLength = length - HEADER_LEN;
+        if (dataLength > 0) {
+            data = new byte[dataLength];
+            ds.read(data, 0, dataLength);
+            parseData(new DataInputStream(new ByteArrayInputStream(data)));
+        }
+    }
+
+    protected void parseData(DataInputStream ds) throws IOException {
+    }
+
+    protected byte[] readJdwpString(DataInputStream ds) throws IOException {
+        byte[] str = null;
+        int len = ds.readInt();
+        if (len > 0) {
+            str = new byte[len];
+            ds.read(str, 0, len);
+        }
+        return str;
+    }
+
+    protected long readRefId(DataInputStream ds) throws IOException {
+        return ds.readLong();
+    }
+
+    public int getErrorCode() {
+        return (((errCode[0] & 0xFF) << 8) | (errCode[1] & 0xFF));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jdwp/StreamHandler.java	Tue Aug 30 12:48:03 2016 +0300
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Handles the process output (either stdin or stdout)
+ * passing the lines to a listener
+ */
+public class StreamHandler implements Runnable {
+
+    public interface Listener {
+        /**
+         * Called when a line has been read from the process output stream
+         * @param handler this StreamHandler
+         * @param s the line
+         */
+        void onStringRead(StreamHandler handler, String s);
+    }
+
+    private final ExecutorService executor;
+    private final InputStream is;
+    private final Listener listener;
+
+    /**
+     * @param is input stream to read from
+     * @param listener listener to pass the read lines to
+     * @throws IOException
+     */
+    public StreamHandler(InputStream is, Listener listener) throws IOException {
+        this.is = is;
+        this.listener = listener;
+        executor = Executors.newSingleThreadExecutor();
+    }
+
+    /**
+     * Starts asynchronous reading
+     */
+    public void start() {
+        executor.submit(this);
+    }
+
+    @Override
+    public void run() {
+        try {
+            BufferedReader br = new BufferedReader(new InputStreamReader(is));
+            String line;
+            while ((line = br.readLine()) != null) {
+                listener.onStringRead(this, line);
+            }
+        } catch (Exception x) {
+            throw new RuntimeException(x);
+        }
+    }
+
+}