changeset 10548:521ee1e45c45

8055230: Rename attach provider implementation class be platform neutral Reviewed-by: alanb, chegar, dfuchs, dholmes, erikj, sla
author mchung
date Tue, 26 Aug 2014 14:35:33 -0700
parents ebeeb57242f5
children 1522c5bb84df
files make/gensrc/GensrcProviders.gmk make/lib/Lib-jdk.attach.gmk make/mapfiles/libattach/mapfile-aix make/mapfiles/libattach/mapfile-linux make/mapfiles/libattach/mapfile-solaris src/jdk.attach/aix/classes/sun/tools/attach/AixAttachProvider.java src/jdk.attach/aix/classes/sun/tools/attach/AixVirtualMachine.java src/jdk.attach/aix/classes/sun/tools/attach/AttachProviderImpl.java src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java src/jdk.attach/aix/native/libattach/AixVirtualMachine.c src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c src/jdk.attach/linux/classes/sun/tools/attach/AttachProviderImpl.java src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c src/jdk.attach/macosx/classes/sun/tools/attach/AttachProviderImpl.java src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c src/jdk.attach/unix/classes/sun/tools/attach/BsdAttachProvider.java src/jdk.attach/unix/classes/sun/tools/attach/BsdVirtualMachine.java src/jdk.attach/unix/classes/sun/tools/attach/LinuxAttachProvider.java src/jdk.attach/unix/classes/sun/tools/attach/LinuxVirtualMachine.java src/jdk.attach/unix/classes/sun/tools/attach/SolarisAttachProvider.java src/jdk.attach/unix/classes/sun/tools/attach/SolarisVirtualMachine.java src/jdk.attach/unix/native/libattach/BsdVirtualMachine.c src/jdk.attach/unix/native/libattach/LinuxVirtualMachine.c src/jdk.attach/unix/native/libattach/SolarisVirtualMachine.c src/jdk.attach/windows/classes/sun/tools/attach/AttachProviderImpl.java src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java src/jdk.attach/windows/classes/sun/tools/attach/WindowsAttachProvider.java src/jdk.attach/windows/classes/sun/tools/attach/WindowsVirtualMachine.java src/jdk.attach/windows/native/libattach/AttachProviderImpl.c src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c src/jdk.attach/windows/native/libattach/WindowsAttachProvider.c src/jdk.attach/windows/native/libattach/WindowsVirtualMachine.c
diffstat 38 files changed, 4160 insertions(+), 4202 deletions(-) [+]
line wrap: on
line diff
--- a/make/gensrc/GensrcProviders.gmk	Tue Aug 26 11:43:19 2014 -0700
+++ b/make/gensrc/GensrcProviders.gmk	Tue Aug 26 14:35:33 2014 -0700
@@ -32,15 +32,6 @@
 
 ################################################################################
 
-# Filter com.sun.tools.attach.spi.AttachProvider
-$(JDK_OUTPUTDIR)/gensrc/jdk.attach/META-INF/services/com.sun.tools.attach.spi.AttachProvider: \
-    $(JDK_TOPDIR)/src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider
-	$(process-provider)
-
-GENSRC_JDK_ATTACH += $(JDK_OUTPUTDIR)/gensrc/jdk.attach/META-INF/services/com.sun.tools.attach.spi.AttachProvider
-
-################################################################################
-
 # Filter com.sun.jdi.connect.Connector
 $(JDK_OUTPUTDIR)/gensrc/jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector: \
     $(JDK_TOPDIR)/src/jdk.jdi/share/classes/META-INF/services/com.sun.jdi.connect.Connector
--- a/make/lib/Lib-jdk.attach.gmk	Tue Aug 26 11:43:19 2014 -0700
+++ b/make/lib/Lib-jdk.attach.gmk	Tue Aug 26 14:35:33 2014 -0700
@@ -27,33 +27,11 @@
 
 ################################################################################
 
-ifeq ($(OPENJDK_TARGET_OS), aix)
-  LIBATTACH_OS_API_DIR := aix
-else
-  LIBATTACH_OS_API_DIR := $(OPENJDK_TARGET_OS_API_DIR)
-endif
-
-LIBATTACH_SRC := $(JDK_TOPDIR)/src/jdk.attach/$(LIBATTACH_OS_API_DIR)/native/libattach
-
-LIBATTACH_EXCLUDE_FILES :=
-ifneq ($(OPENJDK_TARGET_OS), solaris)
-  LIBATTACH_EXCLUDE_FILES += SolarisVirtualMachine.c
-endif
-ifneq ($(OPENJDK_TARGET_OS), linux)
-  LIBATTACH_EXCLUDE_FILES += LinuxVirtualMachine.c
-endif
-ifneq ($(OPENJDK_TARGET_OS), macosx)
-  LIBATTACH_EXCLUDE_FILES += BsdVirtualMachine.c
-endif
-ifneq ($(OPENJDK_TARGET_OS),aix)
-  LIBATTACH_EXCLUDE_FILES += AixVirtualMachine.c
-endif
 
 $(eval $(call SetupNativeCompilation,BUILD_LIBATTACH, \
     LIBRARY := attach, \
     OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
-    SRC := $(LIBATTACH_SRC), \
-    EXCLUDE_FILES := $(LIBATTACH_EXCLUDE_FILES), \
+    SRC := $(JDK_TOPDIR)/src/jdk.attach/$(OPENJDK_TARGET_OS)/native/libattach, \
     LANG := C, \
     OPTIMIZATION := LOW, \
     CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) \
--- a/make/mapfiles/libattach/mapfile-aix	Tue Aug 26 11:43:19 2014 -0700
+++ b/make/mapfiles/libattach/mapfile-aix	Tue Aug 26 14:35:33 2014 -0700
@@ -27,13 +27,13 @@
 
 SUNWprivate_1.1 {
 	global:
-            Java_sun_tools_attach_AixVirtualMachine_socket
-            Java_sun_tools_attach_AixVirtualMachine_connect
-            Java_sun_tools_attach_AixVirtualMachine_sendQuitTo
-            Java_sun_tools_attach_AixVirtualMachine_checkPermissions
-            Java_sun_tools_attach_AixVirtualMachine_close
-            Java_sun_tools_attach_AixVirtualMachine_read
-            Java_sun_tools_attach_AixVirtualMachine_write
+            Java_sun_tools_attach_VirtualMachineImpl_socket
+            Java_sun_tools_attach_VirtualMachineImpl_connect
+            Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo
+            Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
+            Java_sun_tools_attach_VirtualMachineImpl_close
+            Java_sun_tools_attach_VirtualMachineImpl_read
+            Java_sun_tools_attach_VirtualMachineImpl_write
 	local:
 		*;
 };
--- a/make/mapfiles/libattach/mapfile-linux	Tue Aug 26 11:43:19 2014 -0700
+++ b/make/mapfiles/libattach/mapfile-linux	Tue Aug 26 14:35:33 2014 -0700
@@ -27,17 +27,17 @@
 
 SUNWprivate_1.1 {
 	global:
-	    Java_sun_tools_attach_LinuxVirtualMachine_checkPermissions;
-	    Java_sun_tools_attach_LinuxVirtualMachine_close;
-	    Java_sun_tools_attach_LinuxVirtualMachine_connect;
-	    Java_sun_tools_attach_LinuxVirtualMachine_getLinuxThreadsManager;
-	    Java_sun_tools_attach_LinuxVirtualMachine_isLinuxThreads;
-	    Java_sun_tools_attach_LinuxVirtualMachine_open;
-	    Java_sun_tools_attach_LinuxVirtualMachine_sendQuitTo;
-            Java_sun_tools_attach_LinuxVirtualMachine_sendQuitToChildrenOf;
-	    Java_sun_tools_attach_LinuxVirtualMachine_socket;
-	    Java_sun_tools_attach_LinuxVirtualMachine_read;
-	    Java_sun_tools_attach_LinuxVirtualMachine_write;
+	    Java_sun_tools_attach_VirtualMachineImpl_checkPermissions;
+	    Java_sun_tools_attach_VirtualMachineImpl_close;
+	    Java_sun_tools_attach_VirtualMachineImpl_connect;
+	    Java_sun_tools_attach_VirtualMachineImpl_getLinuxThreadsManager;
+	    Java_sun_tools_attach_VirtualMachineImpl_isLinuxThreads;
+	    Java_sun_tools_attach_VirtualMachineImpl_open;
+	    Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo;
+            Java_sun_tools_attach_VirtualMachineImpl_sendQuitToChildrenOf;
+	    Java_sun_tools_attach_VirtualMachineImpl_socket;
+	    Java_sun_tools_attach_VirtualMachineImpl_read;
+	    Java_sun_tools_attach_VirtualMachineImpl_write;
 	local:
 		*;
 };
--- a/make/mapfiles/libattach/mapfile-solaris	Tue Aug 26 11:43:19 2014 -0700
+++ b/make/mapfiles/libattach/mapfile-solaris	Tue Aug 26 14:35:33 2014 -0700
@@ -27,12 +27,12 @@
 
 SUNWprivate_1.1 {
 	global:
-            Java_sun_tools_attach_SolarisVirtualMachine_checkPermissions;
-            Java_sun_tools_attach_SolarisVirtualMachine_enqueue;
-            Java_sun_tools_attach_SolarisVirtualMachine_open;
-	    Java_sun_tools_attach_SolarisVirtualMachine_close;
-	    Java_sun_tools_attach_SolarisVirtualMachine_read;
-	    Java_sun_tools_attach_SolarisVirtualMachine_sigquit;
+            Java_sun_tools_attach_VirtualMachineImpl_checkPermissions;
+            Java_sun_tools_attach_VirtualMachineImpl_enqueue;
+            Java_sun_tools_attach_VirtualMachineImpl_open;
+	    Java_sun_tools_attach_VirtualMachineImpl_close;
+	    Java_sun_tools_attach_VirtualMachineImpl_read;
+	    Java_sun_tools_attach_VirtualMachineImpl_sigquit;
 	local:
 		*;
 };
--- a/src/jdk.attach/aix/classes/sun/tools/attach/AixAttachProvider.java	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 SAP AG. 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.tools.attach;
-
-import com.sun.tools.attach.VirtualMachine;
-import com.sun.tools.attach.VirtualMachineDescriptor;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.spi.AttachProvider;
-
-import java.io.IOException;
-
-// Based on 'LinuxAttachProvider.java'. All occurrences of the string
-// "Linux" have been textually replaced by "Aix" to avoid confusion.
-
-/*
- * An AttachProvider implementation for Aix that uses a UNIX domain
- * socket.
- */
-public class AixAttachProvider extends HotSpotAttachProvider {
-
-    // perf counter for the JVM version
-    private static final String JVM_VERSION = "java.property.java.vm.version";
-
-    public AixAttachProvider() {
-    }
-
-    public String name() {
-        return "sun";
-    }
-
-    public String type() {
-        return "socket";
-    }
-
-    public VirtualMachine attachVirtualMachine(String vmid)
-        throws AttachNotSupportedException, IOException
-    {
-        checkAttachPermission();
-
-        // AttachNotSupportedException will be thrown if the target VM can be determined
-        // to be not attachable.
-        testAttachable(vmid);
-
-        return new AixVirtualMachine(this, vmid);
-    }
-
-    public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd)
-        throws AttachNotSupportedException, IOException
-    {
-        if (vmd.provider() != this) {
-            throw new AttachNotSupportedException("provider mismatch");
-        }
-        // To avoid re-checking if the VM if attachable, we check if the descriptor
-        // is for a hotspot VM - these descriptors are created by the listVirtualMachines
-        // implementation which only returns a list of attachable VMs.
-        if (vmd instanceof HotSpotVirtualMachineDescriptor) {
-            assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable();
-            checkAttachPermission();
-            return new AixVirtualMachine(this, vmd.id());
-        } else {
-            return attachVirtualMachine(vmd.id());
-        }
-    }
-
-}
--- a/src/jdk.attach/aix/classes/sun/tools/attach/AixVirtualMachine.java	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,317 +0,0 @@
-/*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 SAP AG. 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.tools.attach;
-
-import com.sun.tools.attach.VirtualMachine;
-import com.sun.tools.attach.AgentLoadException;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.spi.AttachProvider;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.File;
-import java.util.Properties;
-
-// Based on 'LinuxVirtualMachine.java'. All occurrences of the string
-// "Linux" have been textually replaced by "Aix" to avoid confusion.
-
-/*
- * Aix implementation of HotSpotVirtualMachine
- */
-public class AixVirtualMachine extends HotSpotVirtualMachine {
-    // "/tmp" is used as a global well-known location for the files
-    // .java_pid<pid>. and .attach_pid<pid>. It is important that this
-    // location is the same for all processes, otherwise the tools
-    // will not be able to find all Hotspot processes.
-    // Any changes to this needs to be synchronized with HotSpot.
-    private static final String tmpdir = "/tmp";
-
-    // The patch to the socket file created by the target VM
-    String path;
-
-    /**
-     * Attaches to the target VM
-     */
-    AixVirtualMachine(AttachProvider provider, String vmid)
-        throws AttachNotSupportedException, IOException
-    {
-        super(provider, vmid);
-
-        // This provider only understands pids
-        int pid;
-        try {
-            pid = Integer.parseInt(vmid);
-        } catch (NumberFormatException x) {
-            throw new AttachNotSupportedException("Invalid process identifier");
-        }
-
-        // Find the socket file. If not found then we attempt to start the
-        // attach mechanism in the target VM by sending it a QUIT signal.
-        // Then we attempt to find the socket file again.
-        path = findSocketFile(pid);
-        if (path == null) {
-            File f = createAttachFile(pid);
-            try {
-                sendQuitTo(pid);
-
-                // give the target VM time to start the attach mechanism
-                int i = 0;
-                long delay = 200;
-                int retries = (int)(attachTimeout() / delay);
-                do {
-                    try {
-                        Thread.sleep(delay);
-                    } catch (InterruptedException x) { }
-                    path = findSocketFile(pid);
-                    i++;
-                } while (i <= retries && path == null);
-                if (path == null) {
-                    throw new AttachNotSupportedException(
-                        "Unable to open socket file: target process not responding " +
-                        "or HotSpot VM not loaded");
-                }
-            } finally {
-                f.delete();
-            }
-        }
-
-        // Check that the file owner/permission to avoid attaching to
-        // bogus process
-        checkPermissions(path);
-
-        // Check that we can connect to the process
-        // - this ensures we throw the permission denied error now rather than
-        // later when we attempt to enqueue a command.
-        int s = socket();
-        try {
-            connect(s, path);
-        } finally {
-            close(s);
-        }
-    }
-
-    /**
-     * Detach from the target VM
-     */
-    public void detach() throws IOException {
-        synchronized (this) {
-            if (this.path != null) {
-                this.path = null;
-            }
-        }
-    }
-
-    // protocol version
-    private final static String PROTOCOL_VERSION = "1";
-
-    // known errors
-    private final static int ATTACH_ERROR_BADVERSION = 101;
-
-    /**
-     * Execute the given command in the target VM.
-     */
-    InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
-        assert args.length <= 3;            // includes null
-
-        // did we detach?
-        String p;
-        synchronized (this) {
-            if (this.path == null) {
-                throw new IOException("Detached from target VM");
-            }
-            p = this.path;
-        }
-
-        // create UNIX socket
-        int s = socket();
-
-        // connect to target VM
-        try {
-            connect(s, p);
-        } catch (IOException x) {
-            close(s);
-            throw x;
-        }
-
-        IOException ioe = null;
-
-        // connected - write request
-        // <ver> <cmd> <args...>
-        try {
-            writeString(s, PROTOCOL_VERSION);
-            writeString(s, cmd);
-
-            for (int i=0; i<3; i++) {
-                if (i < args.length && args[i] != null) {
-                    writeString(s, (String)args[i]);
-                } else {
-                    writeString(s, "");
-                }
-            }
-        } catch (IOException x) {
-            ioe = x;
-        }
-
-
-        // Create an input stream to read reply
-        SocketInputStream sis = new SocketInputStream(s);
-
-        // Read the command completion status
-        int completionStatus;
-        try {
-            completionStatus = readInt(sis);
-        } catch (IOException x) {
-            sis.close();
-            if (ioe != null) {
-                throw ioe;
-            } else {
-                throw x;
-            }
-        }
-
-        if (completionStatus != 0) {
-            sis.close();
-
-            // In the event of a protocol mismatch then the target VM
-            // returns a known error so that we can throw a reasonable
-            // error.
-            if (completionStatus == ATTACH_ERROR_BADVERSION) {
-                throw new IOException("Protocol mismatch with target VM");
-            }
-
-            // Special-case the "load" command so that the right exception is
-            // thrown.
-            if (cmd.equals("load")) {
-                throw new AgentLoadException("Failed to load agent library");
-            } else {
-                throw new IOException("Command failed in target VM");
-            }
-        }
-
-        // Return the input stream so that the command output can be read
-        return sis;
-    }
-
-    /*
-     * InputStream for the socket connection to get target VM
-     */
-    private class SocketInputStream extends InputStream {
-        int s;
-
-        public SocketInputStream(int s) {
-            this.s = s;
-        }
-
-        public synchronized int read() throws IOException {
-            byte b[] = new byte[1];
-            int n = this.read(b, 0, 1);
-            if (n == 1) {
-                return b[0] & 0xff;
-            } else {
-                return -1;
-            }
-        }
-
-        public synchronized int read(byte[] bs, int off, int len) throws IOException {
-            if ((off < 0) || (off > bs.length) || (len < 0) ||
-                ((off + len) > bs.length) || ((off + len) < 0)) {
-                throw new IndexOutOfBoundsException();
-            } else if (len == 0)
-                return 0;
-
-            return AixVirtualMachine.read(s, bs, off, len);
-        }
-
-        public void close() throws IOException {
-            AixVirtualMachine.close(s);
-        }
-    }
-
-    // Return the socket file for the given process.
-    private String findSocketFile(int pid) {
-        File f = new File(tmpdir, ".java_pid" + pid);
-        if (!f.exists()) {
-            return null;
-        }
-        return f.getPath();
-    }
-
-    // On Solaris/Linux/Aix a simple handshake is used to start the attach mechanism
-    // if not already started. The client creates a .attach_pid<pid> file in the
-    // target VM's working directory (or temp directory), and the SIGQUIT handler
-    // checks for the file.
-    private File createAttachFile(int pid) throws IOException {
-        String fn = ".attach_pid" + pid;
-        String path = "/proc/" + pid + "/cwd/" + fn;
-        File f = new File(path);
-        try {
-            f.createNewFile();
-        } catch (IOException x) {
-            f = new File(tmpdir, fn);
-            f.createNewFile();
-        }
-        return f;
-    }
-
-    /*
-     * Write/sends the given to the target VM. String is transmitted in
-     * UTF-8 encoding.
-     */
-    private void writeString(int fd, String s) throws IOException {
-        if (s.length() > 0) {
-            byte b[];
-            try {
-                b = s.getBytes("UTF-8");
-            } catch (java.io.UnsupportedEncodingException x) {
-                throw new InternalError(x);
-            }
-            AixVirtualMachine.write(fd, b, 0, b.length);
-        }
-        byte b[] = new byte[1];
-        b[0] = 0;
-        write(fd, b, 0, 1);
-    }
-
-
-    //-- native methods
-
-    static native void sendQuitTo(int pid) throws IOException;
-
-    static native void checkPermissions(String path) throws IOException;
-
-    static native int socket() throws IOException;
-
-    static native void connect(int fd, String path) throws IOException;
-
-    static native void close(int fd) throws IOException;
-
-    static native int read(int fd, byte buf[], int off, int bufLen) throws IOException;
-
-    static native void write(int fd, byte buf[], int off, int bufLen) throws IOException;
-
-    static {
-        System.loadLibrary("attach");
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/aix/classes/sun/tools/attach/AttachProviderImpl.java	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 SAP AG. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 sun.tools.attach;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.VirtualMachineDescriptor;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.spi.AttachProvider;
+
+import java.io.IOException;
+
+// Based on linux/classes/sun/tools/attach/AttachProviderImpl.java.
+
+/*
+ * An AttachProvider implementation for Aix that uses a UNIX domain
+ * socket.
+ */
+public class AttachProviderImpl extends HotSpotAttachProvider {
+
+    // perf counter for the JVM version
+    private static final String JVM_VERSION = "java.property.java.vm.version";
+
+    public AttachProviderImpl() {
+    }
+
+    public String name() {
+        return "sun";
+    }
+
+    public String type() {
+        return "socket";
+    }
+
+    public VirtualMachine attachVirtualMachine(String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        checkAttachPermission();
+
+        // AttachNotSupportedException will be thrown if the target VM can be determined
+        // to be not attachable.
+        testAttachable(vmid);
+
+        return new VirtualMachineImpl(this, vmid);
+    }
+
+    public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd)
+        throws AttachNotSupportedException, IOException
+    {
+        if (vmd.provider() != this) {
+            throw new AttachNotSupportedException("provider mismatch");
+        }
+        // To avoid re-checking if the VM if attachable, we check if the descriptor
+        // is for a hotspot VM - these descriptors are created by the listVirtualMachines
+        // implementation which only returns a list of attachable VMs.
+        if (vmd instanceof HotSpotVirtualMachineDescriptor) {
+            assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable();
+            checkAttachPermission();
+            return new VirtualMachineImpl(this, vmd.id());
+        } else {
+            return attachVirtualMachine(vmd.id());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 SAP AG. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 sun.tools.attach;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.AgentLoadException;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.spi.AttachProvider;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+import java.util.Properties;
+
+// Based on linux/classes/sun/tools/attach/VirtualMachineImpl.java.
+
+/*
+ * Aix implementation of HotSpotVirtualMachine
+ */
+public class VirtualMachineImpl extends HotSpotVirtualMachine {
+    // "/tmp" is used as a global well-known location for the files
+    // .java_pid<pid>. and .attach_pid<pid>. It is important that this
+    // location is the same for all processes, otherwise the tools
+    // will not be able to find all Hotspot processes.
+    // Any changes to this needs to be synchronized with HotSpot.
+    private static final String tmpdir = "/tmp";
+
+    // The patch to the socket file created by the target VM
+    String path;
+
+    /**
+     * Attaches to the target VM
+     */
+    VirtualMachineImpl(AttachProvider provider, String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        super(provider, vmid);
+
+        // This provider only understands pids
+        int pid;
+        try {
+            pid = Integer.parseInt(vmid);
+        } catch (NumberFormatException x) {
+            throw new AttachNotSupportedException("Invalid process identifier");
+        }
+
+        // Find the socket file. If not found then we attempt to start the
+        // attach mechanism in the target VM by sending it a QUIT signal.
+        // Then we attempt to find the socket file again.
+        path = findSocketFile(pid);
+        if (path == null) {
+            File f = createAttachFile(pid);
+            try {
+                sendQuitTo(pid);
+
+                // give the target VM time to start the attach mechanism
+                int i = 0;
+                long delay = 200;
+                int retries = (int)(attachTimeout() / delay);
+                do {
+                    try {
+                        Thread.sleep(delay);
+                    } catch (InterruptedException x) { }
+                    path = findSocketFile(pid);
+                    i++;
+                } while (i <= retries && path == null);
+                if (path == null) {
+                    throw new AttachNotSupportedException(
+                        "Unable to open socket file: target process not responding " +
+                        "or HotSpot VM not loaded");
+                }
+            } finally {
+                f.delete();
+            }
+        }
+
+        // Check that the file owner/permission to avoid attaching to
+        // bogus process
+        checkPermissions(path);
+
+        // Check that we can connect to the process
+        // - this ensures we throw the permission denied error now rather than
+        // later when we attempt to enqueue a command.
+        int s = socket();
+        try {
+            connect(s, path);
+        } finally {
+            close(s);
+        }
+    }
+
+    /**
+     * Detach from the target VM
+     */
+    public void detach() throws IOException {
+        synchronized (this) {
+            if (this.path != null) {
+                this.path = null;
+            }
+        }
+    }
+
+    // protocol version
+    private final static String PROTOCOL_VERSION = "1";
+
+    // known errors
+    private final static int ATTACH_ERROR_BADVERSION = 101;
+
+    /**
+     * Execute the given command in the target VM.
+     */
+    InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
+        assert args.length <= 3;            // includes null
+
+        // did we detach?
+        String p;
+        synchronized (this) {
+            if (this.path == null) {
+                throw new IOException("Detached from target VM");
+            }
+            p = this.path;
+        }
+
+        // create UNIX socket
+        int s = socket();
+
+        // connect to target VM
+        try {
+            connect(s, p);
+        } catch (IOException x) {
+            close(s);
+            throw x;
+        }
+
+        IOException ioe = null;
+
+        // connected - write request
+        // <ver> <cmd> <args...>
+        try {
+            writeString(s, PROTOCOL_VERSION);
+            writeString(s, cmd);
+
+            for (int i=0; i<3; i++) {
+                if (i < args.length && args[i] != null) {
+                    writeString(s, (String)args[i]);
+                } else {
+                    writeString(s, "");
+                }
+            }
+        } catch (IOException x) {
+            ioe = x;
+        }
+
+
+        // Create an input stream to read reply
+        SocketInputStream sis = new SocketInputStream(s);
+
+        // Read the command completion status
+        int completionStatus;
+        try {
+            completionStatus = readInt(sis);
+        } catch (IOException x) {
+            sis.close();
+            if (ioe != null) {
+                throw ioe;
+            } else {
+                throw x;
+            }
+        }
+
+        if (completionStatus != 0) {
+            sis.close();
+
+            // In the event of a protocol mismatch then the target VM
+            // returns a known error so that we can throw a reasonable
+            // error.
+            if (completionStatus == ATTACH_ERROR_BADVERSION) {
+                throw new IOException("Protocol mismatch with target VM");
+            }
+
+            // Special-case the "load" command so that the right exception is
+            // thrown.
+            if (cmd.equals("load")) {
+                throw new AgentLoadException("Failed to load agent library");
+            } else {
+                throw new IOException("Command failed in target VM");
+            }
+        }
+
+        // Return the input stream so that the command output can be read
+        return sis;
+    }
+
+    /*
+     * InputStream for the socket connection to get target VM
+     */
+    private class SocketInputStream extends InputStream {
+        int s;
+
+        public SocketInputStream(int s) {
+            this.s = s;
+        }
+
+        public synchronized int read() throws IOException {
+            byte b[] = new byte[1];
+            int n = this.read(b, 0, 1);
+            if (n == 1) {
+                return b[0] & 0xff;
+            } else {
+                return -1;
+            }
+        }
+
+        public synchronized int read(byte[] bs, int off, int len) throws IOException {
+            if ((off < 0) || (off > bs.length) || (len < 0) ||
+                ((off + len) > bs.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0)
+                return 0;
+
+            return VirtualMachineImpl.read(s, bs, off, len);
+        }
+
+        public void close() throws IOException {
+            VirtualMachineImpl.close(s);
+        }
+    }
+
+    // Return the socket file for the given process.
+    private String findSocketFile(int pid) {
+        File f = new File(tmpdir, ".java_pid" + pid);
+        if (!f.exists()) {
+            return null;
+        }
+        return f.getPath();
+    }
+
+    // On Solaris/Linux/Aix a simple handshake is used to start the attach mechanism
+    // if not already started. The client creates a .attach_pid<pid> file in the
+    // target VM's working directory (or temp directory), and the SIGQUIT handler
+    // checks for the file.
+    private File createAttachFile(int pid) throws IOException {
+        String fn = ".attach_pid" + pid;
+        String path = "/proc/" + pid + "/cwd/" + fn;
+        File f = new File(path);
+        try {
+            f.createNewFile();
+        } catch (IOException x) {
+            f = new File(tmpdir, fn);
+            f.createNewFile();
+        }
+        return f;
+    }
+
+    /*
+     * Write/sends the given to the target VM. String is transmitted in
+     * UTF-8 encoding.
+     */
+    private void writeString(int fd, String s) throws IOException {
+        if (s.length() > 0) {
+            byte b[];
+            try {
+                b = s.getBytes("UTF-8");
+            } catch (java.io.UnsupportedEncodingException x) {
+                throw new InternalError(x);
+            }
+            VirtualMachineImpl.write(fd, b, 0, b.length);
+        }
+        byte b[] = new byte[1];
+        b[0] = 0;
+        write(fd, b, 0, 1);
+    }
+
+
+    //-- native methods
+
+    static native void sendQuitTo(int pid) throws IOException;
+
+    static native void checkPermissions(String path) throws IOException;
+
+    static native int socket() throws IOException;
+
+    static native void connect(int fd, String path) throws IOException;
+
+    static native void close(int fd) throws IOException;
+
+    static native int read(int fd, byte buf[], int off, int bufLen) throws IOException;
+
+    static native void write(int fd, byte buf[], int off, int bufLen) throws IOException;
+
+    static {
+        System.loadLibrary("attach");
+    }
+}
--- a/src/jdk.attach/aix/native/libattach/AixVirtualMachine.c	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-/*
- * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 SAP AG. 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-
-/*
- * Based on 'LinuxVirtualMachine.c'. Non-relevant code has been removed and all
- * occurrences of the string "Linux" have been replaced by "Aix".
- */
-
-#include "sun_tools_attach_AixVirtualMachine.h"
-
-#define RESTARTABLE(_cmd, _result) do { \
-  do { \
-    _result = _cmd; \
-  } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
-
-/*
- * Class:     sun_tools_attach_AixVirtualMachine
- * Method:    socket
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_AixVirtualMachine_socket
-  (JNIEnv *env, jclass cls)
-{
-    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
-    if (fd == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "socket");
-    }
-    /* added time out values */
-    else {
-        struct timeval tv;
-        tv.tv_sec = 2 * 60;
-        tv.tv_usec = 0;
-
-        setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
-        setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
-    }
-    return (jint)fd;
-}
-
-/*
- * Class:     sun_tools_attach_AixVirtualMachine
- * Method:    connect
- * Signature: (ILjava/lang/String;)I
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_connect
-  (JNIEnv *env, jclass cls, jint fd, jstring path)
-{
-    jboolean isCopy;
-    const char* p = GetStringPlatformChars(env, path, &isCopy);
-    if (p != NULL) {
-        struct sockaddr_un addr;
-        int err = 0;
-
-        memset(&addr, 0, sizeof(addr));
-        addr.sun_family = AF_UNIX;
-        /* strncpy is safe because addr.sun_path was zero-initialized before. */
-        strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1);
-        /* We must call bind with the actual socketaddr length. This is obligatory for AS400. */
-        if (connect(fd, (struct sockaddr*)&addr, SUN_LEN(&addr)) == -1) {
-            err = errno;
-        }
-
-        if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, path, p);
-        }
-
-        /*
-         * If the connect failed then we throw the appropriate exception
-         * here (can't throw it before releasing the string as can't call
-         * JNI with pending exception)
-         */
-        if (err != 0) {
-            if (err == ENOENT) {
-                JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);
-            } else {
-                char* msg = strdup(strerror(err));
-                JNU_ThrowIOException(env, msg);
-                if (msg != NULL) {
-                    free(msg);
-                }
-            }
-        }
-    }
-}
-
-
-/*
- * Structure and callback function used to send a QUIT signal to all
- * children of a given process
- */
-typedef struct {
-    pid_t ppid;
-} SendQuitContext;
-
-static void SendQuitCallback(const pid_t pid, void* user_data) {
-    SendQuitContext* context = (SendQuitContext*)user_data;
-    pid_t parent = getParent(pid);
-    if (parent == context->ppid) {
-        kill(pid, SIGQUIT);
-    }
-}
-
-/*
- * Class:     sun_tools_attach_AixVirtualMachine
- * Method:    sendQuitTo
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_sendQuitTo
-  (JNIEnv *env, jclass cls, jint pid)
-{
-    if (kill((pid_t)pid, SIGQUIT)) {
-        JNU_ThrowIOExceptionWithLastError(env, "kill");
-    }
-}
-
-/*
- * Class:     sun_tools_attach_AixVirtualMachine
- * Method:    checkPermissions
- * Signature: (Ljava/lang/String;)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_checkPermissions
-  (JNIEnv *env, jclass cls, jstring path)
-{
-    jboolean isCopy;
-    const char* p = GetStringPlatformChars(env, path, &isCopy);
-    if (p != NULL) {
-        struct stat64 sb;
-        uid_t uid, gid;
-        int res;
-        /* added missing initialization of the stat64 buffer */
-        memset(&sb, 0, sizeof(struct stat64));
-
-        /*
-         * Check that the path is owned by the effective uid/gid of this
-         * process. Also check that group/other access is not allowed.
-         */
-        uid = geteuid();
-        gid = getegid();
-
-        res = stat64(p, &sb);
-        if (res != 0) {
-            /* save errno */
-            res = errno;
-        }
-
-        /* release p here before we throw an I/O exception */
-        if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, path, p);
-        }
-
-        if (res == 0) {
-            if ( (sb.st_uid != uid) || (sb.st_gid != gid) ||
-                 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) {
-                JNU_ThrowIOException(env, "well-known file is not secure");
-            }
-        } else {
-            char* msg = strdup(strerror(res));
-            JNU_ThrowIOException(env, msg);
-            if (msg != NULL) {
-                free(msg);
-            }
-        }
-    }
-}
-
-/*
- * Class:     sun_tools_attach_AixVirtualMachine
- * Method:    close
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_close
-  (JNIEnv *env, jclass cls, jint fd)
-{
-    int res;
-    /* Fixed deadlock when this call of close by the client is not seen by the attach server
-     * which has accepted the (very short) connection already and is waiting for the request. But read don't get a byte,
-     * because the close is lost without shutdown.
-     */
-    shutdown(fd, 2);
-    RESTARTABLE(close(fd), res);
-}
-
-/*
- * Class:     sun_tools_attach_AixVirtualMachine
- * Method:    read
- * Signature: (I[BI)I
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_AixVirtualMachine_read
-  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)
-{
-    unsigned char buf[128];
-    size_t len = sizeof(buf);
-    ssize_t n;
-
-    size_t remaining = (size_t)(baLen - off);
-    if (len > remaining) {
-        len = remaining;
-    }
-
-    RESTARTABLE(read(fd, buf+off, len), n);
-    if (n == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "read");
-    } else {
-        if (n == 0) {
-            n = -1;     // EOF
-        } else {
-            (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf+off));
-        }
-    }
-    return n;
-}
-
-/*
- * Class:     sun_tools_attach_AixVirtualMachine
- * Method:    write
- * Signature: (I[B)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_write
-  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen)
-{
-    size_t remaining = bufLen;
-    do {
-        unsigned char buf[128];
-        size_t len = sizeof(buf);
-        int n;
-
-        if (len > remaining) {
-            len = remaining;
-        }
-        (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf);
-
-        RESTARTABLE(write(fd, buf, len), n);
-        if (n > 0) {
-            off += n;
-            remaining -= n;
-        } else {
-            JNU_ThrowIOExceptionWithLastError(env, "write");
-            return;
-        }
-
-    } while (remaining > 0);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 SAP AG. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+/*
+ * Based on 'LinuxVirtualMachine.c'. Non-relevant code has been removed and all
+ * occurrences of the string "Linux" have been replaced by "Aix".
+ */
+
+#include "sun_tools_attach_VirtualMachineImpl.h"
+
+#define RESTARTABLE(_cmd, _result) do { \
+  do { \
+    _result = _cmd; \
+  } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    socket
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_socket
+  (JNIEnv *env, jclass cls)
+{
+    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (fd == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "socket");
+    }
+    /* added time out values */
+    else {
+        struct timeval tv;
+        tv.tv_sec = 2 * 60;
+        tv.tv_usec = 0;
+
+        setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
+        setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
+    }
+    return (jint)fd;
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    connect
+ * Signature: (ILjava/lang/String;)I
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connect
+  (JNIEnv *env, jclass cls, jint fd, jstring path)
+{
+    jboolean isCopy;
+    const char* p = GetStringPlatformChars(env, path, &isCopy);
+    if (p != NULL) {
+        struct sockaddr_un addr;
+        int err = 0;
+
+        memset(&addr, 0, sizeof(addr));
+        addr.sun_family = AF_UNIX;
+        /* strncpy is safe because addr.sun_path was zero-initialized before. */
+        strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1);
+        /* We must call bind with the actual socketaddr length. This is obligatory for AS400. */
+        if (connect(fd, (struct sockaddr*)&addr, SUN_LEN(&addr)) == -1) {
+            err = errno;
+        }
+
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, p);
+        }
+
+        /*
+         * If the connect failed then we throw the appropriate exception
+         * here (can't throw it before releasing the string as can't call
+         * JNI with pending exception)
+         */
+        if (err != 0) {
+            if (err == ENOENT) {
+                JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);
+            } else {
+                char* msg = strdup(strerror(err));
+                JNU_ThrowIOException(env, msg);
+                if (msg != NULL) {
+                    free(msg);
+                }
+            }
+        }
+    }
+}
+
+
+/*
+ * Structure and callback function used to send a QUIT signal to all
+ * children of a given process
+ */
+typedef struct {
+    pid_t ppid;
+} SendQuitContext;
+
+static void SendQuitCallback(const pid_t pid, void* user_data) {
+    SendQuitContext* context = (SendQuitContext*)user_data;
+    pid_t parent = getParent(pid);
+    if (parent == context->ppid) {
+        kill(pid, SIGQUIT);
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    sendQuitTo
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo
+  (JNIEnv *env, jclass cls, jint pid)
+{
+    if (kill((pid_t)pid, SIGQUIT)) {
+        JNU_ThrowIOExceptionWithLastError(env, "kill");
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    checkPermissions
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
+  (JNIEnv *env, jclass cls, jstring path)
+{
+    jboolean isCopy;
+    const char* p = GetStringPlatformChars(env, path, &isCopy);
+    if (p != NULL) {
+        struct stat64 sb;
+        uid_t uid, gid;
+        int res;
+        /* added missing initialization of the stat64 buffer */
+        memset(&sb, 0, sizeof(struct stat64));
+
+        /*
+         * Check that the path is owned by the effective uid/gid of this
+         * process. Also check that group/other access is not allowed.
+         */
+        uid = geteuid();
+        gid = getegid();
+
+        res = stat64(p, &sb);
+        if (res != 0) {
+            /* save errno */
+            res = errno;
+        }
+
+        /* release p here before we throw an I/O exception */
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, p);
+        }
+
+        if (res == 0) {
+            if ( (sb.st_uid != uid) || (sb.st_gid != gid) ||
+                 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) {
+                JNU_ThrowIOException(env, "well-known file is not secure");
+            }
+        } else {
+            char* msg = strdup(strerror(res));
+            JNU_ThrowIOException(env, msg);
+            if (msg != NULL) {
+                free(msg);
+            }
+        }
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    close
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close
+  (JNIEnv *env, jclass cls, jint fd)
+{
+    int res;
+    /* Fixed deadlock when this call of close by the client is not seen by the attach server
+     * which has accepted the (very short) connection already and is waiting for the request. But read don't get a byte,
+     * because the close is lost without shutdown.
+     */
+    shutdown(fd, 2);
+    RESTARTABLE(close(fd), res);
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    read
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_read
+  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)
+{
+    unsigned char buf[128];
+    size_t len = sizeof(buf);
+    ssize_t n;
+
+    size_t remaining = (size_t)(baLen - off);
+    if (len > remaining) {
+        len = remaining;
+    }
+
+    RESTARTABLE(read(fd, buf+off, len), n);
+    if (n == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "read");
+    } else {
+        if (n == 0) {
+            n = -1;     // EOF
+        } else {
+            (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf+off));
+        }
+    }
+    return n;
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    write
+ * Signature: (I[B)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_write
+  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen)
+{
+    size_t remaining = bufLen;
+    do {
+        unsigned char buf[128];
+        size_t len = sizeof(buf);
+        int n;
+
+        if (len > remaining) {
+            len = remaining;
+        }
+        (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf);
+
+        RESTARTABLE(write(fd, buf, len), n);
+        if (n > 0) {
+            off += n;
+            remaining -= n;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "write");
+            return;
+        }
+
+    } while (remaining > 0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/linux/classes/sun/tools/attach/AttachProviderImpl.java	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2005, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 sun.tools.attach;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.VirtualMachineDescriptor;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.spi.AttachProvider;
+
+import java.io.IOException;
+
+/*
+ * An AttachProvider implementation for Linux that uses a UNIX domain
+ * socket.
+ */
+public class AttachProviderImpl extends HotSpotAttachProvider {
+
+    // perf counter for the JVM version
+    private static final String JVM_VERSION = "java.property.java.vm.version";
+
+    public AttachProviderImpl() {
+    }
+
+    public String name() {
+        return "sun";
+    }
+
+    public String type() {
+        return "socket";
+    }
+
+    public VirtualMachine attachVirtualMachine(String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        checkAttachPermission();
+
+        // AttachNotSupportedException will be thrown if the target VM can be determined
+        // to be not attachable.
+        testAttachable(vmid);
+
+        return new VirtualMachineImpl(this, vmid);
+    }
+
+    public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd)
+        throws AttachNotSupportedException, IOException
+    {
+        if (vmd.provider() != this) {
+            throw new AttachNotSupportedException("provider mismatch");
+        }
+        // To avoid re-checking if the VM if attachable, we check if the descriptor
+        // is for a hotspot VM - these descriptors are created by the listVirtualMachines
+        // implementation which only returns a list of attachable VMs.
+        if (vmd instanceof HotSpotVirtualMachineDescriptor) {
+            assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable();
+            checkAttachPermission();
+            return new VirtualMachineImpl(this, vmd.id());
+        } else {
+            return attachVirtualMachine(vmd.id());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2005, 2014, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 sun.tools.attach;
+
+import com.sun.tools.attach.AttachOperationFailedException;
+import com.sun.tools.attach.AgentLoadException;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.spi.AttachProvider;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+
+/*
+ * Linux implementation of HotSpotVirtualMachine
+ */
+public class VirtualMachineImpl extends HotSpotVirtualMachine {
+    // "/tmp" is used as a global well-known location for the files
+    // .java_pid<pid>. and .attach_pid<pid>. It is important that this
+    // location is the same for all processes, otherwise the tools
+    // will not be able to find all Hotspot processes.
+    // Any changes to this needs to be synchronized with HotSpot.
+    private static final String tmpdir = "/tmp";
+
+    // Indicates if this machine uses the old LinuxThreads
+    static boolean isLinuxThreads;
+
+    // The patch to the socket file created by the target VM
+    String path;
+
+    /**
+     * Attaches to the target VM
+     */
+    VirtualMachineImpl(AttachProvider provider, String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        super(provider, vmid);
+
+        // This provider only understands pids
+        int pid;
+        try {
+            pid = Integer.parseInt(vmid);
+        } catch (NumberFormatException x) {
+            throw new AttachNotSupportedException("Invalid process identifier");
+        }
+
+        // Find the socket file. If not found then we attempt to start the
+        // attach mechanism in the target VM by sending it a QUIT signal.
+        // Then we attempt to find the socket file again.
+        path = findSocketFile(pid);
+        if (path == null) {
+            File f = createAttachFile(pid);
+            try {
+                // On LinuxThreads each thread is a process and we don't have the
+                // pid of the VMThread which has SIGQUIT unblocked. To workaround
+                // this we get the pid of the "manager thread" that is created
+                // by the first call to pthread_create. This is parent of all
+                // threads (except the initial thread).
+                if (isLinuxThreads) {
+                    int mpid;
+                    try {
+                        mpid = getLinuxThreadsManager(pid);
+                    } catch (IOException x) {
+                        throw new AttachNotSupportedException(x.getMessage());
+                    }
+                    assert(mpid >= 1);
+                    sendQuitToChildrenOf(mpid);
+                } else {
+                    sendQuitTo(pid);
+                }
+
+                // give the target VM time to start the attach mechanism
+                int i = 0;
+                long delay = 200;
+                int retries = (int)(attachTimeout() / delay);
+                do {
+                    try {
+                        Thread.sleep(delay);
+                    } catch (InterruptedException x) { }
+                    path = findSocketFile(pid);
+                    i++;
+                } while (i <= retries && path == null);
+                if (path == null) {
+                    throw new AttachNotSupportedException(
+                        "Unable to open socket file: target process not responding " +
+                        "or HotSpot VM not loaded");
+                }
+            } finally {
+                f.delete();
+            }
+        }
+
+        // Check that the file owner/permission to avoid attaching to
+        // bogus process
+        checkPermissions(path);
+
+        // Check that we can connect to the process
+        // - this ensures we throw the permission denied error now rather than
+        // later when we attempt to enqueue a command.
+        int s = socket();
+        try {
+            connect(s, path);
+        } finally {
+            close(s);
+        }
+    }
+
+    /**
+     * Detach from the target VM
+     */
+    public void detach() throws IOException {
+        synchronized (this) {
+            if (this.path != null) {
+                this.path = null;
+            }
+        }
+    }
+
+    // protocol version
+    private final static String PROTOCOL_VERSION = "1";
+
+    // known errors
+    private final static int ATTACH_ERROR_BADVERSION = 101;
+
+    /**
+     * Execute the given command in the target VM.
+     */
+    InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
+        assert args.length <= 3;                // includes null
+
+        // did we detach?
+        String p;
+        synchronized (this) {
+            if (this.path == null) {
+                throw new IOException("Detached from target VM");
+            }
+            p = this.path;
+        }
+
+        // create UNIX socket
+        int s = socket();
+
+        // connect to target VM
+        try {
+            connect(s, p);
+        } catch (IOException x) {
+            close(s);
+            throw x;
+        }
+
+        IOException ioe = null;
+
+        // connected - write request
+        // <ver> <cmd> <args...>
+        try {
+            writeString(s, PROTOCOL_VERSION);
+            writeString(s, cmd);
+
+            for (int i=0; i<3; i++) {
+                if (i < args.length && args[i] != null) {
+                    writeString(s, (String)args[i]);
+                } else {
+                    writeString(s, "");
+                }
+            }
+        } catch (IOException x) {
+            ioe = x;
+        }
+
+
+        // Create an input stream to read reply
+        SocketInputStream sis = new SocketInputStream(s);
+
+        // Read the command completion status
+        int completionStatus;
+        try {
+            completionStatus = readInt(sis);
+        } catch (IOException x) {
+            sis.close();
+            if (ioe != null) {
+                throw ioe;
+            } else {
+                throw x;
+            }
+        }
+
+        if (completionStatus != 0) {
+            // read from the stream and use that as the error message
+            String message = readErrorMessage(sis);
+            sis.close();
+
+            // In the event of a protocol mismatch then the target VM
+            // returns a known error so that we can throw a reasonable
+            // error.
+            if (completionStatus == ATTACH_ERROR_BADVERSION) {
+                throw new IOException("Protocol mismatch with target VM");
+            }
+
+            // Special-case the "load" command so that the right exception is
+            // thrown.
+            if (cmd.equals("load")) {
+                throw new AgentLoadException("Failed to load agent library");
+            } else {
+                if (message == null) {
+                    throw new AttachOperationFailedException("Command failed in target VM");
+                } else {
+                    throw new AttachOperationFailedException(message);
+                }
+            }
+        }
+
+        // Return the input stream so that the command output can be read
+        return sis;
+    }
+
+    /*
+     * InputStream for the socket connection to get target VM
+     */
+    private class SocketInputStream extends InputStream {
+        int s;
+
+        public SocketInputStream(int s) {
+            this.s = s;
+        }
+
+        public synchronized int read() throws IOException {
+            byte b[] = new byte[1];
+            int n = this.read(b, 0, 1);
+            if (n == 1) {
+                return b[0] & 0xff;
+            } else {
+                return -1;
+            }
+        }
+
+        public synchronized int read(byte[] bs, int off, int len) throws IOException {
+            if ((off < 0) || (off > bs.length) || (len < 0) ||
+                ((off + len) > bs.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0)
+                return 0;
+
+            return VirtualMachineImpl.read(s, bs, off, len);
+        }
+
+        public void close() throws IOException {
+            VirtualMachineImpl.close(s);
+        }
+    }
+
+    // Return the socket file for the given process.
+    private String findSocketFile(int pid) {
+        File f = new File(tmpdir, ".java_pid" + pid);
+        if (!f.exists()) {
+            return null;
+        }
+        return f.getPath();
+    }
+
+    // On Solaris/Linux a simple handshake is used to start the attach mechanism
+    // if not already started. The client creates a .attach_pid<pid> file in the
+    // target VM's working directory (or temp directory), and the SIGQUIT handler
+    // checks for the file.
+    private File createAttachFile(int pid) throws IOException {
+        String fn = ".attach_pid" + pid;
+        String path = "/proc/" + pid + "/cwd/" + fn;
+        File f = new File(path);
+        try {
+            f.createNewFile();
+        } catch (IOException x) {
+            f = new File(tmpdir, fn);
+            f.createNewFile();
+        }
+        return f;
+    }
+
+    /*
+     * Write/sends the given to the target VM. String is transmitted in
+     * UTF-8 encoding.
+     */
+    private void writeString(int fd, String s) throws IOException {
+        if (s.length() > 0) {
+            byte b[];
+            try {
+                b = s.getBytes("UTF-8");
+            } catch (java.io.UnsupportedEncodingException x) {
+                throw new InternalError(x);
+            }
+            VirtualMachineImpl.write(fd, b, 0, b.length);
+        }
+        byte b[] = new byte[1];
+        b[0] = 0;
+        write(fd, b, 0, 1);
+    }
+
+
+    //-- native methods
+
+    static native boolean isLinuxThreads();
+
+    static native int getLinuxThreadsManager(int pid) throws IOException;
+
+    static native void sendQuitToChildrenOf(int pid) throws IOException;
+
+    static native void sendQuitTo(int pid) throws IOException;
+
+    static native void checkPermissions(String path) throws IOException;
+
+    static native int socket() throws IOException;
+
+    static native void connect(int fd, String path) throws IOException;
+
+    static native void close(int fd) throws IOException;
+
+    static native int read(int fd, byte buf[], int off, int bufLen) throws IOException;
+
+    static native void write(int fd, byte buf[], int off, int bufLen) throws IOException;
+
+    static {
+        System.loadLibrary("attach");
+        isLinuxThreads = isLinuxThreads();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 2005, 2014, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include "sun_tools_attach_VirtualMachineImpl.h"
+
+#define RESTARTABLE(_cmd, _result) do { \
+  do { \
+    _result = _cmd; \
+  } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+/*
+ * Defines a callback that is invoked for each process
+ */
+typedef void (*ProcessCallback)(const pid_t pid, void* user_data);
+
+/*
+ * Invokes the callback function for each process
+ */
+static void forEachProcess(ProcessCallback f, void* user_data) {
+    DIR* dir;
+    struct dirent* ptr;
+
+    /*
+     * To locate the children we scan /proc looking for files that have a
+     * position integer as a filename.
+     */
+    if ((dir = opendir("/proc")) == NULL) {
+        return;
+    }
+    while ((ptr = readdir(dir)) != NULL) {
+        pid_t pid;
+
+        /* skip current/parent directories */
+        if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
+            continue;
+        }
+
+        /* skip files that aren't numbers */
+        pid = (pid_t)atoi(ptr->d_name);
+        if ((int)pid <= 0) {
+            continue;
+        }
+
+        /* invoke the callback */
+        (*f)(pid, user_data);
+    }
+    closedir(dir);
+}
+
+
+/*
+ * Returns the parent pid of a given pid, or -1 if not found
+ */
+static pid_t getParent(pid_t pid) {
+    char state;
+    FILE* fp;
+    char stat[2048];
+    int statlen;
+    char fn[32];
+    int i, p;
+    char* s;
+
+    /*
+     * try to open /proc/%d/stat
+     */
+    sprintf(fn, "/proc/%d/stat", pid);
+    fp = fopen(fn, "r");
+    if (fp == NULL) {
+        return -1;
+    }
+
+    /*
+     * The format is: pid (command) state ppid ...
+     * As the command could be anything we must find the right most
+     * ")" and then skip the white spaces that follow it.
+     */
+    statlen = fread(stat, 1, 2047, fp);
+    stat[statlen] = '\0';
+    fclose(fp);
+    s = strrchr(stat, ')');
+    if (s == NULL) {
+        return -1;
+    }
+    do s++; while (isspace(*s));
+    i = sscanf(s, "%c %d", &state, &p);
+    return (pid_t)p;
+}
+
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    socket
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_socket
+  (JNIEnv *env, jclass cls)
+{
+    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (fd == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "socket");
+    }
+    return (jint)fd;
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    connect
+ * Signature: (ILjava/lang/String;)I
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connect
+  (JNIEnv *env, jclass cls, jint fd, jstring path)
+{
+    jboolean isCopy;
+    const char* p = GetStringPlatformChars(env, path, &isCopy);
+    if (p != NULL) {
+        struct sockaddr_un addr;
+        int err = 0;
+
+        memset(&addr, 0, sizeof(addr));
+        addr.sun_family = AF_UNIX;
+        /* strncpy is safe because addr.sun_path was zero-initialized before. */
+        strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1);
+
+        if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+            err = errno;
+        }
+
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, p);
+        }
+
+        /*
+         * If the connect failed then we throw the appropriate exception
+         * here (can't throw it before releasing the string as can't call
+         * JNI with pending exception)
+         */
+        if (err != 0) {
+            if (err == ENOENT) {
+                JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);
+            } else {
+                char* msg = strdup(strerror(err));
+                JNU_ThrowIOException(env, msg);
+                if (msg != NULL) {
+                    free(msg);
+                }
+            }
+        }
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    isLinuxThreads
+ * Signature: ()V
+ */
+JNIEXPORT jboolean JNICALL Java_sun_tools_attach_VirtualMachineImpl_isLinuxThreads
+  (JNIEnv *env, jclass cls)
+{
+# ifndef _CS_GNU_LIBPTHREAD_VERSION
+# define _CS_GNU_LIBPTHREAD_VERSION 3
+# endif
+    size_t n;
+    char* s;
+    jboolean res;
+
+    n = confstr(_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
+    if (n <= 0) {
+       /* glibc before 2.3.2 only has LinuxThreads */
+       return JNI_TRUE;
+    }
+
+    s = (char *)malloc(n);
+    if (s == NULL) {
+        JNU_ThrowOutOfMemoryError(env, "malloc failed");
+        return JNI_TRUE;
+    }
+    confstr(_CS_GNU_LIBPTHREAD_VERSION, s, n);
+
+    /*
+     * If the LIBPTHREAD version include "NPTL" then we know we
+     * have the new threads library and not LinuxThreads
+     */
+    res = (jboolean)(strstr(s, "NPTL") == NULL);
+    free(s);
+    return res;
+}
+
+/*
+ * Structure and callback function used to count the children of
+ * a given process, and record the pid of the "manager thread".
+ */
+typedef struct {
+    pid_t ppid;
+    int count;
+    pid_t mpid;
+} ChildCountContext;
+
+static void ChildCountCallback(const pid_t pid, void* user_data) {
+    ChildCountContext* context = (ChildCountContext*)user_data;
+    if (getParent(pid) == context->ppid) {
+        context->count++;
+        /*
+         * Remember the pid of the first child. If the final count is
+         * one then this is the pid of the LinuxThreads manager.
+         */
+        if (context->count == 1) {
+            context->mpid = pid;
+        }
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    getLinuxThreadsManager
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_getLinuxThreadsManager
+  (JNIEnv *env, jclass cls, jint pid)
+{
+    ChildCountContext context;
+
+    /*
+     * Iterate over all processes to find how many children 'pid' has
+     */
+    context.ppid = pid;
+    context.count = 0;
+    context.mpid = (pid_t)0;
+    forEachProcess(ChildCountCallback, (void*)&context);
+
+    /*
+     * If there's no children then this is likely the pid of the primordial
+     * created by the launcher - in that case the LinuxThreads manager is the
+     * parent of this process.
+     */
+    if (context.count == 0) {
+        pid_t parent = getParent(pid);
+        if ((int)parent > 0) {
+            return (jint)parent;
+        }
+    }
+
+    /*
+     * There's one child so this is likely the embedded VM case where the
+     * the primordial thread == LinuxThreads initial thread. The LinuxThreads
+     * manager in that case is the child.
+     */
+    if (context.count == 1) {
+        return (jint)context.mpid;
+    }
+
+    /*
+     * If we get here it's most likely we were given the wrong pid
+     */
+    JNU_ThrowIOException(env, "Unable to get pid of LinuxThreads manager thread");
+    return -1;
+}
+
+/*
+ * Structure and callback function used to send a QUIT signal to all
+ * children of a given process
+ */
+typedef struct {
+    pid_t ppid;
+} SendQuitContext;
+
+static void SendQuitCallback(const pid_t pid, void* user_data) {
+    SendQuitContext* context = (SendQuitContext*)user_data;
+    pid_t parent = getParent(pid);
+    if (parent == context->ppid) {
+        kill(pid, SIGQUIT);
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    sendQuitToChildrenOf
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sendQuitToChildrenOf
+  (JNIEnv *env, jclass cls, jint pid)
+{
+    SendQuitContext context;
+    context.ppid = (pid_t)pid;
+
+    /*
+     * Iterate over all children of 'pid' and send a QUIT signal to each.
+     */
+    forEachProcess(SendQuitCallback, (void*)&context);
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    sendQuitTo
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo
+  (JNIEnv *env, jclass cls, jint pid)
+{
+    if (kill((pid_t)pid, SIGQUIT)) {
+        JNU_ThrowIOExceptionWithLastError(env, "kill");
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    checkPermissions
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
+  (JNIEnv *env, jclass cls, jstring path)
+{
+    jboolean isCopy;
+    const char* p = GetStringPlatformChars(env, path, &isCopy);
+    if (p != NULL) {
+        struct stat64 sb;
+        uid_t uid, gid;
+        int res;
+
+        /*
+         * Check that the path is owned by the effective uid/gid of this
+         * process. Also check that group/other access is not allowed.
+         */
+        uid = geteuid();
+        gid = getegid();
+
+        res = stat64(p, &sb);
+        if (res != 0) {
+            /* save errno */
+            res = errno;
+        }
+
+        /* release p here before we throw an I/O exception */
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, p);
+        }
+
+        if (res == 0) {
+            if ( (sb.st_uid != uid) || (sb.st_gid != gid) ||
+                 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) {
+                JNU_ThrowIOException(env, "well-known file is not secure");
+            }
+        } else {
+            char* msg = strdup(strerror(res));
+            JNU_ThrowIOException(env, msg);
+            if (msg != NULL) {
+                free(msg);
+            }
+        }
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    close
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close
+  (JNIEnv *env, jclass cls, jint fd)
+{
+    int res;
+    RESTARTABLE(close(fd), res);
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    read
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_read
+  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)
+{
+    unsigned char buf[128];
+    size_t len = sizeof(buf);
+    ssize_t n;
+
+    size_t remaining = (size_t)(baLen - off);
+    if (len > remaining) {
+        len = remaining;
+    }
+
+    RESTARTABLE(read(fd, buf, len), n);
+    if (n == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "read");
+    } else {
+        if (n == 0) {
+            n = -1;     // EOF
+        } else {
+            (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf));
+        }
+    }
+    return n;
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    write
+ * Signature: (I[B)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_write
+  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen)
+{
+    size_t remaining = bufLen;
+    do {
+        unsigned char buf[128];
+        size_t len = sizeof(buf);
+        int n;
+
+        if (len > remaining) {
+            len = remaining;
+        }
+        (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf);
+
+        RESTARTABLE(write(fd, buf, len), n);
+        if (n > 0) {
+           off += n;
+           remaining -= n;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "write");
+            return;
+        }
+
+    } while (remaining > 0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/macosx/classes/sun/tools/attach/AttachProviderImpl.java	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2005, 2012, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 sun.tools.attach;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.VirtualMachineDescriptor;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.spi.AttachProvider;
+
+import java.io.IOException;
+
+/*
+ * An AttachProvider implementation for Bsd that uses a UNIX domain
+ * socket.
+ */
+public class AttachProviderImpl extends HotSpotAttachProvider {
+
+    // perf counter for the JVM version
+    private static final String JVM_VERSION = "java.property.java.vm.version";
+
+    public AttachProviderImpl() {
+    }
+
+    public String name() {
+        return "sun";
+    }
+
+    public String type() {
+        return "socket";
+    }
+
+    public VirtualMachine attachVirtualMachine(String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        checkAttachPermission();
+
+        // AttachNotSupportedException will be thrown if the target VM can be determined
+        // to be not attachable.
+        testAttachable(vmid);
+
+        return new VirtualMachineImpl(this, vmid);
+    }
+
+    public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd)
+        throws AttachNotSupportedException, IOException
+    {
+        if (vmd.provider() != this) {
+            throw new AttachNotSupportedException("provider mismatch");
+        }
+        // To avoid re-checking if the VM if attachable, we check if the descriptor
+        // is for a hotspot VM - these descriptors are created by the listVirtualMachines
+        // implementation which only returns a list of attachable VMs.
+        if (vmd instanceof HotSpotVirtualMachineDescriptor) {
+            assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable();
+            checkAttachPermission();
+            return new VirtualMachineImpl(this, vmd.id());
+        } else {
+            return attachVirtualMachine(vmd.id());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2005, 2014, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 sun.tools.attach;
+
+import com.sun.tools.attach.AttachOperationFailedException;
+import com.sun.tools.attach.AgentLoadException;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.spi.AttachProvider;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+
+/*
+ * Bsd implementation of HotSpotVirtualMachine
+ */
+public class VirtualMachineImpl extends HotSpotVirtualMachine {
+    // "tmpdir" is used as a global well-known location for the files
+    // .java_pid<pid>. and .attach_pid<pid>. It is important that this
+    // location is the same for all processes, otherwise the tools
+    // will not be able to find all Hotspot processes.
+    // This is intentionally not the same as java.io.tmpdir, since
+    // the latter can be changed by the user.
+    // Any changes to this needs to be synchronized with HotSpot.
+    private static final String tmpdir;
+
+    // The patch to the socket file created by the target VM
+    String path;
+
+    /**
+     * Attaches to the target VM
+     */
+    VirtualMachineImpl(AttachProvider provider, String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        super(provider, vmid);
+
+        // This provider only understands pids
+        int pid;
+        try {
+            pid = Integer.parseInt(vmid);
+        } catch (NumberFormatException x) {
+            throw new AttachNotSupportedException("Invalid process identifier");
+        }
+
+        // Find the socket file. If not found then we attempt to start the
+        // attach mechanism in the target VM by sending it a QUIT signal.
+        // Then we attempt to find the socket file again.
+        path = findSocketFile(pid);
+        if (path == null) {
+            File f = new File(tmpdir, ".attach_pid" + pid);
+            createAttachFile(f.getPath());
+            try {
+                sendQuitTo(pid);
+
+                // give the target VM time to start the attach mechanism
+                int i = 0;
+                long delay = 200;
+                int retries = (int)(attachTimeout() / delay);
+                do {
+                    try {
+                        Thread.sleep(delay);
+                    } catch (InterruptedException x) { }
+                    path = findSocketFile(pid);
+                    i++;
+                } while (i <= retries && path == null);
+                if (path == null) {
+                    throw new AttachNotSupportedException(
+                        "Unable to open socket file: target process not responding " +
+                        "or HotSpot VM not loaded");
+                }
+            } finally {
+                f.delete();
+            }
+        }
+
+        // Check that the file owner/permission to avoid attaching to
+        // bogus process
+        checkPermissions(path);
+
+        // Check that we can connect to the process
+        // - this ensures we throw the permission denied error now rather than
+        // later when we attempt to enqueue a command.
+        int s = socket();
+        try {
+            connect(s, path);
+        } finally {
+            close(s);
+        }
+    }
+
+    /**
+     * Detach from the target VM
+     */
+    public void detach() throws IOException {
+        synchronized (this) {
+            if (this.path != null) {
+                this.path = null;
+            }
+        }
+    }
+
+    // protocol version
+    private final static String PROTOCOL_VERSION = "1";
+
+    // known errors
+    private final static int ATTACH_ERROR_BADVERSION = 101;
+
+    /**
+     * Execute the given command in the target VM.
+     */
+    InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
+        assert args.length <= 3;                // includes null
+
+        // did we detach?
+        String p;
+        synchronized (this) {
+            if (this.path == null) {
+                throw new IOException("Detached from target VM");
+            }
+            p = this.path;
+        }
+
+        // create UNIX socket
+        int s = socket();
+
+        // connect to target VM
+        try {
+            connect(s, p);
+        } catch (IOException x) {
+            close(s);
+            throw x;
+        }
+
+        IOException ioe = null;
+
+        // connected - write request
+        // <ver> <cmd> <args...>
+        try {
+            writeString(s, PROTOCOL_VERSION);
+            writeString(s, cmd);
+
+            for (int i=0; i<3; i++) {
+                if (i < args.length && args[i] != null) {
+                    writeString(s, (String)args[i]);
+                } else {
+                    writeString(s, "");
+                }
+            }
+        } catch (IOException x) {
+            ioe = x;
+        }
+
+
+        // Create an input stream to read reply
+        SocketInputStream sis = new SocketInputStream(s);
+
+        // Read the command completion status
+        int completionStatus;
+        try {
+            completionStatus = readInt(sis);
+        } catch (IOException x) {
+            sis.close();
+            if (ioe != null) {
+                throw ioe;
+            } else {
+                throw x;
+            }
+        }
+
+        if (completionStatus != 0) {
+            // read from the stream and use that as the error message
+            String message = readErrorMessage(sis);
+            sis.close();
+
+            // In the event of a protocol mismatch then the target VM
+            // returns a known error so that we can throw a reasonable
+            // error.
+            if (completionStatus == ATTACH_ERROR_BADVERSION) {
+                throw new IOException("Protocol mismatch with target VM");
+            }
+
+            // Special-case the "load" command so that the right exception is
+            // thrown.
+            if (cmd.equals("load")) {
+                throw new AgentLoadException("Failed to load agent library");
+            } else {
+                if (message == null) {
+                    throw new AttachOperationFailedException("Command failed in target VM");
+                } else {
+                    throw new AttachOperationFailedException(message);
+                }
+            }
+        }
+
+        // Return the input stream so that the command output can be read
+        return sis;
+    }
+
+    /*
+     * InputStream for the socket connection to get target VM
+     */
+    private class SocketInputStream extends InputStream {
+        int s;
+
+        public SocketInputStream(int s) {
+            this.s = s;
+        }
+
+        public synchronized int read() throws IOException {
+            byte b[] = new byte[1];
+            int n = this.read(b, 0, 1);
+            if (n == 1) {
+                return b[0] & 0xff;
+            } else {
+                return -1;
+            }
+        }
+
+        public synchronized int read(byte[] bs, int off, int len) throws IOException {
+            if ((off < 0) || (off > bs.length) || (len < 0) ||
+                ((off + len) > bs.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0) {
+                return 0;
+            }
+
+            return VirtualMachineImpl.read(s, bs, off, len);
+        }
+
+        public void close() throws IOException {
+            VirtualMachineImpl.close(s);
+        }
+    }
+
+    // Return the socket file for the given process.
+    // Checks temp directory for .java_pid<pid>.
+    private String findSocketFile(int pid) {
+        String fn = ".java_pid" + pid;
+        File f = new File(tmpdir, fn);
+        return f.exists() ? f.getPath() : null;
+    }
+
+    /*
+     * Write/sends the given to the target VM. String is transmitted in
+     * UTF-8 encoding.
+     */
+    private void writeString(int fd, String s) throws IOException {
+        if (s.length() > 0) {
+            byte b[];
+            try {
+                b = s.getBytes("UTF-8");
+            } catch (java.io.UnsupportedEncodingException x) {
+                throw new InternalError();
+            }
+            VirtualMachineImpl.write(fd, b, 0, b.length);
+        }
+        byte b[] = new byte[1];
+        b[0] = 0;
+        write(fd, b, 0, 1);
+    }
+
+
+    //-- native methods
+
+    static native void sendQuitTo(int pid) throws IOException;
+
+    static native void checkPermissions(String path) throws IOException;
+
+    static native int socket() throws IOException;
+
+    static native void connect(int fd, String path) throws IOException;
+
+    static native void close(int fd) throws IOException;
+
+    static native int read(int fd, byte buf[], int off, int bufLen) throws IOException;
+
+    static native void write(int fd, byte buf[], int off, int bufLen) throws IOException;
+
+    static native void createAttachFile(String path);
+
+    static native String getTempDir();
+
+    static {
+        System.loadLibrary("attach");
+        tmpdir = getTempDir();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2005, 2014, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syslimits.h>
+#include <sys/un.h>
+#include <fcntl.h>
+
+#include "sun_tools_attach_VirtualMachineImpl.h"
+
+#define RESTARTABLE(_cmd, _result) do { \
+  do { \
+    _result = _cmd; \
+  } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    socket
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_socket
+  (JNIEnv *env, jclass cls)
+{
+    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (fd == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "socket");
+    }
+    return (jint)fd;
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    connect
+ * Signature: (ILjava/lang/String;)I
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connect
+  (JNIEnv *env, jclass cls, jint fd, jstring path)
+{
+    jboolean isCopy;
+    const char* p = GetStringPlatformChars(env, path, &isCopy);
+    if (p != NULL) {
+        struct sockaddr_un addr;
+        int err = 0;
+
+        memset(&addr, 0, sizeof(addr));
+        addr.sun_family = AF_UNIX;
+        /* strncpy is safe because addr.sun_path was zero-initialized before. */
+        strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1);
+
+        if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+            err = errno;
+        }
+
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, p);
+        }
+
+        /*
+         * If the connect failed then we throw the appropriate exception
+         * here (can't throw it before releasing the string as can't call
+         * JNI with pending exception)
+         */
+        if (err != 0) {
+            if (err == ENOENT) {
+                JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);
+            } else {
+                char* msg = strdup(strerror(err));
+                JNU_ThrowIOException(env, msg);
+                if (msg != NULL) {
+                    free(msg);
+                }
+            }
+        }
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    sendQuitTo
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo
+  (JNIEnv *env, jclass cls, jint pid)
+{
+    if (kill((pid_t)pid, SIGQUIT)) {
+        JNU_ThrowIOExceptionWithLastError(env, "kill");
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    checkPermissions
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
+  (JNIEnv *env, jclass cls, jstring path)
+{
+    jboolean isCopy;
+    const char* p = GetStringPlatformChars(env, path, &isCopy);
+    if (p != NULL) {
+        struct stat sb;
+        uid_t uid, gid;
+        int res;
+
+        /*
+         * Check that the path is owned by the effective uid/gid of this
+         * process. Also check that group/other access is not allowed.
+         */
+        uid = geteuid();
+        gid = getegid();
+
+        res = stat(p, &sb);
+        if (res != 0) {
+            /* save errno */
+            res = errno;
+        }
+
+        /* release p here before we throw an I/O exception */
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, p);
+        }
+
+        if (res == 0) {
+            if ( (sb.st_uid != uid) || (sb.st_gid != gid) ||
+                 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) {
+                JNU_ThrowIOException(env, "well-known file is not secure");
+            }
+        } else {
+            char* msg = strdup(strerror(res));
+            JNU_ThrowIOException(env, msg);
+            if (msg != NULL) {
+                free(msg);
+            }
+        }
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    close
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close
+  (JNIEnv *env, jclass cls, jint fd)
+{
+    int res;
+    RESTARTABLE(close(fd), res);
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    read
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_read
+  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)
+{
+    unsigned char buf[128];
+    size_t len = sizeof(buf);
+    ssize_t n;
+
+    size_t remaining = (size_t)(baLen - off);
+    if (len > remaining) {
+        len = remaining;
+    }
+
+    RESTARTABLE(read(fd, buf, len), n);
+    if (n == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "read");
+    } else {
+        if (n == 0) {
+            n = -1;     // EOF
+        } else {
+            (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf));
+        }
+    }
+    return n;
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    write
+ * Signature: (I[B)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_write
+  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen)
+{
+    size_t remaining = bufLen;
+    do {
+        unsigned char buf[128];
+        size_t len = sizeof(buf);
+        int n;
+
+        if (len > remaining) {
+            len = remaining;
+        }
+        (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf);
+
+        RESTARTABLE(write(fd, buf, len), n);
+        if (n > 0) {
+           off += n;
+           remaining -= n;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "write");
+            return;
+        }
+
+    } while (remaining > 0);
+}
+
+/*
+ * Class:     sun_tools_attach_BSDVirtualMachine
+ * Method:    createAttachFile
+ * Signature: (Ljava.lang.String;)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_createAttachFile(JNIEnv *env, jclass cls, jstring path)
+{
+    const char* _path;
+    jboolean isCopy;
+    int fd, rc;
+
+    _path = GetStringPlatformChars(env, path, &isCopy);
+    if (_path == NULL) {
+        JNU_ThrowIOException(env, "Must specify a path");
+        return;
+    }
+
+    RESTARTABLE(open(_path, O_CREAT | O_EXCL, S_IWUSR | S_IRUSR), fd);
+    if (fd == -1) {
+        /* release p here before we throw an I/O exception */
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, _path);
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "open");
+        return;
+    }
+
+    RESTARTABLE(chown(_path, geteuid(), getegid()), rc);
+
+    RESTARTABLE(close(fd), rc);
+
+    /* release p here */
+    if (isCopy) {
+        JNU_ReleaseStringPlatformChars(env, path, _path);
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_BSDVirtualMachine
+ * Method:    getTempDir
+ * Signature: (V)Ljava.lang.String;
+ */
+JNIEXPORT jstring JNICALL Java_sun_tools_attach_VirtualMachineImpl_getTempDir(JNIEnv *env, jclass cls)
+{
+    // This must be hard coded because it's the system's temporary
+    // directory not the java application's temp directory, ala java.io.tmpdir.
+
+#ifdef __APPLE__
+    // macosx has a secure per-user temporary directory
+    static char *temp_path = NULL;
+    char temp_path_storage[PATH_MAX];
+    if (temp_path == NULL) {
+        int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, temp_path_storage, PATH_MAX);
+        if (pathSize == 0 || pathSize > PATH_MAX) {
+            strlcpy(temp_path_storage, "/tmp", sizeof(temp_path_storage));
+        }
+        temp_path = temp_path_storage;
+    }
+    return JNU_NewStringPlatform(env, temp_path);
+#else /* __APPLE__ */
+    return (*env)->NewStringUTF(env, "/tmp");
+#endif /* __APPLE__ */
+}
--- a/src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider	Tue Aug 26 11:43:19 2014 -0700
+++ b/src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider	Tue Aug 26 14:35:33 2014 -0700
@@ -22,13 +22,4 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-# List all Sun provided attach providers here. If there
-# are providers that are only available on a particular OS
-# then prefix the line with #[OS] and they will automatically
-# uncommented by the build process.
-#
-#[solaris]sun.tools.attach.SolarisAttachProvider
-#[windows]sun.tools.attach.WindowsAttachProvider
-#[linux]sun.tools.attach.LinuxAttachProvider
-#[macosx]sun.tools.attach.BsdAttachProvider
-#[aix]sun.tools.attach.AixAttachProvider
+sun.tools.attach.AttachProviderImpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2005, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 sun.tools.attach;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.VirtualMachineDescriptor;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.spi.AttachProvider;
+import java.io.IOException;
+
+/*
+ * An AttachProvider implementation for Solaris that use the doors
+ * interface to the VM.
+ */
+public class AttachProviderImpl extends HotSpotAttachProvider {
+
+    public AttachProviderImpl() {
+    }
+
+    public String name() {
+        return "sun";
+    }
+
+    public String type() {
+        return "doors";
+    }
+
+    public VirtualMachine attachVirtualMachine(String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        checkAttachPermission();
+
+        // AttachNotSupportedException will be thrown if the target VM can be determined
+        // to be not attachable.
+        testAttachable(vmid);
+
+        return new VirtualMachineImpl(this, vmid);
+    }
+
+    public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd)
+        throws AttachNotSupportedException, IOException
+    {
+        if (vmd.provider() != this) {
+            throw new AttachNotSupportedException("provider mismatch");
+        }
+        // To avoid re-checking if the VM if attachable, we check if the descriptor
+        // is for a hotspot VM - these descriptors are created by the listVirtualMachines
+        // implementation which only returns a list of attachable VMs.
+        if (vmd instanceof HotSpotVirtualMachineDescriptor) {
+            assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable();
+            checkAttachPermission();
+            return new VirtualMachineImpl(this, vmd.id());
+        } else {
+            return attachVirtualMachine(vmd.id());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2005, 2014, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 sun.tools.attach;
+
+import com.sun.tools.attach.AttachOperationFailedException;
+import com.sun.tools.attach.AgentLoadException;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.spi.AttachProvider;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/*
+ * Solaris implementation of HotSpotVirtualMachine.
+ */
+public class VirtualMachineImpl extends HotSpotVirtualMachine {
+    // "/tmp" is used as a global well-known location for the files
+    // .java_pid<pid>. and .attach_pid<pid>. It is important that this
+    // location is the same for all processes, otherwise the tools
+    // will not be able to find all Hotspot processes.
+    // Any changes to this needs to be synchronized with HotSpot.
+    private static final String tmpdir = "/tmp";
+
+    // door descriptor;
+    private int fd = -1;
+
+    /**
+     * Attaches to the target VM
+     */
+    VirtualMachineImpl(AttachProvider provider, String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        super(provider, vmid);
+        // This provider only understands process-ids (pids).
+        int pid;
+        try {
+            pid = Integer.parseInt(vmid);
+        } catch (NumberFormatException x) {
+            throw new AttachNotSupportedException("invalid process identifier");
+        }
+
+        // Opens the door file to the target VM. If the file is not
+        // found it might mean that the attach mechanism isn't started in the
+        // target VM so we attempt to start it and retry.
+        try {
+            fd = openDoor(pid);
+        } catch (FileNotFoundException fnf1) {
+            File f = createAttachFile(pid);
+            try {
+                // kill -QUIT will tickle target VM to check for the
+                // attach file.
+                sigquit(pid);
+
+                // give the target VM time to start the attach mechanism
+                int i = 0;
+                long delay = 200;
+                int retries = (int)(attachTimeout() / delay);
+                do {
+                    try {
+                        Thread.sleep(delay);
+                    } catch (InterruptedException x) { }
+                    try {
+                        fd = openDoor(pid);
+                    } catch (FileNotFoundException fnf2) { }
+                    i++;
+                } while (i <= retries && fd == -1);
+                if (fd == -1) {
+                    throw new AttachNotSupportedException(
+                        "Unable to open door: target process not responding or " +
+                        "HotSpot VM not loaded");
+                }
+            } finally {
+                f.delete();
+            }
+        }
+        assert fd >= 0;
+    }
+
+    /**
+     * Detach from the target VM
+     */
+    public void detach() throws IOException {
+        synchronized (this) {
+            if (fd != -1) {
+                close(fd);
+                fd = -1;
+            }
+        }
+    }
+
+    /**
+     * Execute the given command in the target VM.
+     */
+    InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
+        assert args.length <= 3;                // includes null
+
+        // first check that we are still attached
+        int door;
+        synchronized (this) {
+            if (fd == -1) {
+                throw new IOException("Detached from target VM");
+            }
+            door = fd;
+        }
+
+        // enqueue the command via a door call
+        int s = enqueue(door, cmd, args);
+        assert s >= 0;                          // valid file descriptor
+
+        // The door call returns a file descriptor (one end of a socket pair).
+        // Create an input stream around it.
+        SocketInputStream sis = new SocketInputStream(s);
+
+        // Read the command completion status
+        int completionStatus;
+        try {
+            completionStatus = readInt(sis);
+        } catch (IOException ioe) {
+            sis.close();
+            throw ioe;
+        }
+
+        // If non-0 it means an error but we need to special-case the
+        // "load" command to ensure that the right exception is thrown.
+        if (completionStatus != 0) {
+            // read from the stream and use that as the error message
+            String message = readErrorMessage(sis);
+            sis.close();
+            if (cmd.equals("load")) {
+                throw new AgentLoadException("Failed to load agent library");
+            } else {
+                if (message == null) {
+                    throw new AttachOperationFailedException("Command failed in target VM");
+                } else {
+                    throw new AttachOperationFailedException(message);
+                }
+            }
+        }
+
+        // Return the input stream so that the command output can be read
+        return sis;
+    }
+
+    // InputStream over a socket
+    private class SocketInputStream extends InputStream {
+        int s;
+
+        public SocketInputStream(int s) {
+            this.s = s;
+        }
+
+        public synchronized int read() throws IOException {
+            byte b[] = new byte[1];
+            int n = this.read(b, 0, 1);
+            if (n == 1) {
+                return b[0] & 0xff;
+            } else {
+                return -1;
+            }
+        }
+
+        public synchronized int read(byte[] bs, int off, int len) throws IOException {
+            if ((off < 0) || (off > bs.length) || (len < 0) ||
+                ((off + len) > bs.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0)
+                return 0;
+
+            return VirtualMachineImpl.read(s, bs, off, len);
+        }
+
+        public void close() throws IOException {
+            VirtualMachineImpl.close(s);
+        }
+    }
+
+    // The door is attached to .java_pid<pid> in the temporary directory.
+    private int openDoor(int pid) throws IOException {
+        String path = tmpdir + "/.java_pid" + pid;;
+        fd = open(path);
+
+        // Check that the file owner/permission to avoid attaching to
+        // bogus process
+        try {
+            checkPermissions(path);
+        } catch (IOException ioe) {
+            close(fd);
+            throw ioe;
+        }
+        return fd;
+    }
+
+    // On Solaris/Linux a simple handshake is used to start the attach mechanism
+    // if not already started. The client creates a .attach_pid<pid> file in the
+    // target VM's working directory (or temporary directory), and the SIGQUIT
+    // handler checks for the file.
+    private File createAttachFile(int pid) throws IOException {
+        String fn = ".attach_pid" + pid;
+        String path = "/proc/" + pid + "/cwd/" + fn;
+        File f = new File(path);
+        try {
+            f.createNewFile();
+        } catch (IOException x) {
+            f = new File(tmpdir, fn);
+            f.createNewFile();
+        }
+        return f;
+    }
+
+    //-- native methods
+
+    static native int open(String path) throws IOException;
+
+    static native void close(int fd) throws IOException;
+
+    static native int read(int fd, byte buf[], int off, int buflen) throws IOException;
+
+    static native void checkPermissions(String path) throws IOException;
+
+    static native void sigquit(int pid) throws IOException;
+
+    // enqueue a command (and arguments) to the given door
+    static native int enqueue(int fd, String cmd, Object ... args)
+        throws IOException;
+
+    static {
+        System.loadLibrary("attach");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2005, 2014, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <door.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "jni.h"
+#include "jni_util.h"
+
+#include "sun_tools_attach_VirtualMachineImpl.h"
+
+#define RESTARTABLE(_cmd, _result) do { \
+  do { \
+    _result = _cmd; \
+  } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    open
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_open
+  (JNIEnv *env, jclass cls, jstring path)
+{
+    jboolean isCopy;
+    const char* p = GetStringPlatformChars(env, path, &isCopy);
+    if (p == NULL) {
+        return 0;
+    } else {
+        int fd;
+        int err = 0;
+
+        fd = open(p, O_RDWR);
+        if (fd == -1) {
+            err = errno;
+        }
+
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, p);
+        }
+
+        if (fd == -1) {
+            if (err == ENOENT) {
+                JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);
+            } else {
+                char* msg = strdup(strerror(err));
+                JNU_ThrowIOException(env, msg);
+                if (msg != NULL) {
+                    free(msg);
+                }
+            }
+        }
+        return fd;
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    checkPermissions
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
+  (JNIEnv *env, jclass cls, jstring path)
+{
+    jboolean isCopy;
+    const char* p = GetStringPlatformChars(env, path, &isCopy);
+    if (p != NULL) {
+        struct stat64 sb;
+        uid_t uid, gid;
+        int res;
+
+        /*
+         * Check that the path is owned by the effective uid/gid of this
+         * process. Also check that group/other access is not allowed.
+         */
+        uid = geteuid();
+        gid = getegid();
+
+        res = stat64(p, &sb);
+        if (res != 0) {
+            /* save errno */
+            res = errno;
+        }
+
+        /* release p here before we throw an I/O exception */
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, p);
+        }
+
+        if (res == 0) {
+            if ( (sb.st_uid != uid) || (sb.st_gid != gid) ||
+                 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) {
+                JNU_ThrowIOException(env, "well-known file is not secure");
+            }
+        } else {
+            char* msg = strdup(strerror(res));
+            JNU_ThrowIOException(env, msg);
+            if (msg != NULL) {
+                free(msg);
+            }
+        }
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    close
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close
+  (JNIEnv *env, jclass cls, jint fd)
+{
+    int ret;
+    RESTARTABLE(close(fd), ret);
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    read
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_read
+  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)
+{
+    unsigned char buf[128];
+    size_t len = sizeof(buf);
+    ssize_t n;
+
+    size_t remaining = (size_t)(baLen - off);
+    if (len > remaining) {
+        len = remaining;
+    }
+
+    RESTARTABLE(read(fd, buf, len), n);
+    if (n == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "read");
+    } else {
+        if (n == 0) {
+            n = -1;     // EOF
+        } else {
+            (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf));
+        }
+    }
+    return n;
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    sigquit
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sigquit
+  (JNIEnv *env, jclass cls, jint pid)
+{
+    if (kill((pid_t)pid, SIGQUIT) == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "kill");
+    }
+}
+
+/*
+ * A simple table to translate some known errors into reasonable
+ * error messages
+ */
+static struct {
+    jint err;
+    const char* msg;
+} const error_messages[] = {
+    { 100,      "Bad request" },
+    { 101,      "Protocol mismatch" },
+    { 102,      "Resource failure" },
+    { 103,      "Internal error" },
+    { 104,      "Permission denied" },
+};
+
+/*
+ * Lookup the given error code and return the appropriate
+ * message. If not found return NULL.
+ */
+static const char* translate_error(jint err) {
+    int table_size = sizeof(error_messages) / sizeof(error_messages[0]);
+    int i;
+
+    for (i=0; i<table_size; i++) {
+        if (err == error_messages[i].err) {
+            return error_messages[i].msg;
+        }
+    }
+    return NULL;
+}
+
+/*
+ * Current protocol version
+ */
+static const char* PROTOCOL_VERSION = "1";
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    enqueue
+ * Signature: (JILjava/lang/String;[Ljava/lang/Object;)V
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue
+  (JNIEnv *env, jclass cls, jint fd, jstring cmd, jobjectArray args)
+{
+    jint arg_count, i;
+    size_t size;
+    jboolean isCopy;
+    door_arg_t door_args;
+    char res_buffer[128];
+    jint result = -1;
+    int rc;
+    const char* cstr;
+    char* buf;
+
+    /*
+     * First we get the command string and create the start of the
+     * argument string to send to the target VM:
+     * <ver>\0<cmd>\0
+     */
+    cstr = JNU_GetStringPlatformChars(env, cmd, &isCopy);
+    if (cstr == NULL) {
+        return -1;              /* pending exception */
+    }
+    size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2;
+    buf = (char*)malloc(size);
+    if (buf != NULL) {
+        char* pos = buf;
+        strcpy(buf, PROTOCOL_VERSION);
+        pos += strlen(PROTOCOL_VERSION)+1;
+        strcpy(pos, cstr);
+    }
+    if (isCopy) {
+        JNU_ReleaseStringPlatformChars(env, cmd, cstr);
+    }
+    if (buf == NULL) {
+        JNU_ThrowOutOfMemoryError(env, "malloc failed");
+        return -1;
+    }
+
+    /*
+     * Next we iterate over the arguments and extend the buffer
+     * to include them.
+     */
+    arg_count = (*env)->GetArrayLength(env, args);
+
+    for (i=0; i<arg_count; i++) {
+        jobject obj = (*env)->GetObjectArrayElement(env, args, i);
+        if (obj != NULL) {
+            cstr = JNU_GetStringPlatformChars(env, obj, &isCopy);
+            if (cstr != NULL) {
+                size_t len = strlen(cstr);
+                char* newbuf = (char*)realloc(buf, size+len+1);
+                if (newbuf != NULL) {
+                    buf = newbuf;
+                    strcpy(buf+size, cstr);
+                    size += len+1;
+                }
+                if (isCopy) {
+                    JNU_ReleaseStringPlatformChars(env, obj, cstr);
+                }
+                if (newbuf == NULL) {
+                    free(buf);
+                    JNU_ThrowOutOfMemoryError(env, "realloc failed");
+                    return -1;
+                }
+            }
+        }
+        if ((*env)->ExceptionOccurred(env)) {
+            free(buf);
+            return -1;
+        }
+    }
+
+    /*
+     * The arguments to the door function are in 'buf' so we now
+     * do the door call
+     */
+    door_args.data_ptr = buf;
+    door_args.data_size = size;
+    door_args.desc_ptr = NULL;
+    door_args.desc_num = 0;
+    door_args.rbuf = (char*)&res_buffer;
+    door_args.rsize = sizeof(res_buffer);
+
+    RESTARTABLE(door_call(fd, &door_args), rc);
+
+    /*
+     * door_call failed
+     */
+    if (rc == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "door_call");
+    } else {
+        /*
+         * door_call succeeded but the call didn't return the the expected jint.
+         */
+        if (door_args.data_size < sizeof(jint)) {
+            JNU_ThrowIOException(env, "Enqueue error - reason unknown as result is truncated!");
+        } else {
+            jint* res = (jint*)(door_args.data_ptr);
+            if (*res != JNI_OK) {
+                const char* msg = translate_error(*res);
+                char buf[255];
+                if (msg == NULL) {
+                    sprintf(buf, "Unable to enqueue command to target VM: %d", *res);
+                } else {
+                    sprintf(buf, "Unable to enqueue command to target VM: %s", msg);
+                }
+                JNU_ThrowIOException(env, buf);
+            } else {
+                /*
+                 * The door call should return a file descriptor to one end of
+                 * a socket pair
+                 */
+                if ((door_args.desc_ptr != NULL) &&
+                    (door_args.desc_num == 1) &&
+                    (door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) {
+                    result = door_args.desc_ptr->d_data.d_desc.d_descriptor;
+                } else {
+                    JNU_ThrowIOException(env, "Reply from enqueue missing descriptor!");
+                }
+            }
+        }
+    }
+
+    free(buf);
+    return result;
+}
--- a/src/jdk.attach/unix/classes/sun/tools/attach/BsdAttachProvider.java	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2005, 2012, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.tools.attach;
-
-import com.sun.tools.attach.VirtualMachine;
-import com.sun.tools.attach.VirtualMachineDescriptor;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.spi.AttachProvider;
-
-import java.io.IOException;
-
-/*
- * An AttachProvider implementation for Bsd that uses a UNIX domain
- * socket.
- */
-public class BsdAttachProvider extends HotSpotAttachProvider {
-
-    // perf counter for the JVM version
-    private static final String JVM_VERSION = "java.property.java.vm.version";
-
-    public BsdAttachProvider() {
-    }
-
-    public String name() {
-        return "sun";
-    }
-
-    public String type() {
-        return "socket";
-    }
-
-    public VirtualMachine attachVirtualMachine(String vmid)
-        throws AttachNotSupportedException, IOException
-    {
-        checkAttachPermission();
-
-        // AttachNotSupportedException will be thrown if the target VM can be determined
-        // to be not attachable.
-        testAttachable(vmid);
-
-        return new BsdVirtualMachine(this, vmid);
-    }
-
-    public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd)
-        throws AttachNotSupportedException, IOException
-    {
-        if (vmd.provider() != this) {
-            throw new AttachNotSupportedException("provider mismatch");
-        }
-        // To avoid re-checking if the VM if attachable, we check if the descriptor
-        // is for a hotspot VM - these descriptors are created by the listVirtualMachines
-        // implementation which only returns a list of attachable VMs.
-        if (vmd instanceof HotSpotVirtualMachineDescriptor) {
-            assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable();
-            checkAttachPermission();
-            return new BsdVirtualMachine(this, vmd.id());
-        } else {
-            return attachVirtualMachine(vmd.id());
-        }
-    }
-
-}
--- a/src/jdk.attach/unix/classes/sun/tools/attach/BsdVirtualMachine.java	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,310 +0,0 @@
-/*
- * Copyright (c) 2005, 2014, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.tools.attach;
-
-import com.sun.tools.attach.AttachOperationFailedException;
-import com.sun.tools.attach.AgentLoadException;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.spi.AttachProvider;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.File;
-
-/*
- * Bsd implementation of HotSpotVirtualMachine
- */
-public class BsdVirtualMachine extends HotSpotVirtualMachine {
-    // "tmpdir" is used as a global well-known location for the files
-    // .java_pid<pid>. and .attach_pid<pid>. It is important that this
-    // location is the same for all processes, otherwise the tools
-    // will not be able to find all Hotspot processes.
-    // This is intentionally not the same as java.io.tmpdir, since
-    // the latter can be changed by the user.
-    // Any changes to this needs to be synchronized with HotSpot.
-    private static final String tmpdir;
-
-    // The patch to the socket file created by the target VM
-    String path;
-
-    /**
-     * Attaches to the target VM
-     */
-    BsdVirtualMachine(AttachProvider provider, String vmid)
-        throws AttachNotSupportedException, IOException
-    {
-        super(provider, vmid);
-
-        // This provider only understands pids
-        int pid;
-        try {
-            pid = Integer.parseInt(vmid);
-        } catch (NumberFormatException x) {
-            throw new AttachNotSupportedException("Invalid process identifier");
-        }
-
-        // Find the socket file. If not found then we attempt to start the
-        // attach mechanism in the target VM by sending it a QUIT signal.
-        // Then we attempt to find the socket file again.
-        path = findSocketFile(pid);
-        if (path == null) {
-            File f = new File(tmpdir, ".attach_pid" + pid);
-            createAttachFile(f.getPath());
-            try {
-                sendQuitTo(pid);
-
-                // give the target VM time to start the attach mechanism
-                int i = 0;
-                long delay = 200;
-                int retries = (int)(attachTimeout() / delay);
-                do {
-                    try {
-                        Thread.sleep(delay);
-                    } catch (InterruptedException x) { }
-                    path = findSocketFile(pid);
-                    i++;
-                } while (i <= retries && path == null);
-                if (path == null) {
-                    throw new AttachNotSupportedException(
-                        "Unable to open socket file: target process not responding " +
-                        "or HotSpot VM not loaded");
-                }
-            } finally {
-                f.delete();
-            }
-        }
-
-        // Check that the file owner/permission to avoid attaching to
-        // bogus process
-        checkPermissions(path);
-
-        // Check that we can connect to the process
-        // - this ensures we throw the permission denied error now rather than
-        // later when we attempt to enqueue a command.
-        int s = socket();
-        try {
-            connect(s, path);
-        } finally {
-            close(s);
-        }
-    }
-
-    /**
-     * Detach from the target VM
-     */
-    public void detach() throws IOException {
-        synchronized (this) {
-            if (this.path != null) {
-                this.path = null;
-            }
-        }
-    }
-
-    // protocol version
-    private final static String PROTOCOL_VERSION = "1";
-
-    // known errors
-    private final static int ATTACH_ERROR_BADVERSION = 101;
-
-    /**
-     * Execute the given command in the target VM.
-     */
-    InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
-        assert args.length <= 3;                // includes null
-
-        // did we detach?
-        String p;
-        synchronized (this) {
-            if (this.path == null) {
-                throw new IOException("Detached from target VM");
-            }
-            p = this.path;
-        }
-
-        // create UNIX socket
-        int s = socket();
-
-        // connect to target VM
-        try {
-            connect(s, p);
-        } catch (IOException x) {
-            close(s);
-            throw x;
-        }
-
-        IOException ioe = null;
-
-        // connected - write request
-        // <ver> <cmd> <args...>
-        try {
-            writeString(s, PROTOCOL_VERSION);
-            writeString(s, cmd);
-
-            for (int i=0; i<3; i++) {
-                if (i < args.length && args[i] != null) {
-                    writeString(s, (String)args[i]);
-                } else {
-                    writeString(s, "");
-                }
-            }
-        } catch (IOException x) {
-            ioe = x;
-        }
-
-
-        // Create an input stream to read reply
-        SocketInputStream sis = new SocketInputStream(s);
-
-        // Read the command completion status
-        int completionStatus;
-        try {
-            completionStatus = readInt(sis);
-        } catch (IOException x) {
-            sis.close();
-            if (ioe != null) {
-                throw ioe;
-            } else {
-                throw x;
-            }
-        }
-
-        if (completionStatus != 0) {
-            // read from the stream and use that as the error message
-            String message = readErrorMessage(sis);
-            sis.close();
-
-            // In the event of a protocol mismatch then the target VM
-            // returns a known error so that we can throw a reasonable
-            // error.
-            if (completionStatus == ATTACH_ERROR_BADVERSION) {
-                throw new IOException("Protocol mismatch with target VM");
-            }
-
-            // Special-case the "load" command so that the right exception is
-            // thrown.
-            if (cmd.equals("load")) {
-                throw new AgentLoadException("Failed to load agent library");
-            } else {
-                if (message == null) {
-                    throw new AttachOperationFailedException("Command failed in target VM");
-                } else {
-                    throw new AttachOperationFailedException(message);
-                }
-            }
-        }
-
-        // Return the input stream so that the command output can be read
-        return sis;
-    }
-
-    /*
-     * InputStream for the socket connection to get target VM
-     */
-    private class SocketInputStream extends InputStream {
-        int s;
-
-        public SocketInputStream(int s) {
-            this.s = s;
-        }
-
-        public synchronized int read() throws IOException {
-            byte b[] = new byte[1];
-            int n = this.read(b, 0, 1);
-            if (n == 1) {
-                return b[0] & 0xff;
-            } else {
-                return -1;
-            }
-        }
-
-        public synchronized int read(byte[] bs, int off, int len) throws IOException {
-            if ((off < 0) || (off > bs.length) || (len < 0) ||
-                ((off + len) > bs.length) || ((off + len) < 0)) {
-                throw new IndexOutOfBoundsException();
-            } else if (len == 0) {
-                return 0;
-            }
-
-            return BsdVirtualMachine.read(s, bs, off, len);
-        }
-
-        public void close() throws IOException {
-            BsdVirtualMachine.close(s);
-        }
-    }
-
-    // Return the socket file for the given process.
-    // Checks temp directory for .java_pid<pid>.
-    private String findSocketFile(int pid) {
-        String fn = ".java_pid" + pid;
-        File f = new File(tmpdir, fn);
-        return f.exists() ? f.getPath() : null;
-    }
-
-    /*
-     * Write/sends the given to the target VM. String is transmitted in
-     * UTF-8 encoding.
-     */
-    private void writeString(int fd, String s) throws IOException {
-        if (s.length() > 0) {
-            byte b[];
-            try {
-                b = s.getBytes("UTF-8");
-            } catch (java.io.UnsupportedEncodingException x) {
-                throw new InternalError();
-            }
-            BsdVirtualMachine.write(fd, b, 0, b.length);
-        }
-        byte b[] = new byte[1];
-        b[0] = 0;
-        write(fd, b, 0, 1);
-    }
-
-
-    //-- native methods
-
-    static native void sendQuitTo(int pid) throws IOException;
-
-    static native void checkPermissions(String path) throws IOException;
-
-    static native int socket() throws IOException;
-
-    static native void connect(int fd, String path) throws IOException;
-
-    static native void close(int fd) throws IOException;
-
-    static native int read(int fd, byte buf[], int off, int bufLen) throws IOException;
-
-    static native void write(int fd, byte buf[], int off, int bufLen) throws IOException;
-
-    static native void createAttachFile(String path);
-
-    static native String getTempDir();
-
-    static {
-        System.loadLibrary("attach");
-        tmpdir = getTempDir();
-    }
-}
--- a/src/jdk.attach/unix/classes/sun/tools/attach/LinuxAttachProvider.java	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2005, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.tools.attach;
-
-import com.sun.tools.attach.VirtualMachine;
-import com.sun.tools.attach.VirtualMachineDescriptor;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.spi.AttachProvider;
-
-import java.io.IOException;
-
-/*
- * An AttachProvider implementation for Linux that uses a UNIX domain
- * socket.
- */
-public class LinuxAttachProvider extends HotSpotAttachProvider {
-
-    // perf counter for the JVM version
-    private static final String JVM_VERSION = "java.property.java.vm.version";
-
-    public LinuxAttachProvider() {
-    }
-
-    public String name() {
-        return "sun";
-    }
-
-    public String type() {
-        return "socket";
-    }
-
-    public VirtualMachine attachVirtualMachine(String vmid)
-        throws AttachNotSupportedException, IOException
-    {
-        checkAttachPermission();
-
-        // AttachNotSupportedException will be thrown if the target VM can be determined
-        // to be not attachable.
-        testAttachable(vmid);
-
-        return new LinuxVirtualMachine(this, vmid);
-    }
-
-    public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd)
-        throws AttachNotSupportedException, IOException
-    {
-        if (vmd.provider() != this) {
-            throw new AttachNotSupportedException("provider mismatch");
-        }
-        // To avoid re-checking if the VM if attachable, we check if the descriptor
-        // is for a hotspot VM - these descriptors are created by the listVirtualMachines
-        // implementation which only returns a list of attachable VMs.
-        if (vmd instanceof HotSpotVirtualMachineDescriptor) {
-            assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable();
-            checkAttachPermission();
-            return new LinuxVirtualMachine(this, vmd.id());
-        } else {
-            return attachVirtualMachine(vmd.id());
-        }
-    }
-
-}
--- a/src/jdk.attach/unix/classes/sun/tools/attach/LinuxVirtualMachine.java	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,345 +0,0 @@
-/*
- * Copyright (c) 2005, 2014, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.tools.attach;
-
-import com.sun.tools.attach.AttachOperationFailedException;
-import com.sun.tools.attach.AgentLoadException;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.spi.AttachProvider;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.File;
-
-/*
- * Linux implementation of HotSpotVirtualMachine
- */
-public class LinuxVirtualMachine extends HotSpotVirtualMachine {
-    // "/tmp" is used as a global well-known location for the files
-    // .java_pid<pid>. and .attach_pid<pid>. It is important that this
-    // location is the same for all processes, otherwise the tools
-    // will not be able to find all Hotspot processes.
-    // Any changes to this needs to be synchronized with HotSpot.
-    private static final String tmpdir = "/tmp";
-
-    // Indicates if this machine uses the old LinuxThreads
-    static boolean isLinuxThreads;
-
-    // The patch to the socket file created by the target VM
-    String path;
-
-    /**
-     * Attaches to the target VM
-     */
-    LinuxVirtualMachine(AttachProvider provider, String vmid)
-        throws AttachNotSupportedException, IOException
-    {
-        super(provider, vmid);
-
-        // This provider only understands pids
-        int pid;
-        try {
-            pid = Integer.parseInt(vmid);
-        } catch (NumberFormatException x) {
-            throw new AttachNotSupportedException("Invalid process identifier");
-        }
-
-        // Find the socket file. If not found then we attempt to start the
-        // attach mechanism in the target VM by sending it a QUIT signal.
-        // Then we attempt to find the socket file again.
-        path = findSocketFile(pid);
-        if (path == null) {
-            File f = createAttachFile(pid);
-            try {
-                // On LinuxThreads each thread is a process and we don't have the
-                // pid of the VMThread which has SIGQUIT unblocked. To workaround
-                // this we get the pid of the "manager thread" that is created
-                // by the first call to pthread_create. This is parent of all
-                // threads (except the initial thread).
-                if (isLinuxThreads) {
-                    int mpid;
-                    try {
-                        mpid = getLinuxThreadsManager(pid);
-                    } catch (IOException x) {
-                        throw new AttachNotSupportedException(x.getMessage());
-                    }
-                    assert(mpid >= 1);
-                    sendQuitToChildrenOf(mpid);
-                } else {
-                    sendQuitTo(pid);
-                }
-
-                // give the target VM time to start the attach mechanism
-                int i = 0;
-                long delay = 200;
-                int retries = (int)(attachTimeout() / delay);
-                do {
-                    try {
-                        Thread.sleep(delay);
-                    } catch (InterruptedException x) { }
-                    path = findSocketFile(pid);
-                    i++;
-                } while (i <= retries && path == null);
-                if (path == null) {
-                    throw new AttachNotSupportedException(
-                        "Unable to open socket file: target process not responding " +
-                        "or HotSpot VM not loaded");
-                }
-            } finally {
-                f.delete();
-            }
-        }
-
-        // Check that the file owner/permission to avoid attaching to
-        // bogus process
-        checkPermissions(path);
-
-        // Check that we can connect to the process
-        // - this ensures we throw the permission denied error now rather than
-        // later when we attempt to enqueue a command.
-        int s = socket();
-        try {
-            connect(s, path);
-        } finally {
-            close(s);
-        }
-    }
-
-    /**
-     * Detach from the target VM
-     */
-    public void detach() throws IOException {
-        synchronized (this) {
-            if (this.path != null) {
-                this.path = null;
-            }
-        }
-    }
-
-    // protocol version
-    private final static String PROTOCOL_VERSION = "1";
-
-    // known errors
-    private final static int ATTACH_ERROR_BADVERSION = 101;
-
-    /**
-     * Execute the given command in the target VM.
-     */
-    InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
-        assert args.length <= 3;                // includes null
-
-        // did we detach?
-        String p;
-        synchronized (this) {
-            if (this.path == null) {
-                throw new IOException("Detached from target VM");
-            }
-            p = this.path;
-        }
-
-        // create UNIX socket
-        int s = socket();
-
-        // connect to target VM
-        try {
-            connect(s, p);
-        } catch (IOException x) {
-            close(s);
-            throw x;
-        }
-
-        IOException ioe = null;
-
-        // connected - write request
-        // <ver> <cmd> <args...>
-        try {
-            writeString(s, PROTOCOL_VERSION);
-            writeString(s, cmd);
-
-            for (int i=0; i<3; i++) {
-                if (i < args.length && args[i] != null) {
-                    writeString(s, (String)args[i]);
-                } else {
-                    writeString(s, "");
-                }
-            }
-        } catch (IOException x) {
-            ioe = x;
-        }
-
-
-        // Create an input stream to read reply
-        SocketInputStream sis = new SocketInputStream(s);
-
-        // Read the command completion status
-        int completionStatus;
-        try {
-            completionStatus = readInt(sis);
-        } catch (IOException x) {
-            sis.close();
-            if (ioe != null) {
-                throw ioe;
-            } else {
-                throw x;
-            }
-        }
-
-        if (completionStatus != 0) {
-            // read from the stream and use that as the error message
-            String message = readErrorMessage(sis);
-            sis.close();
-
-            // In the event of a protocol mismatch then the target VM
-            // returns a known error so that we can throw a reasonable
-            // error.
-            if (completionStatus == ATTACH_ERROR_BADVERSION) {
-                throw new IOException("Protocol mismatch with target VM");
-            }
-
-            // Special-case the "load" command so that the right exception is
-            // thrown.
-            if (cmd.equals("load")) {
-                throw new AgentLoadException("Failed to load agent library");
-            } else {
-                if (message == null) {
-                    throw new AttachOperationFailedException("Command failed in target VM");
-                } else {
-                    throw new AttachOperationFailedException(message);
-                }
-            }
-        }
-
-        // Return the input stream so that the command output can be read
-        return sis;
-    }
-
-    /*
-     * InputStream for the socket connection to get target VM
-     */
-    private class SocketInputStream extends InputStream {
-        int s;
-
-        public SocketInputStream(int s) {
-            this.s = s;
-        }
-
-        public synchronized int read() throws IOException {
-            byte b[] = new byte[1];
-            int n = this.read(b, 0, 1);
-            if (n == 1) {
-                return b[0] & 0xff;
-            } else {
-                return -1;
-            }
-        }
-
-        public synchronized int read(byte[] bs, int off, int len) throws IOException {
-            if ((off < 0) || (off > bs.length) || (len < 0) ||
-                ((off + len) > bs.length) || ((off + len) < 0)) {
-                throw new IndexOutOfBoundsException();
-            } else if (len == 0)
-                return 0;
-
-            return LinuxVirtualMachine.read(s, bs, off, len);
-        }
-
-        public void close() throws IOException {
-            LinuxVirtualMachine.close(s);
-        }
-    }
-
-    // Return the socket file for the given process.
-    private String findSocketFile(int pid) {
-        File f = new File(tmpdir, ".java_pid" + pid);
-        if (!f.exists()) {
-            return null;
-        }
-        return f.getPath();
-    }
-
-    // On Solaris/Linux a simple handshake is used to start the attach mechanism
-    // if not already started. The client creates a .attach_pid<pid> file in the
-    // target VM's working directory (or temp directory), and the SIGQUIT handler
-    // checks for the file.
-    private File createAttachFile(int pid) throws IOException {
-        String fn = ".attach_pid" + pid;
-        String path = "/proc/" + pid + "/cwd/" + fn;
-        File f = new File(path);
-        try {
-            f.createNewFile();
-        } catch (IOException x) {
-            f = new File(tmpdir, fn);
-            f.createNewFile();
-        }
-        return f;
-    }
-
-    /*
-     * Write/sends the given to the target VM. String is transmitted in
-     * UTF-8 encoding.
-     */
-    private void writeString(int fd, String s) throws IOException {
-        if (s.length() > 0) {
-            byte b[];
-            try {
-                b = s.getBytes("UTF-8");
-            } catch (java.io.UnsupportedEncodingException x) {
-                throw new InternalError(x);
-            }
-            LinuxVirtualMachine.write(fd, b, 0, b.length);
-        }
-        byte b[] = new byte[1];
-        b[0] = 0;
-        write(fd, b, 0, 1);
-    }
-
-
-    //-- native methods
-
-    static native boolean isLinuxThreads();
-
-    static native int getLinuxThreadsManager(int pid) throws IOException;
-
-    static native void sendQuitToChildrenOf(int pid) throws IOException;
-
-    static native void sendQuitTo(int pid) throws IOException;
-
-    static native void checkPermissions(String path) throws IOException;
-
-    static native int socket() throws IOException;
-
-    static native void connect(int fd, String path) throws IOException;
-
-    static native void close(int fd) throws IOException;
-
-    static native int read(int fd, byte buf[], int off, int bufLen) throws IOException;
-
-    static native void write(int fd, byte buf[], int off, int bufLen) throws IOException;
-
-    static {
-        System.loadLibrary("attach");
-        isLinuxThreads = isLinuxThreads();
-    }
-}
--- a/src/jdk.attach/unix/classes/sun/tools/attach/SolarisAttachProvider.java	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2005, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.tools.attach;
-
-import com.sun.tools.attach.VirtualMachine;
-import com.sun.tools.attach.VirtualMachineDescriptor;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.spi.AttachProvider;
-import java.io.IOException;
-
-/*
- * An AttachProvider implementation for Solaris that use the doors
- * interface to the VM.
- */
-public class SolarisAttachProvider extends HotSpotAttachProvider {
-
-    public SolarisAttachProvider() {
-    }
-
-    public String name() {
-        return "sun";
-    }
-
-    public String type() {
-        return "doors";
-    }
-
-    public VirtualMachine attachVirtualMachine(String vmid)
-        throws AttachNotSupportedException, IOException
-    {
-        checkAttachPermission();
-
-        // AttachNotSupportedException will be thrown if the target VM can be determined
-        // to be not attachable.
-        testAttachable(vmid);
-
-        return new SolarisVirtualMachine(this, vmid);
-    }
-
-    public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd)
-        throws AttachNotSupportedException, IOException
-    {
-        if (vmd.provider() != this) {
-            throw new AttachNotSupportedException("provider mismatch");
-        }
-        // To avoid re-checking if the VM if attachable, we check if the descriptor
-        // is for a hotspot VM - these descriptors are created by the listVirtualMachines
-        // implementation which only returns a list of attachable VMs.
-        if (vmd instanceof HotSpotVirtualMachineDescriptor) {
-            assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable();
-            checkAttachPermission();
-            return new SolarisVirtualMachine(this, vmd.id());
-        } else {
-            return attachVirtualMachine(vmd.id());
-        }
-    }
-
-}
--- a/src/jdk.attach/unix/classes/sun/tools/attach/SolarisVirtualMachine.java	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,253 +0,0 @@
-/*
- * Copyright (c) 2005, 2014, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.tools.attach;
-
-import com.sun.tools.attach.AttachOperationFailedException;
-import com.sun.tools.attach.AgentLoadException;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.spi.AttachProvider;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.File;
-import java.io.FileNotFoundException;
-
-/*
- * Solaris implementation of HotSpotVirtualMachine.
- */
-public class SolarisVirtualMachine extends HotSpotVirtualMachine {
-    // "/tmp" is used as a global well-known location for the files
-    // .java_pid<pid>. and .attach_pid<pid>. It is important that this
-    // location is the same for all processes, otherwise the tools
-    // will not be able to find all Hotspot processes.
-    // Any changes to this needs to be synchronized with HotSpot.
-    private static final String tmpdir = "/tmp";
-
-    // door descriptor;
-    private int fd = -1;
-
-    /**
-     * Attaches to the target VM
-     */
-    SolarisVirtualMachine(AttachProvider provider, String vmid)
-        throws AttachNotSupportedException, IOException
-    {
-        super(provider, vmid);
-        // This provider only understands process-ids (pids).
-        int pid;
-        try {
-            pid = Integer.parseInt(vmid);
-        } catch (NumberFormatException x) {
-            throw new AttachNotSupportedException("invalid process identifier");
-        }
-
-        // Opens the door file to the target VM. If the file is not
-        // found it might mean that the attach mechanism isn't started in the
-        // target VM so we attempt to start it and retry.
-        try {
-            fd = openDoor(pid);
-        } catch (FileNotFoundException fnf1) {
-            File f = createAttachFile(pid);
-            try {
-                // kill -QUIT will tickle target VM to check for the
-                // attach file.
-                sigquit(pid);
-
-                // give the target VM time to start the attach mechanism
-                int i = 0;
-                long delay = 200;
-                int retries = (int)(attachTimeout() / delay);
-                do {
-                    try {
-                        Thread.sleep(delay);
-                    } catch (InterruptedException x) { }
-                    try {
-                        fd = openDoor(pid);
-                    } catch (FileNotFoundException fnf2) { }
-                    i++;
-                } while (i <= retries && fd == -1);
-                if (fd == -1) {
-                    throw new AttachNotSupportedException(
-                        "Unable to open door: target process not responding or " +
-                        "HotSpot VM not loaded");
-                }
-            } finally {
-                f.delete();
-            }
-        }
-        assert fd >= 0;
-    }
-
-    /**
-     * Detach from the target VM
-     */
-    public void detach() throws IOException {
-        synchronized (this) {
-            if (fd != -1) {
-                close(fd);
-                fd = -1;
-            }
-        }
-    }
-
-    /**
-     * Execute the given command in the target VM.
-     */
-    InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
-        assert args.length <= 3;                // includes null
-
-        // first check that we are still attached
-        int door;
-        synchronized (this) {
-            if (fd == -1) {
-                throw new IOException("Detached from target VM");
-            }
-            door = fd;
-        }
-
-        // enqueue the command via a door call
-        int s = enqueue(door, cmd, args);
-        assert s >= 0;                          // valid file descriptor
-
-        // The door call returns a file descriptor (one end of a socket pair).
-        // Create an input stream around it.
-        SocketInputStream sis = new SocketInputStream(s);
-
-        // Read the command completion status
-        int completionStatus;
-        try {
-            completionStatus = readInt(sis);
-        } catch (IOException ioe) {
-            sis.close();
-            throw ioe;
-        }
-
-        // If non-0 it means an error but we need to special-case the
-        // "load" command to ensure that the right exception is thrown.
-        if (completionStatus != 0) {
-            // read from the stream and use that as the error message
-            String message = readErrorMessage(sis);
-            sis.close();
-            if (cmd.equals("load")) {
-                throw new AgentLoadException("Failed to load agent library");
-            } else {
-                if (message == null) {
-                    throw new AttachOperationFailedException("Command failed in target VM");
-                } else {
-                    throw new AttachOperationFailedException(message);
-                }
-            }
-        }
-
-        // Return the input stream so that the command output can be read
-        return sis;
-    }
-
-    // InputStream over a socket
-    private class SocketInputStream extends InputStream {
-        int s;
-
-        public SocketInputStream(int s) {
-            this.s = s;
-        }
-
-        public synchronized int read() throws IOException {
-            byte b[] = new byte[1];
-            int n = this.read(b, 0, 1);
-            if (n == 1) {
-                return b[0] & 0xff;
-            } else {
-                return -1;
-            }
-        }
-
-        public synchronized int read(byte[] bs, int off, int len) throws IOException {
-            if ((off < 0) || (off > bs.length) || (len < 0) ||
-                ((off + len) > bs.length) || ((off + len) < 0)) {
-                throw new IndexOutOfBoundsException();
-            } else if (len == 0)
-                return 0;
-
-            return SolarisVirtualMachine.read(s, bs, off, len);
-        }
-
-        public void close() throws IOException {
-            SolarisVirtualMachine.close(s);
-        }
-    }
-
-    // The door is attached to .java_pid<pid> in the temporary directory.
-    private int openDoor(int pid) throws IOException {
-        String path = tmpdir + "/.java_pid" + pid;;
-        fd = open(path);
-
-        // Check that the file owner/permission to avoid attaching to
-        // bogus process
-        try {
-            checkPermissions(path);
-        } catch (IOException ioe) {
-            close(fd);
-            throw ioe;
-        }
-        return fd;
-    }
-
-    // On Solaris/Linux a simple handshake is used to start the attach mechanism
-    // if not already started. The client creates a .attach_pid<pid> file in the
-    // target VM's working directory (or temporary directory), and the SIGQUIT
-    // handler checks for the file.
-    private File createAttachFile(int pid) throws IOException {
-        String fn = ".attach_pid" + pid;
-        String path = "/proc/" + pid + "/cwd/" + fn;
-        File f = new File(path);
-        try {
-            f.createNewFile();
-        } catch (IOException x) {
-            f = new File(tmpdir, fn);
-            f.createNewFile();
-        }
-        return f;
-    }
-
-    //-- native methods
-
-    static native int open(String path) throws IOException;
-
-    static native void close(int fd) throws IOException;
-
-    static native int read(int fd, byte buf[], int off, int buflen) throws IOException;
-
-    static native void checkPermissions(String path) throws IOException;
-
-    static native void sigquit(int pid) throws IOException;
-
-    // enqueue a command (and arguments) to the given door
-    static native int enqueue(int fd, String cmd, Object ... args)
-        throws IOException;
-
-    static {
-        System.loadLibrary("attach");
-    }
-}
--- a/src/jdk.attach/unix/native/libattach/BsdVirtualMachine.c	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,309 +0,0 @@
-/*
- * Copyright (c) 2005, 2014, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/syslimits.h>
-#include <sys/un.h>
-#include <fcntl.h>
-
-#include "sun_tools_attach_BsdVirtualMachine.h"
-
-#define RESTARTABLE(_cmd, _result) do { \
-  do { \
-    _result = _cmd; \
-  } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
-/*
- * Class:     sun_tools_attach_BsdVirtualMachine
- * Method:    socket
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_BsdVirtualMachine_socket
-  (JNIEnv *env, jclass cls)
-{
-    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
-    if (fd == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "socket");
-    }
-    return (jint)fd;
-}
-
-/*
- * Class:     sun_tools_attach_BsdVirtualMachine
- * Method:    connect
- * Signature: (ILjava/lang/String;)I
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_connect
-  (JNIEnv *env, jclass cls, jint fd, jstring path)
-{
-    jboolean isCopy;
-    const char* p = GetStringPlatformChars(env, path, &isCopy);
-    if (p != NULL) {
-        struct sockaddr_un addr;
-        int err = 0;
-
-        memset(&addr, 0, sizeof(addr));
-        addr.sun_family = AF_UNIX;
-        /* strncpy is safe because addr.sun_path was zero-initialized before. */
-        strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1);
-
-        if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
-            err = errno;
-        }
-
-        if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, path, p);
-        }
-
-        /*
-         * If the connect failed then we throw the appropriate exception
-         * here (can't throw it before releasing the string as can't call
-         * JNI with pending exception)
-         */
-        if (err != 0) {
-            if (err == ENOENT) {
-                JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);
-            } else {
-                char* msg = strdup(strerror(err));
-                JNU_ThrowIOException(env, msg);
-                if (msg != NULL) {
-                    free(msg);
-                }
-            }
-        }
-    }
-}
-
-/*
- * Class:     sun_tools_attach_BsdVirtualMachine
- * Method:    sendQuitTo
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_sendQuitTo
-  (JNIEnv *env, jclass cls, jint pid)
-{
-    if (kill((pid_t)pid, SIGQUIT)) {
-        JNU_ThrowIOExceptionWithLastError(env, "kill");
-    }
-}
-
-/*
- * Class:     sun_tools_attach_BsdVirtualMachine
- * Method:    checkPermissions
- * Signature: (Ljava/lang/String;)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_checkPermissions
-  (JNIEnv *env, jclass cls, jstring path)
-{
-    jboolean isCopy;
-    const char* p = GetStringPlatformChars(env, path, &isCopy);
-    if (p != NULL) {
-        struct stat sb;
-        uid_t uid, gid;
-        int res;
-
-        /*
-         * Check that the path is owned by the effective uid/gid of this
-         * process. Also check that group/other access is not allowed.
-         */
-        uid = geteuid();
-        gid = getegid();
-
-        res = stat(p, &sb);
-        if (res != 0) {
-            /* save errno */
-            res = errno;
-        }
-
-        /* release p here before we throw an I/O exception */
-        if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, path, p);
-        }
-
-        if (res == 0) {
-            if ( (sb.st_uid != uid) || (sb.st_gid != gid) ||
-                 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) {
-                JNU_ThrowIOException(env, "well-known file is not secure");
-            }
-        } else {
-            char* msg = strdup(strerror(res));
-            JNU_ThrowIOException(env, msg);
-            if (msg != NULL) {
-                free(msg);
-            }
-        }
-    }
-}
-
-/*
- * Class:     sun_tools_attach_BsdVirtualMachine
- * Method:    close
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_close
-  (JNIEnv *env, jclass cls, jint fd)
-{
-    int res;
-    RESTARTABLE(close(fd), res);
-}
-
-/*
- * Class:     sun_tools_attach_BsdVirtualMachine
- * Method:    read
- * Signature: (I[BI)I
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_BsdVirtualMachine_read
-  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)
-{
-    unsigned char buf[128];
-    size_t len = sizeof(buf);
-    ssize_t n;
-
-    size_t remaining = (size_t)(baLen - off);
-    if (len > remaining) {
-        len = remaining;
-    }
-
-    RESTARTABLE(read(fd, buf, len), n);
-    if (n == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "read");
-    } else {
-        if (n == 0) {
-            n = -1;     // EOF
-        } else {
-            (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf));
-        }
-    }
-    return n;
-}
-
-/*
- * Class:     sun_tools_attach_BsdVirtualMachine
- * Method:    write
- * Signature: (I[B)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_write
-  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen)
-{
-    size_t remaining = bufLen;
-    do {
-        unsigned char buf[128];
-        size_t len = sizeof(buf);
-        int n;
-
-        if (len > remaining) {
-            len = remaining;
-        }
-        (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf);
-
-        RESTARTABLE(write(fd, buf, len), n);
-        if (n > 0) {
-           off += n;
-           remaining -= n;
-        } else {
-            JNU_ThrowIOExceptionWithLastError(env, "write");
-            return;
-        }
-
-    } while (remaining > 0);
-}
-
-/*
- * Class:     sun_tools_attach_BSDVirtualMachine
- * Method:    createAttachFile
- * Signature: (Ljava.lang.String;)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_createAttachFile(JNIEnv *env, jclass cls, jstring path)
-{
-    const char* _path;
-    jboolean isCopy;
-    int fd, rc;
-
-    _path = GetStringPlatformChars(env, path, &isCopy);
-    if (_path == NULL) {
-        JNU_ThrowIOException(env, "Must specify a path");
-        return;
-    }
-
-    RESTARTABLE(open(_path, O_CREAT | O_EXCL, S_IWUSR | S_IRUSR), fd);
-    if (fd == -1) {
-        /* release p here before we throw an I/O exception */
-        if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, path, _path);
-        }
-        JNU_ThrowIOExceptionWithLastError(env, "open");
-        return;
-    }
-
-    RESTARTABLE(chown(_path, geteuid(), getegid()), rc);
-
-    RESTARTABLE(close(fd), rc);
-
-    /* release p here */
-    if (isCopy) {
-        JNU_ReleaseStringPlatformChars(env, path, _path);
-    }
-}
-
-/*
- * Class:     sun_tools_attach_BSDVirtualMachine
- * Method:    getTempDir
- * Signature: (V)Ljava.lang.String;
- */
-JNIEXPORT jstring JNICALL Java_sun_tools_attach_BsdVirtualMachine_getTempDir(JNIEnv *env, jclass cls)
-{
-    // This must be hard coded because it's the system's temporary
-    // directory not the java application's temp directory, ala java.io.tmpdir.
-
-#ifdef __APPLE__
-    // macosx has a secure per-user temporary directory
-    static char *temp_path = NULL;
-    char temp_path_storage[PATH_MAX];
-    if (temp_path == NULL) {
-        int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, temp_path_storage, PATH_MAX);
-        if (pathSize == 0 || pathSize > PATH_MAX) {
-            strlcpy(temp_path_storage, "/tmp", sizeof(temp_path_storage));
-        }
-        temp_path = temp_path_storage;
-    }
-    return JNU_NewStringPlatform(env, temp_path);
-#else /* __APPLE__ */
-    return (*env)->NewStringUTF(env, "/tmp");
-#endif /* __APPLE__ */
-}
--- a/src/jdk.attach/unix/native/libattach/LinuxVirtualMachine.c	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,463 +0,0 @@
-/*
- * Copyright (c) 2005, 2014, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-
-#include "sun_tools_attach_LinuxVirtualMachine.h"
-
-#define RESTARTABLE(_cmd, _result) do { \
-  do { \
-    _result = _cmd; \
-  } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
-/*
- * Defines a callback that is invoked for each process
- */
-typedef void (*ProcessCallback)(const pid_t pid, void* user_data);
-
-/*
- * Invokes the callback function for each process
- */
-static void forEachProcess(ProcessCallback f, void* user_data) {
-    DIR* dir;
-    struct dirent* ptr;
-
-    /*
-     * To locate the children we scan /proc looking for files that have a
-     * position integer as a filename.
-     */
-    if ((dir = opendir("/proc")) == NULL) {
-        return;
-    }
-    while ((ptr = readdir(dir)) != NULL) {
-        pid_t pid;
-
-        /* skip current/parent directories */
-        if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
-            continue;
-        }
-
-        /* skip files that aren't numbers */
-        pid = (pid_t)atoi(ptr->d_name);
-        if ((int)pid <= 0) {
-            continue;
-        }
-
-        /* invoke the callback */
-        (*f)(pid, user_data);
-    }
-    closedir(dir);
-}
-
-
-/*
- * Returns the parent pid of a given pid, or -1 if not found
- */
-static pid_t getParent(pid_t pid) {
-    char state;
-    FILE* fp;
-    char stat[2048];
-    int statlen;
-    char fn[32];
-    int i, p;
-    char* s;
-
-    /*
-     * try to open /proc/%d/stat
-     */
-    sprintf(fn, "/proc/%d/stat", pid);
-    fp = fopen(fn, "r");
-    if (fp == NULL) {
-        return -1;
-    }
-
-    /*
-     * The format is: pid (command) state ppid ...
-     * As the command could be anything we must find the right most
-     * ")" and then skip the white spaces that follow it.
-     */
-    statlen = fread(stat, 1, 2047, fp);
-    stat[statlen] = '\0';
-    fclose(fp);
-    s = strrchr(stat, ')');
-    if (s == NULL) {
-        return -1;
-    }
-    do s++; while (isspace(*s));
-    i = sscanf(s, "%c %d", &state, &p);
-    return (pid_t)p;
-}
-
-
-/*
- * Class:     sun_tools_attach_LinuxVirtualMachine
- * Method:    socket
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_LinuxVirtualMachine_socket
-  (JNIEnv *env, jclass cls)
-{
-    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
-    if (fd == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "socket");
-    }
-    return (jint)fd;
-}
-
-/*
- * Class:     sun_tools_attach_LinuxVirtualMachine
- * Method:    connect
- * Signature: (ILjava/lang/String;)I
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_LinuxVirtualMachine_connect
-  (JNIEnv *env, jclass cls, jint fd, jstring path)
-{
-    jboolean isCopy;
-    const char* p = GetStringPlatformChars(env, path, &isCopy);
-    if (p != NULL) {
-        struct sockaddr_un addr;
-        int err = 0;
-
-        memset(&addr, 0, sizeof(addr));
-        addr.sun_family = AF_UNIX;
-        /* strncpy is safe because addr.sun_path was zero-initialized before. */
-        strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1);
-
-        if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
-            err = errno;
-        }
-
-        if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, path, p);
-        }
-
-        /*
-         * If the connect failed then we throw the appropriate exception
-         * here (can't throw it before releasing the string as can't call
-         * JNI with pending exception)
-         */
-        if (err != 0) {
-            if (err == ENOENT) {
-                JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);
-            } else {
-                char* msg = strdup(strerror(err));
-                JNU_ThrowIOException(env, msg);
-                if (msg != NULL) {
-                    free(msg);
-                }
-            }
-        }
-    }
-}
-
-/*
- * Class:     sun_tools_attach_LinuxVirtualMachine
- * Method:    isLinuxThreads
- * Signature: ()V
- */
-JNIEXPORT jboolean JNICALL Java_sun_tools_attach_LinuxVirtualMachine_isLinuxThreads
-  (JNIEnv *env, jclass cls)
-{
-# ifndef _CS_GNU_LIBPTHREAD_VERSION
-# define _CS_GNU_LIBPTHREAD_VERSION 3
-# endif
-    size_t n;
-    char* s;
-    jboolean res;
-
-    n = confstr(_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
-    if (n <= 0) {
-       /* glibc before 2.3.2 only has LinuxThreads */
-       return JNI_TRUE;
-    }
-
-    s = (char *)malloc(n);
-    if (s == NULL) {
-        JNU_ThrowOutOfMemoryError(env, "malloc failed");
-        return JNI_TRUE;
-    }
-    confstr(_CS_GNU_LIBPTHREAD_VERSION, s, n);
-
-    /*
-     * If the LIBPTHREAD version include "NPTL" then we know we
-     * have the new threads library and not LinuxThreads
-     */
-    res = (jboolean)(strstr(s, "NPTL") == NULL);
-    free(s);
-    return res;
-}
-
-/*
- * Structure and callback function used to count the children of
- * a given process, and record the pid of the "manager thread".
- */
-typedef struct {
-    pid_t ppid;
-    int count;
-    pid_t mpid;
-} ChildCountContext;
-
-static void ChildCountCallback(const pid_t pid, void* user_data) {
-    ChildCountContext* context = (ChildCountContext*)user_data;
-    if (getParent(pid) == context->ppid) {
-        context->count++;
-        /*
-         * Remember the pid of the first child. If the final count is
-         * one then this is the pid of the LinuxThreads manager.
-         */
-        if (context->count == 1) {
-            context->mpid = pid;
-        }
-    }
-}
-
-/*
- * Class:     sun_tools_attach_LinuxVirtualMachine
- * Method:    getLinuxThreadsManager
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_LinuxVirtualMachine_getLinuxThreadsManager
-  (JNIEnv *env, jclass cls, jint pid)
-{
-    ChildCountContext context;
-
-    /*
-     * Iterate over all processes to find how many children 'pid' has
-     */
-    context.ppid = pid;
-    context.count = 0;
-    context.mpid = (pid_t)0;
-    forEachProcess(ChildCountCallback, (void*)&context);
-
-    /*
-     * If there's no children then this is likely the pid of the primordial
-     * created by the launcher - in that case the LinuxThreads manager is the
-     * parent of this process.
-     */
-    if (context.count == 0) {
-        pid_t parent = getParent(pid);
-        if ((int)parent > 0) {
-            return (jint)parent;
-        }
-    }
-
-    /*
-     * There's one child so this is likely the embedded VM case where the
-     * the primordial thread == LinuxThreads initial thread. The LinuxThreads
-     * manager in that case is the child.
-     */
-    if (context.count == 1) {
-        return (jint)context.mpid;
-    }
-
-    /*
-     * If we get here it's most likely we were given the wrong pid
-     */
-    JNU_ThrowIOException(env, "Unable to get pid of LinuxThreads manager thread");
-    return -1;
-}
-
-/*
- * Structure and callback function used to send a QUIT signal to all
- * children of a given process
- */
-typedef struct {
-    pid_t ppid;
-} SendQuitContext;
-
-static void SendQuitCallback(const pid_t pid, void* user_data) {
-    SendQuitContext* context = (SendQuitContext*)user_data;
-    pid_t parent = getParent(pid);
-    if (parent == context->ppid) {
-        kill(pid, SIGQUIT);
-    }
-}
-
-/*
- * Class:     sun_tools_attach_LinuxVirtualMachine
- * Method:    sendQuitToChildrenOf
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_LinuxVirtualMachine_sendQuitToChildrenOf
-  (JNIEnv *env, jclass cls, jint pid)
-{
-    SendQuitContext context;
-    context.ppid = (pid_t)pid;
-
-    /*
-     * Iterate over all children of 'pid' and send a QUIT signal to each.
-     */
-    forEachProcess(SendQuitCallback, (void*)&context);
-}
-
-/*
- * Class:     sun_tools_attach_LinuxVirtualMachine
- * Method:    sendQuitTo
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_LinuxVirtualMachine_sendQuitTo
-  (JNIEnv *env, jclass cls, jint pid)
-{
-    if (kill((pid_t)pid, SIGQUIT)) {
-        JNU_ThrowIOExceptionWithLastError(env, "kill");
-    }
-}
-
-/*
- * Class:     sun_tools_attach_LinuxVirtualMachine
- * Method:    checkPermissions
- * Signature: (Ljava/lang/String;)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_LinuxVirtualMachine_checkPermissions
-  (JNIEnv *env, jclass cls, jstring path)
-{
-    jboolean isCopy;
-    const char* p = GetStringPlatformChars(env, path, &isCopy);
-    if (p != NULL) {
-        struct stat64 sb;
-        uid_t uid, gid;
-        int res;
-
-        /*
-         * Check that the path is owned by the effective uid/gid of this
-         * process. Also check that group/other access is not allowed.
-         */
-        uid = geteuid();
-        gid = getegid();
-
-        res = stat64(p, &sb);
-        if (res != 0) {
-            /* save errno */
-            res = errno;
-        }
-
-        /* release p here before we throw an I/O exception */
-        if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, path, p);
-        }
-
-        if (res == 0) {
-            if ( (sb.st_uid != uid) || (sb.st_gid != gid) ||
-                 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) {
-                JNU_ThrowIOException(env, "well-known file is not secure");
-            }
-        } else {
-            char* msg = strdup(strerror(res));
-            JNU_ThrowIOException(env, msg);
-            if (msg != NULL) {
-                free(msg);
-            }
-        }
-    }
-}
-
-/*
- * Class:     sun_tools_attach_LinuxVirtualMachine
- * Method:    close
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_LinuxVirtualMachine_close
-  (JNIEnv *env, jclass cls, jint fd)
-{
-    int res;
-    RESTARTABLE(close(fd), res);
-}
-
-/*
- * Class:     sun_tools_attach_LinuxVirtualMachine
- * Method:    read
- * Signature: (I[BI)I
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_LinuxVirtualMachine_read
-  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)
-{
-    unsigned char buf[128];
-    size_t len = sizeof(buf);
-    ssize_t n;
-
-    size_t remaining = (size_t)(baLen - off);
-    if (len > remaining) {
-        len = remaining;
-    }
-
-    RESTARTABLE(read(fd, buf, len), n);
-    if (n == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "read");
-    } else {
-        if (n == 0) {
-            n = -1;     // EOF
-        } else {
-            (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf));
-        }
-    }
-    return n;
-}
-
-/*
- * Class:     sun_tools_attach_LinuxVirtualMachine
- * Method:    write
- * Signature: (I[B)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_LinuxVirtualMachine_write
-  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen)
-{
-    size_t remaining = bufLen;
-    do {
-        unsigned char buf[128];
-        size_t len = sizeof(buf);
-        int n;
-
-        if (len > remaining) {
-            len = remaining;
-        }
-        (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf);
-
-        RESTARTABLE(write(fd, buf, len), n);
-        if (n > 0) {
-           off += n;
-           remaining -= n;
-        } else {
-            JNU_ThrowIOExceptionWithLastError(env, "write");
-            return;
-        }
-
-    } while (remaining > 0);
-}
--- a/src/jdk.attach/unix/native/libattach/SolarisVirtualMachine.c	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,356 +0,0 @@
-/*
- * Copyright (c) 2005, 2014, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <door.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-
-#include "jni.h"
-#include "jni_util.h"
-
-#include "sun_tools_attach_SolarisVirtualMachine.h"
-
-#define RESTARTABLE(_cmd, _result) do { \
-  do { \
-    _result = _cmd; \
-  } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
-/*
- * Class:     sun_tools_attach_SolarisVirtualMachine
- * Method:    open
- * Signature: (Ljava/lang/String;)I
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_SolarisVirtualMachine_open
-  (JNIEnv *env, jclass cls, jstring path)
-{
-    jboolean isCopy;
-    const char* p = GetStringPlatformChars(env, path, &isCopy);
-    if (p == NULL) {
-        return 0;
-    } else {
-        int fd;
-        int err = 0;
-
-        fd = open(p, O_RDWR);
-        if (fd == -1) {
-            err = errno;
-        }
-
-        if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, path, p);
-        }
-
-        if (fd == -1) {
-            if (err == ENOENT) {
-                JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);
-            } else {
-                char* msg = strdup(strerror(err));
-                JNU_ThrowIOException(env, msg);
-                if (msg != NULL) {
-                    free(msg);
-                }
-            }
-        }
-        return fd;
-    }
-}
-
-/*
- * Class:     sun_tools_attach_SolarisVirtualMachine
- * Method:    checkPermissions
- * Signature: (Ljava/lang/String;)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_SolarisVirtualMachine_checkPermissions
-  (JNIEnv *env, jclass cls, jstring path)
-{
-    jboolean isCopy;
-    const char* p = GetStringPlatformChars(env, path, &isCopy);
-    if (p != NULL) {
-        struct stat64 sb;
-        uid_t uid, gid;
-        int res;
-
-        /*
-         * Check that the path is owned by the effective uid/gid of this
-         * process. Also check that group/other access is not allowed.
-         */
-        uid = geteuid();
-        gid = getegid();
-
-        res = stat64(p, &sb);
-        if (res != 0) {
-            /* save errno */
-            res = errno;
-        }
-
-        /* release p here before we throw an I/O exception */
-        if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, path, p);
-        }
-
-        if (res == 0) {
-            if ( (sb.st_uid != uid) || (sb.st_gid != gid) ||
-                 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) {
-                JNU_ThrowIOException(env, "well-known file is not secure");
-            }
-        } else {
-            char* msg = strdup(strerror(res));
-            JNU_ThrowIOException(env, msg);
-            if (msg != NULL) {
-                free(msg);
-            }
-        }
-    }
-}
-
-/*
- * Class:     sun_tools_attach_SolarisVirtualMachine
- * Method:    close
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_SolarisVirtualMachine_close
-  (JNIEnv *env, jclass cls, jint fd)
-{
-    int ret;
-    RESTARTABLE(close(fd), ret);
-}
-
-/*
- * Class:     sun_tools_attach_SolarisVirtualMachine
- * Method:    read
- * Signature: (I[BI)I
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_SolarisVirtualMachine_read
-  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)
-{
-    unsigned char buf[128];
-    size_t len = sizeof(buf);
-    ssize_t n;
-
-    size_t remaining = (size_t)(baLen - off);
-    if (len > remaining) {
-        len = remaining;
-    }
-
-    RESTARTABLE(read(fd, buf, len), n);
-    if (n == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "read");
-    } else {
-        if (n == 0) {
-            n = -1;     // EOF
-        } else {
-            (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf));
-        }
-    }
-    return n;
-}
-
-/*
- * Class:     sun_tools_attach_SolarisVirtualMachine
- * Method:    sigquit
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_SolarisVirtualMachine_sigquit
-  (JNIEnv *env, jclass cls, jint pid)
-{
-    if (kill((pid_t)pid, SIGQUIT) == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "kill");
-    }
-}
-
-/*
- * A simple table to translate some known errors into reasonable
- * error messages
- */
-static struct {
-    jint err;
-    const char* msg;
-} const error_messages[] = {
-    { 100,      "Bad request" },
-    { 101,      "Protocol mismatch" },
-    { 102,      "Resource failure" },
-    { 103,      "Internal error" },
-    { 104,      "Permission denied" },
-};
-
-/*
- * Lookup the given error code and return the appropriate
- * message. If not found return NULL.
- */
-static const char* translate_error(jint err) {
-    int table_size = sizeof(error_messages) / sizeof(error_messages[0]);
-    int i;
-
-    for (i=0; i<table_size; i++) {
-        if (err == error_messages[i].err) {
-            return error_messages[i].msg;
-        }
-    }
-    return NULL;
-}
-
-/*
- * Current protocol version
- */
-static const char* PROTOCOL_VERSION = "1";
-
-/*
- * Class:     sun_tools_attach_SolarisVirtualMachine
- * Method:    enqueue
- * Signature: (JILjava/lang/String;[Ljava/lang/Object;)V
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_SolarisVirtualMachine_enqueue
-  (JNIEnv *env, jclass cls, jint fd, jstring cmd, jobjectArray args)
-{
-    jint arg_count, i;
-    size_t size;
-    jboolean isCopy;
-    door_arg_t door_args;
-    char res_buffer[128];
-    jint result = -1;
-    int rc;
-    const char* cstr;
-    char* buf;
-
-    /*
-     * First we get the command string and create the start of the
-     * argument string to send to the target VM:
-     * <ver>\0<cmd>\0
-     */
-    cstr = JNU_GetStringPlatformChars(env, cmd, &isCopy);
-    if (cstr == NULL) {
-        return -1;              /* pending exception */
-    }
-    size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2;
-    buf = (char*)malloc(size);
-    if (buf != NULL) {
-        char* pos = buf;
-        strcpy(buf, PROTOCOL_VERSION);
-        pos += strlen(PROTOCOL_VERSION)+1;
-        strcpy(pos, cstr);
-    }
-    if (isCopy) {
-        JNU_ReleaseStringPlatformChars(env, cmd, cstr);
-    }
-    if (buf == NULL) {
-        JNU_ThrowOutOfMemoryError(env, "malloc failed");
-        return -1;
-    }
-
-    /*
-     * Next we iterate over the arguments and extend the buffer
-     * to include them.
-     */
-    arg_count = (*env)->GetArrayLength(env, args);
-
-    for (i=0; i<arg_count; i++) {
-        jobject obj = (*env)->GetObjectArrayElement(env, args, i);
-        if (obj != NULL) {
-            cstr = JNU_GetStringPlatformChars(env, obj, &isCopy);
-            if (cstr != NULL) {
-                size_t len = strlen(cstr);
-                char* newbuf = (char*)realloc(buf, size+len+1);
-                if (newbuf != NULL) {
-                    buf = newbuf;
-                    strcpy(buf+size, cstr);
-                    size += len+1;
-                }
-                if (isCopy) {
-                    JNU_ReleaseStringPlatformChars(env, obj, cstr);
-                }
-                if (newbuf == NULL) {
-                    free(buf);
-                    JNU_ThrowOutOfMemoryError(env, "realloc failed");
-                    return -1;
-                }
-            }
-        }
-        if ((*env)->ExceptionOccurred(env)) {
-            free(buf);
-            return -1;
-        }
-    }
-
-    /*
-     * The arguments to the door function are in 'buf' so we now
-     * do the door call
-     */
-    door_args.data_ptr = buf;
-    door_args.data_size = size;
-    door_args.desc_ptr = NULL;
-    door_args.desc_num = 0;
-    door_args.rbuf = (char*)&res_buffer;
-    door_args.rsize = sizeof(res_buffer);
-
-    RESTARTABLE(door_call(fd, &door_args), rc);
-
-    /*
-     * door_call failed
-     */
-    if (rc == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "door_call");
-    } else {
-        /*
-         * door_call succeeded but the call didn't return the the expected jint.
-         */
-        if (door_args.data_size < sizeof(jint)) {
-            JNU_ThrowIOException(env, "Enqueue error - reason unknown as result is truncated!");
-        } else {
-            jint* res = (jint*)(door_args.data_ptr);
-            if (*res != JNI_OK) {
-                const char* msg = translate_error(*res);
-                char buf[255];
-                if (msg == NULL) {
-                    sprintf(buf, "Unable to enqueue command to target VM: %d", *res);
-                } else {
-                    sprintf(buf, "Unable to enqueue command to target VM: %s", msg);
-                }
-                JNU_ThrowIOException(env, buf);
-            } else {
-                /*
-                 * The door call should return a file descriptor to one end of
-                 * a socket pair
-                 */
-                if ((door_args.desc_ptr != NULL) &&
-                    (door_args.desc_num == 1) &&
-                    (door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) {
-                    result = door_args.desc_ptr->d_data.d_desc.d_descriptor;
-                } else {
-                    JNU_ThrowIOException(env, "Reply from enqueue missing descriptor!");
-                }
-            }
-        }
-    }
-
-    free(buf);
-    return result;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/windows/classes/sun/tools/attach/AttachProviderImpl.java	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2005, 2011, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 sun.tools.attach;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.VirtualMachineDescriptor;
+import com.sun.tools.attach.AttachNotSupportedException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+public class AttachProviderImpl extends HotSpotAttachProvider {
+
+    public AttachProviderImpl() {
+        String os = System.getProperty("os.name");
+        if (os.startsWith("Windows 9") || os.equals("Windows Me")) {
+            throw new RuntimeException(
+                "This provider is not supported on this version of Windows");
+        }
+        String arch = System.getProperty("os.arch");
+        if (!arch.equals("x86") && !arch.equals("amd64")) {
+            throw new RuntimeException(
+                "This provider is not supported on this processor architecture");
+        }
+    }
+
+    public String name() {
+        return "sun";
+    }
+
+    public String type() {
+        return "windows";
+    }
+
+    public VirtualMachine attachVirtualMachine(String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        checkAttachPermission();
+
+        // AttachNotSupportedException will be thrown if the target VM can be determined
+        // to be not attachable.
+        testAttachable(vmid);
+
+        return new VirtualMachineImpl(this, vmid);
+    }
+
+    public List<VirtualMachineDescriptor> listVirtualMachines() {
+        // If the temporary file system is secure then we use the default
+        // implementation, otherwise we create a list of Windows processes.
+        if (isTempPathSecure()) {
+            return super.listVirtualMachines();
+        } else {
+            return listJavaProcesses();
+        }
+    }
+
+    /**
+     * Returns true if the temporary file system supports security
+     */
+    private static boolean isTempPathSecure() {
+        if (!wasTempPathChecked) {
+            synchronized (AttachProviderImpl.class) {
+                if (!wasTempPathChecked) {
+                    // get the value of TMP/TEMP, ignoring UNC, and paths that
+                    // aren't absolute
+                    String temp = tempPath();
+                    if ((temp != null) && (temp.length() >= 3) &&
+                        (temp.charAt(1) == ':') && (temp.charAt(2) == '\\'))
+                    {
+                        // check if the volume supports security
+                        long flags = volumeFlags(temp.substring(0, 3));
+                        isTempPathSecure = ((flags & FS_PERSISTENT_ACLS) != 0);
+                    }
+                    wasTempPathChecked = true;
+                }
+            }
+        }
+
+        return isTempPathSecure;
+    }
+
+    // flag to indicate persistent ACLs are supported
+    private static final long FS_PERSISTENT_ACLS = 0x8L;
+
+    // indicates if we've checked the temporary file system
+    private static volatile boolean wasTempPathChecked;
+
+    // indicates if the temporary file system is secure (only valid when
+    // wasTempPathChecked is true)
+    private static boolean isTempPathSecure;
+
+    // returns the value of TMP/TEMP
+    private static native String tempPath();
+
+    // returns the flags for the given volume
+    private static native long volumeFlags(String volume);
+
+
+    /**
+     * Returns a list of virtual machine descriptors derived from an enumeration
+     * of the process list.
+     */
+    private List<VirtualMachineDescriptor> listJavaProcesses() {
+        ArrayList<VirtualMachineDescriptor> list =
+            new ArrayList<VirtualMachineDescriptor>();
+
+        // Use localhost in the display name
+        String host = "localhost";
+        try {
+            host = InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException uhe) {
+            // ignore
+        }
+
+        // Enumerate all processes.
+        // For those processes that have loaded a library named "jvm.dll"
+        // then we attempt to attach. If we succeed then we have a 6.0+ VM.
+        int processes[] = new int[1024];
+        int count = enumProcesses(processes, processes.length);
+        for (int i=0; i<count; i++) {
+            if (isLibraryLoadedByProcess("jvm.dll", processes[i])) {
+                String pid = Integer.toString(processes[i]);
+                try {
+                    new VirtualMachineImpl(this, pid).detach();
+
+                    // FIXME - for now we don't have an appropriate display
+                    // name so we use pid@hostname
+                    String name = pid + "@" + host;
+
+                    list.add(new HotSpotVirtualMachineDescriptor(this, pid, name));
+                } catch (AttachNotSupportedException x) {
+                } catch (IOException ioe) {
+                }
+            }
+        }
+
+        return list;
+    }
+
+    // enumerates processes using psapi's EnumProcesses
+    private static native int enumProcesses(int[] processes, int max);
+
+    // indicates if a library of a given name has been loaded by a process
+    private static native boolean isLibraryLoadedByProcess(String library,
+                                                           int processId);
+
+
+    // native functions in this library
+    static {
+        System.loadLibrary("attach");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2005, 2014, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 sun.tools.attach;
+
+import com.sun.tools.attach.AttachOperationFailedException;
+import com.sun.tools.attach.AgentLoadException;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.spi.AttachProvider;
+
+import sun.tools.attach.HotSpotVirtualMachine;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Random;
+
+public class VirtualMachineImpl extends HotSpotVirtualMachine {
+
+    // the enqueue code stub (copied into each target VM)
+    private static byte[] stub;
+
+    private volatile long hProcess;     // handle to the process
+
+    VirtualMachineImpl(AttachProvider provider, String id)
+        throws AttachNotSupportedException, IOException
+    {
+        super(provider, id);
+
+        int pid;
+        try {
+            pid = Integer.parseInt(id);
+        } catch (NumberFormatException x) {
+            throw new AttachNotSupportedException("Invalid process identifier");
+        }
+        hProcess = openProcess(pid);
+
+        // The target VM might be a pre-6.0 VM so we enqueue a "null" command
+        // which minimally tests that the enqueue function exists in the target
+        // VM.
+        try {
+            enqueue(hProcess, stub, null, null);
+        } catch (IOException x) {
+            throw new AttachNotSupportedException(x.getMessage());
+        }
+    }
+
+    public void detach() throws IOException {
+        synchronized (this) {
+            if (hProcess != -1) {
+                closeProcess(hProcess);
+                hProcess = -1;
+            }
+        }
+    }
+
+    InputStream execute(String cmd, Object ... args)
+        throws AgentLoadException, IOException
+    {
+        assert args.length <= 3;        // includes null
+
+        // create a pipe using a random name
+        int r = (new Random()).nextInt();
+        String pipename = "\\\\.\\pipe\\javatool" + r;
+        long hPipe = createPipe(pipename);
+
+        // check if we are detached - in theory it's possible that detach is invoked
+        // after this check but before we enqueue the command.
+        if (hProcess == -1) {
+            closePipe(hPipe);
+            throw new IOException("Detached from target VM");
+        }
+
+        try {
+            // enqueue the command to the process
+            enqueue(hProcess, stub, cmd, pipename, args);
+
+            // wait for command to complete - process will connect with the
+            // completion status
+            connectPipe(hPipe);
+
+            // create an input stream for the pipe
+            PipedInputStream is = new PipedInputStream(hPipe);
+
+            // read completion status
+            int status = readInt(is);
+            if (status != 0) {
+                // read from the stream and use that as the error message
+                String message = readErrorMessage(is);
+                // special case the load command so that the right exception is thrown
+                if (cmd.equals("load")) {
+                    throw new AgentLoadException("Failed to load agent library");
+                } else {
+                    if (message == null) {
+                        throw new AttachOperationFailedException("Command failed in target VM");
+                    } else {
+                        throw new AttachOperationFailedException(message);
+                    }
+                }
+            }
+
+            // return the input stream
+            return is;
+
+        } catch (IOException ioe) {
+            closePipe(hPipe);
+            throw ioe;
+        }
+    }
+
+    // An InputStream based on a pipe to the target VM
+    private class PipedInputStream extends InputStream {
+
+        private long hPipe;
+
+        public PipedInputStream(long hPipe) {
+            this.hPipe = hPipe;
+        }
+
+        public synchronized int read() throws IOException {
+            byte b[] = new byte[1];
+            int n = this.read(b, 0, 1);
+            if (n == 1) {
+                return b[0] & 0xff;
+            } else {
+                return -1;
+            }
+        }
+
+        public synchronized int read(byte[] bs, int off, int len) throws IOException {
+            if ((off < 0) || (off > bs.length) || (len < 0) ||
+                ((off + len) > bs.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0)
+                return 0;
+
+            return VirtualMachineImpl.readPipe(hPipe, bs, off, len);
+        }
+
+        public void close() throws IOException {
+            if (hPipe != -1) {
+                VirtualMachineImpl.closePipe(hPipe);
+                hPipe = -1;
+           }
+        }
+    }
+
+
+    //-- native methods
+
+    static native void init();
+
+    static native byte[] generateStub();
+
+    static native long openProcess(int pid) throws IOException;
+
+    static native void closeProcess(long hProcess) throws IOException;
+
+    static native long createPipe(String name) throws IOException;
+
+    static native void closePipe(long hPipe) throws IOException;
+
+    static native void connectPipe(long hPipe) throws IOException;
+
+    static native int readPipe(long hPipe, byte buf[], int off, int buflen) throws IOException;
+
+    static native void enqueue(long hProcess, byte[] stub,
+        String cmd, String pipename, Object ... args) throws IOException;
+
+    static {
+        System.loadLibrary("attach");
+        init();                                 // native initialization
+        stub = generateStub();                  // generate stub to copy into target process
+    }
+}
--- a/src/jdk.attach/windows/classes/sun/tools/attach/WindowsAttachProvider.java	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2005, 2011, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.tools.attach;
-
-import com.sun.tools.attach.VirtualMachine;
-import com.sun.tools.attach.VirtualMachineDescriptor;
-import com.sun.tools.attach.AttachNotSupportedException;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-public class WindowsAttachProvider extends HotSpotAttachProvider {
-
-    public WindowsAttachProvider() {
-        String os = System.getProperty("os.name");
-        if (os.startsWith("Windows 9") || os.equals("Windows Me")) {
-            throw new RuntimeException(
-                "This provider is not supported on this version of Windows");
-        }
-        String arch = System.getProperty("os.arch");
-        if (!arch.equals("x86") && !arch.equals("amd64")) {
-            throw new RuntimeException(
-                "This provider is not supported on this processor architecture");
-        }
-    }
-
-    public String name() {
-        return "sun";
-    }
-
-    public String type() {
-        return "windows";
-    }
-
-    public VirtualMachine attachVirtualMachine(String vmid)
-        throws AttachNotSupportedException, IOException
-    {
-        checkAttachPermission();
-
-        // AttachNotSupportedException will be thrown if the target VM can be determined
-        // to be not attachable.
-        testAttachable(vmid);
-
-        return new WindowsVirtualMachine(this, vmid);
-    }
-
-    public List<VirtualMachineDescriptor> listVirtualMachines() {
-        // If the temporary file system is secure then we use the default
-        // implementation, otherwise we create a list of Windows processes.
-        if (isTempPathSecure()) {
-            return super.listVirtualMachines();
-        } else {
-            return listJavaProcesses();
-        }
-    }
-
-    /**
-     * Returns true if the temporary file system supports security
-     */
-    private static boolean isTempPathSecure() {
-        if (!wasTempPathChecked) {
-            synchronized (WindowsAttachProvider.class) {
-                if (!wasTempPathChecked) {
-                    // get the value of TMP/TEMP, ignoring UNC, and paths that
-                    // aren't absolute
-                    String temp = tempPath();
-                    if ((temp != null) && (temp.length() >= 3) &&
-                        (temp.charAt(1) == ':') && (temp.charAt(2) == '\\'))
-                    {
-                        // check if the volume supports security
-                        long flags = volumeFlags(temp.substring(0, 3));
-                        isTempPathSecure = ((flags & FS_PERSISTENT_ACLS) != 0);
-                    }
-                    wasTempPathChecked = true;
-                }
-            }
-        }
-
-        return isTempPathSecure;
-    }
-
-    // flag to indicate persistent ACLs are supported
-    private static final long FS_PERSISTENT_ACLS = 0x8L;
-
-    // indicates if we've checked the temporary file system
-    private static volatile boolean wasTempPathChecked;
-
-    // indicates if the temporary file system is secure (only valid when
-    // wasTempPathChecked is true)
-    private static boolean isTempPathSecure;
-
-    // returns the value of TMP/TEMP
-    private static native String tempPath();
-
-    // returns the flags for the given volume
-    private static native long volumeFlags(String volume);
-
-
-    /**
-     * Returns a list of virtual machine descriptors derived from an enumeration
-     * of the process list.
-     */
-    private List<VirtualMachineDescriptor> listJavaProcesses() {
-        ArrayList<VirtualMachineDescriptor> list =
-            new ArrayList<VirtualMachineDescriptor>();
-
-        // Use localhost in the display name
-        String host = "localhost";
-        try {
-            host = InetAddress.getLocalHost().getHostName();
-        } catch (UnknownHostException uhe) {
-            // ignore
-        }
-
-        // Enumerate all processes.
-        // For those processes that have loaded a library named "jvm.dll"
-        // then we attempt to attach. If we succeed then we have a 6.0+ VM.
-        int processes[] = new int[1024];
-        int count = enumProcesses(processes, processes.length);
-        for (int i=0; i<count; i++) {
-            if (isLibraryLoadedByProcess("jvm.dll", processes[i])) {
-                String pid = Integer.toString(processes[i]);
-                try {
-                    new WindowsVirtualMachine(this, pid).detach();
-
-                    // FIXME - for now we don't have an appropriate display
-                    // name so we use pid@hostname
-                    String name = pid + "@" + host;
-
-                    list.add(new HotSpotVirtualMachineDescriptor(this, pid, name));
-                } catch (AttachNotSupportedException x) {
-                } catch (IOException ioe) {
-                }
-            }
-        }
-
-        return list;
-    }
-
-    // enumerates processes using psapi's EnumProcesses
-    private static native int enumProcesses(int[] processes, int max);
-
-    // indicates if a library of a given name has been loaded by a process
-    private static native boolean isLibraryLoadedByProcess(String library,
-                                                           int processId);
-
-
-    // native functions in this library
-    static {
-        System.loadLibrary("attach");
-    }
-
-}
--- a/src/jdk.attach/windows/classes/sun/tools/attach/WindowsVirtualMachine.java	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 2005, 2014, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.tools.attach;
-
-import com.sun.tools.attach.AttachOperationFailedException;
-import com.sun.tools.attach.AgentLoadException;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.spi.AttachProvider;
-
-import sun.tools.attach.HotSpotVirtualMachine;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Random;
-
-public class WindowsVirtualMachine extends HotSpotVirtualMachine {
-
-    // the enqueue code stub (copied into each target VM)
-    private static byte[] stub;
-
-    private volatile long hProcess;     // handle to the process
-
-    WindowsVirtualMachine(AttachProvider provider, String id)
-        throws AttachNotSupportedException, IOException
-    {
-        super(provider, id);
-
-        int pid;
-        try {
-            pid = Integer.parseInt(id);
-        } catch (NumberFormatException x) {
-            throw new AttachNotSupportedException("Invalid process identifier");
-        }
-        hProcess = openProcess(pid);
-
-        // The target VM might be a pre-6.0 VM so we enqueue a "null" command
-        // which minimally tests that the enqueue function exists in the target
-        // VM.
-        try {
-            enqueue(hProcess, stub, null, null);
-        } catch (IOException x) {
-            throw new AttachNotSupportedException(x.getMessage());
-        }
-    }
-
-    public void detach() throws IOException {
-        synchronized (this) {
-            if (hProcess != -1) {
-                closeProcess(hProcess);
-                hProcess = -1;
-            }
-        }
-    }
-
-    InputStream execute(String cmd, Object ... args)
-        throws AgentLoadException, IOException
-    {
-        assert args.length <= 3;        // includes null
-
-        // create a pipe using a random name
-        int r = (new Random()).nextInt();
-        String pipename = "\\\\.\\pipe\\javatool" + r;
-        long hPipe = createPipe(pipename);
-
-        // check if we are detached - in theory it's possible that detach is invoked
-        // after this check but before we enqueue the command.
-        if (hProcess == -1) {
-            closePipe(hPipe);
-            throw new IOException("Detached from target VM");
-        }
-
-        try {
-            // enqueue the command to the process
-            enqueue(hProcess, stub, cmd, pipename, args);
-
-            // wait for command to complete - process will connect with the
-            // completion status
-            connectPipe(hPipe);
-
-            // create an input stream for the pipe
-            PipedInputStream is = new PipedInputStream(hPipe);
-
-            // read completion status
-            int status = readInt(is);
-            if (status != 0) {
-                // read from the stream and use that as the error message
-                String message = readErrorMessage(is);
-                // special case the load command so that the right exception is thrown
-                if (cmd.equals("load")) {
-                    throw new AgentLoadException("Failed to load agent library");
-                } else {
-                    if (message == null) {
-                        throw new AttachOperationFailedException("Command failed in target VM");
-                    } else {
-                        throw new AttachOperationFailedException(message);
-                    }
-                }
-            }
-
-            // return the input stream
-            return is;
-
-        } catch (IOException ioe) {
-            closePipe(hPipe);
-            throw ioe;
-        }
-    }
-
-    // An InputStream based on a pipe to the target VM
-    private class PipedInputStream extends InputStream {
-
-        private long hPipe;
-
-        public PipedInputStream(long hPipe) {
-            this.hPipe = hPipe;
-        }
-
-        public synchronized int read() throws IOException {
-            byte b[] = new byte[1];
-            int n = this.read(b, 0, 1);
-            if (n == 1) {
-                return b[0] & 0xff;
-            } else {
-                return -1;
-            }
-        }
-
-        public synchronized int read(byte[] bs, int off, int len) throws IOException {
-            if ((off < 0) || (off > bs.length) || (len < 0) ||
-                ((off + len) > bs.length) || ((off + len) < 0)) {
-                throw new IndexOutOfBoundsException();
-            } else if (len == 0)
-                return 0;
-
-            return WindowsVirtualMachine.readPipe(hPipe, bs, off, len);
-        }
-
-        public void close() throws IOException {
-            if (hPipe != -1) {
-                WindowsVirtualMachine.closePipe(hPipe);
-                hPipe = -1;
-           }
-        }
-    }
-
-
-    //-- native methods
-
-    static native void init();
-
-    static native byte[] generateStub();
-
-    static native long openProcess(int pid) throws IOException;
-
-    static native void closeProcess(long hProcess) throws IOException;
-
-    static native long createPipe(String name) throws IOException;
-
-    static native void closePipe(long hPipe) throws IOException;
-
-    static native void connectPipe(long hPipe) throws IOException;
-
-    static native int readPipe(long hPipe, byte buf[], int off, int buflen) throws IOException;
-
-    static native void enqueue(long hProcess, byte[] stub,
-        String cmd, String pipename, Object ... args) throws IOException;
-
-    static {
-        System.loadLibrary("attach");
-        init();                                 // native initialization
-        stub = generateStub();                  // generate stub to copy into target process
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/windows/native/libattach/AttachProviderImpl.c	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2005, 2011, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+#include <Psapi.h>
+
+#include "jni.h"
+#include "jni_util.h"
+
+#include "sun_tools_attach_AttachProviderImpl.h"
+
+/*
+ * Class:     sun_tools_attach_AttachProviderImpl
+ * Method:    tempPath
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_sun_tools_attach_AttachProviderImpl_tempPath(JNIEnv *env, jclass cls)
+{
+    char buf[256];
+    DWORD bufLen, actualLen;
+    jstring result = NULL;
+
+    bufLen = sizeof(buf) / sizeof(char);
+    actualLen = GetTempPath(bufLen, buf);
+    if (actualLen > 0) {
+        char* bufP = buf;
+        if (actualLen > bufLen) {
+            actualLen += sizeof(char);
+            bufP = (char*)malloc(actualLen * sizeof(char));
+            actualLen = GetTempPath(actualLen, bufP);
+        }
+        if (actualLen > 0) {
+            result = JNU_NewStringPlatform(env, bufP);
+        }
+        if (bufP != buf) {
+            free((void*)bufP);
+        }
+    }
+    return result;
+}
+
+/*
+ * Class:     sun_tools_attach_AttachProviderImpl
+ * Method:    volumeFlags
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL
+Java_sun_tools_attach_AttachProviderImpl_volumeFlags(JNIEnv *env, jclass cls, jstring str)
+{
+    jboolean isCopy;
+    const char* volume;
+    DWORD result = 0;
+
+    volume = JNU_GetStringPlatformChars(env, str, &isCopy);
+    if (volume != NULL) {
+        DWORD componentLen, flags;
+        BOOL res = GetVolumeInformation(volume,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        &componentLen,
+                                        &flags,
+                                        NULL,
+                                        0);
+       if (res != 0) {
+           result = flags;
+       }
+       if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, str, volume);
+       }
+    }
+    return result;
+}
+
+
+/*
+ * Class:     sun_tools_attach_AttachProviderImpl
+ * Method:    enumProcesses
+ * Signature: ([JI)I
+ */
+JNIEXPORT jint JNICALL
+Java_sun_tools_attach_AttachProviderImpl_enumProcesses(JNIEnv *env, jclass cls,
+                                                       jintArray arr, jint max)
+{
+    DWORD size, bytesReturned;
+    DWORD* ptr;
+    jint result = 0;
+
+    size = max * sizeof(DWORD);
+    ptr = (DWORD*)malloc(size);
+    if (ptr != NULL) {
+        BOOL res = EnumProcesses(ptr, size, &bytesReturned);
+        if (res != 0) {
+            result = (jint)(bytesReturned / sizeof(DWORD));
+            (*env)->SetIntArrayRegion(env, arr, 0, (jsize)result, (jint*)ptr);
+        }
+        free((void*)ptr);
+    }
+    return result;
+}
+
+/*
+ * Class:     sun_tools_attach_AttachProviderImpl
+ * Method:    isLibraryLoadedByProcess
+ * Signature: (I[Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_sun_tools_attach_AttachProviderImpl_isLibraryLoadedByProcess(JNIEnv *env, jclass cls,
+                                                                  jstring str, jint processId)
+{
+    HANDLE hProcess;
+    jboolean isCopy;
+    const char* lib;
+    DWORD size, bytesReturned;
+    HMODULE* ptr;
+    jboolean result = JNI_FALSE;
+
+    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
+                           PROCESS_VM_READ,
+                           FALSE, (DWORD)processId);
+    if (hProcess == NULL) {
+        return JNI_FALSE;
+    }
+    lib = JNU_GetStringPlatformChars(env, str, &isCopy);
+    if (lib == NULL) {
+        CloseHandle(hProcess);
+        return JNI_FALSE;
+    }
+
+    /*
+     * Enumerate the modules that the process has opened and see if we have a
+     * match.
+     */
+    size = 1024 * sizeof(HMODULE);
+    ptr = (HMODULE*)malloc(size);
+    if (ptr != NULL) {
+        BOOL res = EnumProcessModules(hProcess, ptr, size, &bytesReturned);
+        if (res != 0) {
+            int count = bytesReturned / sizeof(HMODULE);
+            int i = 0;
+            while (i < count) {
+                char base[256];
+                BOOL res = GetModuleBaseName(hProcess, ptr[i], base, sizeof(base));
+                if (res != 0) {
+                    if (strcmp(base, lib) == 0) {
+                      result = JNI_TRUE;
+                      break;
+                    }
+                }
+                i++;
+            }
+        }
+        free((void*)ptr);
+    }
+    if (isCopy) {
+        JNU_ReleaseStringPlatformChars(env, str, lib);
+    }
+    CloseHandle(hProcess);
+
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c	Tue Aug 26 14:35:33 2014 -0700
@@ -0,0 +1,606 @@
+/*
+ * Copyright (c) 2005, 2014, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+#include <windows.h>
+#include <string.h>
+
+#include "jni.h"
+#include "jni_util.h"
+
+#include "sun_tools_attach_VirtualMachineImpl.h"
+
+
+/* kernel32 */
+typedef HINSTANCE (WINAPI* GetModuleHandleFunc) (LPCTSTR);
+typedef FARPROC (WINAPI* GetProcAddressFunc)(HMODULE, LPCSTR);
+
+/* only on Windows 64-bit or 32-bit application running under WOW64 */
+typedef BOOL (WINAPI *IsWow64ProcessFunc) (HANDLE, PBOOL);
+
+static GetModuleHandleFunc _GetModuleHandle;
+static GetProcAddressFunc _GetProcAddress;
+static IsWow64ProcessFunc _IsWow64Process;
+
+/* psapi */
+typedef BOOL  (WINAPI *EnumProcessModulesFunc)  (HANDLE, HMODULE *, DWORD, LPDWORD );
+typedef DWORD (WINAPI *GetModuleFileNameExFunc) ( HANDLE, HMODULE, LPTSTR, DWORD );
+
+/* exported function in target VM */
+typedef jint (WINAPI* EnqueueOperationFunc)
+    (const char* cmd, const char* arg1, const char* arg2, const char* arg3, const char* pipename);
+
+/* OpenProcess with SE_DEBUG_NAME privilege */
+static HANDLE
+doPrivilegedOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
+
+/* convert jstring to C string */
+static void jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, int len);
+
+
+/*
+ * Data copied to target process
+ */
+
+#define MAX_LIBNAME_LENGTH      16
+#define MAX_FUNC_LENGTH         32
+#define MAX_CMD_LENGTH          16
+#define MAX_ARG_LENGTH          1024
+#define MAX_ARGS                3
+#define MAX_PIPE_NAME_LENGTH    256
+
+typedef struct {
+   GetModuleHandleFunc _GetModuleHandle;
+   GetProcAddressFunc _GetProcAddress;
+   char jvmLib[MAX_LIBNAME_LENGTH];         /* "jvm.dll" */
+   char func1[MAX_FUNC_LENGTH];
+   char func2[MAX_FUNC_LENGTH];
+   char cmd[MAX_CMD_LENGTH];                /* "load", "dump", ...      */
+   char arg[MAX_ARGS][MAX_ARG_LENGTH];      /* arguments to command     */
+   char pipename[MAX_PIPE_NAME_LENGTH];
+} DataBlock;
+
+/*
+ * Return codes from enqueue function executed in target VM
+ */
+#define ERR_OPEN_JVM_FAIL           200
+#define ERR_GET_ENQUEUE_FUNC_FAIL   201
+
+
+/*
+ * Code copied to target process
+ */
+#pragma check_stack (off)
+DWORD WINAPI jvm_attach_thread_func(DataBlock *pData)
+{
+    HINSTANCE h;
+    EnqueueOperationFunc addr;
+
+    h = pData->_GetModuleHandle(pData->jvmLib);
+    if (h == NULL) {
+        return ERR_OPEN_JVM_FAIL;
+    }
+
+    addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func1));
+    if (addr == NULL) {
+        addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func2));
+    }
+    if (addr == NULL) {
+        return ERR_GET_ENQUEUE_FUNC_FAIL;
+    }
+
+    /* "null" command - does nothing in the target VM */
+    if (pData->cmd[0] == '\0') {
+        return 0;
+    } else {
+        return (*addr)(pData->cmd, pData->arg[0], pData->arg[1], pData->arg[2], pData->pipename);
+    }
+}
+
+/* This function marks the end of jvm_attach_thread_func. */
+void jvm_attach_thread_func_end (void) {
+}
+#pragma check_stack
+
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_init
+  (JNIEnv *env, jclass cls)
+{
+    // All following APIs exist on Windows XP with SP2/Windows Server 2008
+    _GetModuleHandle = (GetModuleHandleFunc)GetModuleHandle;
+    _GetProcAddress = (GetProcAddressFunc)GetProcAddress;
+    _IsWow64Process = (IsWow64ProcessFunc)IsWow64Process;
+}
+
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    generateStub
+ * Signature: ()[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_sun_tools_attach_VirtualMachineImpl_generateStub
+  (JNIEnv *env, jclass cls)
+{
+    /*
+     * We should replace this with a real stub generator at some point
+     */
+    DWORD len;
+    jbyteArray array;
+
+    len = (DWORD)((LPBYTE) jvm_attach_thread_func_end - (LPBYTE) jvm_attach_thread_func);
+    array= (*env)->NewByteArray(env, (jsize)len);
+    if (array != NULL) {
+        (*env)->SetByteArrayRegion(env, array, 0, (jint)len, (jbyte*)&jvm_attach_thread_func);
+    }
+    return array;
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    openProcess
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL Java_sun_tools_attach_VirtualMachineImpl_openProcess
+  (JNIEnv *env, jclass cls, jint pid)
+{
+    HANDLE hProcess = NULL;
+
+    if (pid == (jint) GetCurrentProcessId()) {
+        /* process is attaching to itself; get a pseudo handle instead */
+        hProcess = GetCurrentProcess();
+        /* duplicate the pseudo handle so it can be used in more contexts */
+        if (DuplicateHandle(hProcess, hProcess, hProcess, &hProcess,
+                PROCESS_ALL_ACCESS, FALSE, 0) == 0) {
+            /*
+             * Could not duplicate the handle which isn't a good sign,
+             * but we'll try again with OpenProcess() below.
+             */
+            hProcess = NULL;
+        }
+    }
+
+    if (hProcess == NULL) {
+        /*
+         * Attempt to open process. If it fails then we try to enable the
+         * SE_DEBUG_NAME privilege and retry.
+         */
+        hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
+        if (hProcess == NULL && GetLastError() == ERROR_ACCESS_DENIED) {
+            hProcess = doPrivilegedOpenProcess(PROCESS_ALL_ACCESS, FALSE,
+                           (DWORD)pid);
+        }
+
+        if (hProcess == NULL) {
+            if (GetLastError() == ERROR_INVALID_PARAMETER) {
+                JNU_ThrowIOException(env, "no such process");
+            } else {
+                char err_mesg[255];
+                /* include the last error in the default detail message */
+                sprintf(err_mesg, "OpenProcess(pid=%d) failed; LastError=0x%x",
+                    (int)pid, (int)GetLastError());
+                JNU_ThrowIOExceptionWithLastError(env, err_mesg);
+            }
+            return (jlong)0;
+        }
+    }
+
+    /*
+     * On Windows 64-bit we need to handle 32-bit tools trying to attach to 64-bit
+     * processes (and visa versa). X-architecture attaching is currently not supported
+     * by this implementation.
+     */
+    if (_IsWow64Process != NULL) {
+        BOOL isCurrent32bit, isTarget32bit;
+        (*_IsWow64Process)(GetCurrentProcess(), &isCurrent32bit);
+        (*_IsWow64Process)(hProcess, &isTarget32bit);
+
+        if (isCurrent32bit != isTarget32bit) {
+            CloseHandle(hProcess);
+            #ifdef _WIN64
+              JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException",
+                  "Unable to attach to 32-bit process running under WOW64");
+            #else
+              JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException",
+                  "Unable to attach to 64-bit process");
+            #endif
+        }
+    }
+
+    return (jlong)hProcess;
+}
+
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    closeProcess
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_closeProcess
+  (JNIEnv *env, jclass cls, jlong hProcess)
+{
+    CloseHandle((HANDLE)hProcess);
+}
+
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    createPipe
+ * Signature: (Ljava/lang/String;)J
+ */
+JNIEXPORT jlong JNICALL Java_sun_tools_attach_VirtualMachineImpl_createPipe
+  (JNIEnv *env, jclass cls, jstring pipename)
+{
+    HANDLE hPipe;
+    char name[MAX_PIPE_NAME_LENGTH];
+
+    jstring_to_cstring(env, pipename, name, MAX_PIPE_NAME_LENGTH);
+
+    hPipe = CreateNamedPipe(
+          name,                         // pipe name
+          PIPE_ACCESS_INBOUND,          // read access
+          PIPE_TYPE_BYTE |              // byte mode
+            PIPE_READMODE_BYTE |
+            PIPE_WAIT,                  // blocking mode
+          1,                            // max. instances
+          128,                          // output buffer size
+          8192,                         // input buffer size
+          NMPWAIT_USE_DEFAULT_WAIT,     // client time-out
+          NULL);                        // default security attribute
+
+    if (hPipe == INVALID_HANDLE_VALUE) {
+        char msg[256];
+        _snprintf(msg, sizeof(msg), "CreateNamedPipe failed: %d", GetLastError());
+        JNU_ThrowIOExceptionWithLastError(env, msg);
+    }
+    return (jlong)hPipe;
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    closePipe
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_closePipe
+  (JNIEnv *env, jclass cls, jlong hPipe)
+{
+    CloseHandle( (HANDLE)hPipe );
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    connectPipe
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connectPipe
+  (JNIEnv *env, jclass cls, jlong hPipe)
+{
+    BOOL fConnected;
+
+    fConnected = ConnectNamedPipe((HANDLE)hPipe, NULL) ?
+        TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+    if (!fConnected) {
+        JNU_ThrowIOExceptionWithLastError(env, "ConnectNamedPipe failed");
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    readPipe
+ * Signature: (J[BII)I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_readPipe
+  (JNIEnv *env, jclass cls, jlong hPipe, jbyteArray ba, jint off, jint baLen)
+{
+    unsigned char buf[128];
+    DWORD len, nread, remaining;
+    BOOL fSuccess;
+
+    len = sizeof(buf);
+    remaining = (DWORD)(baLen - off);
+    if (len > remaining) {
+        len = remaining;
+    }
+
+    fSuccess = ReadFile(
+         (HANDLE)hPipe,         // handle to pipe
+         buf,                   // buffer to receive data
+         len,                   // size of buffer
+         &nread,                // number of bytes read
+         NULL);                 // not overlapped I/O
+
+    if (!fSuccess) {
+        if (GetLastError() == ERROR_BROKEN_PIPE) {
+            return (jint)-1;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "ReadFile");
+        }
+    } else {
+        if (nread == 0) {
+            return (jint)-1;        // EOF
+        } else {
+            (*env)->SetByteArrayRegion(env, ba, off, (jint)nread, (jbyte *)(buf));
+        }
+    }
+
+    return (jint)nread;
+}
+
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    enqueue
+ * Signature: (JZLjava/lang/String;[Ljava/lang/Object;)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue
+  (JNIEnv *env, jclass cls, jlong handle, jbyteArray stub, jstring cmd,
+   jstring pipename, jobjectArray args)
+{
+    DataBlock data;
+    DataBlock* pData;
+    DWORD* pCode;
+    DWORD stubLen;
+    HANDLE hProcess, hThread;
+    jint argsLen, i;
+    jbyte* stubCode;
+    jboolean isCopy;
+
+    /*
+     * Setup data to copy to target process
+     */
+    data._GetModuleHandle = _GetModuleHandle;
+    data._GetProcAddress = _GetProcAddress;
+
+    strcpy(data.jvmLib, "jvm");
+    strcpy(data.func1, "JVM_EnqueueOperation");
+    strcpy(data.func2, "_JVM_EnqueueOperation@20");
+
+    /*
+     * Command and arguments
+     */
+    jstring_to_cstring(env, cmd, data.cmd, MAX_CMD_LENGTH);
+    argsLen = (*env)->GetArrayLength(env, args);
+
+    if (argsLen > 0) {
+        if (argsLen > MAX_ARGS) {
+            JNU_ThrowInternalError(env, "Too many arguments");
+            return;
+        }
+        for (i=0; i<argsLen; i++) {
+            jobject obj = (*env)->GetObjectArrayElement(env, args, i);
+            if (obj == NULL) {
+                data.arg[i][0] = '\0';
+            } else {
+                jstring_to_cstring(env, obj, data.arg[i], MAX_ARG_LENGTH);
+            }
+            if ((*env)->ExceptionOccurred(env)) return;
+        }
+    }
+    for (i=argsLen; i<MAX_ARGS; i++) {
+        data.arg[i][0] = '\0';
+    }
+
+    /* pipe name */
+    jstring_to_cstring(env, pipename, data.pipename, MAX_PIPE_NAME_LENGTH);
+
+    /*
+     * Allocate memory in target process for data and code stub
+     * (assumed aligned and matches architecture of target process)
+     */
+    hProcess = (HANDLE)handle;
+
+    pData = (DataBlock*) VirtualAllocEx( hProcess, 0, sizeof(DataBlock), MEM_COMMIT, PAGE_READWRITE );
+    if (pData == NULL) {
+        JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed");
+        return;
+    }
+    WriteProcessMemory( hProcess, (LPVOID)pData, (LPCVOID)&data, (SIZE_T)sizeof(DataBlock), NULL );
+
+
+    stubLen = (DWORD)(*env)->GetArrayLength(env, stub);
+    stubCode = (*env)->GetByteArrayElements(env, stub, &isCopy);
+
+    if ((*env)->ExceptionOccurred(env)) return;
+
+    pCode = (PDWORD) VirtualAllocEx( hProcess, 0, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
+    if (pCode == NULL) {
+        JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed");
+        VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE);
+        return;
+    }
+    WriteProcessMemory( hProcess, (LPVOID)pCode, (LPCVOID)stubCode, (SIZE_T)stubLen, NULL );
+    if (isCopy) {
+        (*env)->ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT);
+    }
+
+    /*
+     * Create thread in target process to execute code
+     */
+    hThread = CreateRemoteThread( hProcess,
+                                  NULL,
+                                  0,
+                                  (LPTHREAD_START_ROUTINE) pCode,
+                                  pData,
+                                  0,
+                                  NULL );
+    if (hThread != NULL) {
+        if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0) {
+            JNU_ThrowIOExceptionWithLastError(env, "WaitForSingleObject failed");
+        } else {
+            DWORD exitCode;
+            GetExitCodeThread(hThread, &exitCode);
+            if (exitCode) {
+                switch (exitCode) {
+                    case ERR_OPEN_JVM_FAIL :
+                        JNU_ThrowIOException(env,
+                            "jvm.dll not loaded by target process");
+                        break;
+                    case ERR_GET_ENQUEUE_FUNC_FAIL :
+                        JNU_ThrowIOException(env,
+                            "Unable to enqueue operation: the target VM does not support attach mechanism");
+                        break;
+                    default :
+                        JNU_ThrowInternalError(env,
+                            "Remote thread failed for unknown reason");
+                }
+            }
+        }
+        CloseHandle(hThread);
+    } else {
+        if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
+            //
+            // This error will occur when attaching to a process belonging to
+            // another terminal session. See "Remarks":
+            // http://msdn.microsoft.com/en-us/library/ms682437%28VS.85%29.aspx
+            //
+            JNU_ThrowIOException(env,
+                "Insufficient memory or insufficient privileges to attach");
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "CreateRemoteThread failed");
+        }
+    }
+
+    VirtualFreeEx(hProcess, pCode, 0, MEM_RELEASE);
+    VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE);
+}
+
+/*
+ * Attempts to enable the SE_DEBUG_NAME privilege and open the given process.
+ */
+static HANDLE
+doPrivilegedOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) {
+    HANDLE hToken;
+    HANDLE hProcess = NULL;
+    LUID luid;
+    TOKEN_PRIVILEGES tp, tpPrevious;
+    DWORD retLength, error;
+
+    /*
+     * Get the access token
+     */
+    if (!OpenThreadToken(GetCurrentThread(),
+                         TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
+                         FALSE,
+                         &hToken)) {
+        if (GetLastError() != ERROR_NO_TOKEN) {
+            return (HANDLE)NULL;
+        }
+
+        /*
+         * No access token for the thread so impersonate the security context
+         * of the process.
+         */
+        if (!ImpersonateSelf(SecurityImpersonation)) {
+            return (HANDLE)NULL;
+        }
+        if (!OpenThreadToken(GetCurrentThread(),
+                             TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
+                             FALSE,
+                             &hToken)) {
+            return (HANDLE)NULL;
+        }
+    }
+
+    /*
+     * Get LUID for the privilege
+     */
+    if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
+        error = GetLastError();
+        CloseHandle(hToken);
+        SetLastError(error);
+        return (HANDLE)NULL;
+    }
+
+    /*
+     * Enable the privilege
+     */
+    ZeroMemory(&tp, sizeof(tp));
+    tp.PrivilegeCount = 1;
+    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+    tp.Privileges[0].Luid = luid;
+
+    error = 0;
+    if (AdjustTokenPrivileges(hToken,
+                              FALSE,
+                              &tp,
+                              sizeof(TOKEN_PRIVILEGES),
+                              &tpPrevious,
+                              &retLength)) {
+        /*
+         * If we enabled the privilege then attempt to open the
+         * process.
+         */
+        if (GetLastError() == ERROR_SUCCESS) {
+            hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
+            if (hProcess == NULL) {
+                error = GetLastError();
+            }
+        } else {
+            error = ERROR_ACCESS_DENIED;
+        }
+
+        /*
+         * Revert to the previous privileges
+         */
+        AdjustTokenPrivileges(hToken,
+                              FALSE,
+                              &tpPrevious,
+                              retLength,
+                              NULL,
+                              NULL);
+    } else {
+        error = GetLastError();
+    }
+
+
+    /*
+     * Close token and restore error
+     */
+    CloseHandle(hToken);
+    SetLastError(error);
+
+    return hProcess;
+}
+
+/* convert jstring to C string */
+static void jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, int len) {
+    jboolean isCopy;
+    const char* str;
+
+    if (jstr == NULL) {
+        cstr[0] = '\0';
+    } else {
+        str = JNU_GetStringPlatformChars(env, jstr, &isCopy);
+        if ((*env)->ExceptionOccurred(env)) return;
+
+        strncpy(cstr, str, len);
+        cstr[len-1] = '\0';
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, jstr, str);
+        }
+    }
+}
--- a/src/jdk.attach/windows/native/libattach/WindowsAttachProvider.c	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2005, 2011, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-#include <windows.h>
-#include <stdlib.h>
-#include <string.h>
-#include <Psapi.h>
-
-#include "jni.h"
-#include "jni_util.h"
-
-#include "sun_tools_attach_WindowsAttachProvider.h"
-
-/*
- * Class:     sun_tools_attach_WindowsAttachProvider
- * Method:    tempPath
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL
-Java_sun_tools_attach_WindowsAttachProvider_tempPath(JNIEnv *env, jclass cls)
-{
-    char buf[256];
-    DWORD bufLen, actualLen;
-    jstring result = NULL;
-
-    bufLen = sizeof(buf) / sizeof(char);
-    actualLen = GetTempPath(bufLen, buf);
-    if (actualLen > 0) {
-        char* bufP = buf;
-        if (actualLen > bufLen) {
-            actualLen += sizeof(char);
-            bufP = (char*)malloc(actualLen * sizeof(char));
-            actualLen = GetTempPath(actualLen, bufP);
-        }
-        if (actualLen > 0) {
-            result = JNU_NewStringPlatform(env, bufP);
-        }
-        if (bufP != buf) {
-            free((void*)bufP);
-        }
-    }
-    return result;
-}
-
-/*
- * Class:     sun_tools_attach_WindowsAttachProvider
- * Method:    volumeFlags
- * Signature: ()J
- */
-JNIEXPORT jlong JNICALL
-Java_sun_tools_attach_WindowsAttachProvider_volumeFlags(JNIEnv *env, jclass cls, jstring str)
-{
-    jboolean isCopy;
-    const char* volume;
-    DWORD result = 0;
-
-    volume = JNU_GetStringPlatformChars(env, str, &isCopy);
-    if (volume != NULL) {
-        DWORD componentLen, flags;
-        BOOL res = GetVolumeInformation(volume,
-                                        NULL,
-                                        0,
-                                        NULL,
-                                        &componentLen,
-                                        &flags,
-                                        NULL,
-                                        0);
-       if (res != 0) {
-           result = flags;
-       }
-       if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, str, volume);
-       }
-    }
-    return result;
-}
-
-
-/*
- * Class:     sun_tools_attach_WindowsAttachProvider
- * Method:    enumProcesses
- * Signature: ([JI)I
- */
-JNIEXPORT jint JNICALL
-Java_sun_tools_attach_WindowsAttachProvider_enumProcesses(JNIEnv *env, jclass cls,
-                                                          jintArray arr, jint max)
-{
-    DWORD size, bytesReturned;
-    DWORD* ptr;
-    jint result = 0;
-
-    size = max * sizeof(DWORD);
-    ptr = (DWORD*)malloc(size);
-    if (ptr != NULL) {
-        BOOL res = EnumProcesses(ptr, size, &bytesReturned);
-        if (res != 0) {
-            result = (jint)(bytesReturned / sizeof(DWORD));
-            (*env)->SetIntArrayRegion(env, arr, 0, (jsize)result, (jint*)ptr);
-        }
-        free((void*)ptr);
-    }
-    return result;
-}
-
-/*
- * Class:     sun_tools_attach_WindowsAttachProvider
- * Method:    isLibraryLoadedByProcess
- * Signature: (I[Ljava/lang/String;)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_sun_tools_attach_WindowsAttachProvider_isLibraryLoadedByProcess(JNIEnv *env, jclass cls,
-                                                                     jstring str, jint processId)
-{
-    HANDLE hProcess;
-    jboolean isCopy;
-    const char* lib;
-    DWORD size, bytesReturned;
-    HMODULE* ptr;
-    jboolean result = JNI_FALSE;
-
-    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
-                           PROCESS_VM_READ,
-                           FALSE, (DWORD)processId);
-    if (hProcess == NULL) {
-        return JNI_FALSE;
-    }
-    lib = JNU_GetStringPlatformChars(env, str, &isCopy);
-    if (lib == NULL) {
-        CloseHandle(hProcess);
-        return JNI_FALSE;
-    }
-
-    /*
-     * Enumerate the modules that the process has opened and see if we have a
-     * match.
-     */
-    size = 1024 * sizeof(HMODULE);
-    ptr = (HMODULE*)malloc(size);
-    if (ptr != NULL) {
-        BOOL res = EnumProcessModules(hProcess, ptr, size, &bytesReturned);
-        if (res != 0) {
-            int count = bytesReturned / sizeof(HMODULE);
-            int i = 0;
-            while (i < count) {
-                char base[256];
-                BOOL res = GetModuleBaseName(hProcess, ptr[i], base, sizeof(base));
-                if (res != 0) {
-                    if (strcmp(base, lib) == 0) {
-                      result = JNI_TRUE;
-                      break;
-                    }
-                }
-                i++;
-            }
-        }
-        free((void*)ptr);
-    }
-    if (isCopy) {
-        JNU_ReleaseStringPlatformChars(env, str, lib);
-    }
-    CloseHandle(hProcess);
-
-    return result;
-}
--- a/src/jdk.attach/windows/native/libattach/WindowsVirtualMachine.c	Tue Aug 26 11:43:19 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,606 +0,0 @@
-/*
- * Copyright (c) 2005, 2014, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-#include <windows.h>
-#include <string.h>
-
-#include "jni.h"
-#include "jni_util.h"
-
-#include "sun_tools_attach_WindowsVirtualMachine.h"
-
-
-/* kernel32 */
-typedef HINSTANCE (WINAPI* GetModuleHandleFunc) (LPCTSTR);
-typedef FARPROC (WINAPI* GetProcAddressFunc)(HMODULE, LPCSTR);
-
-/* only on Windows 64-bit or 32-bit application running under WOW64 */
-typedef BOOL (WINAPI *IsWow64ProcessFunc) (HANDLE, PBOOL);
-
-static GetModuleHandleFunc _GetModuleHandle;
-static GetProcAddressFunc _GetProcAddress;
-static IsWow64ProcessFunc _IsWow64Process;
-
-/* psapi */
-typedef BOOL  (WINAPI *EnumProcessModulesFunc)  (HANDLE, HMODULE *, DWORD, LPDWORD );
-typedef DWORD (WINAPI *GetModuleFileNameExFunc) ( HANDLE, HMODULE, LPTSTR, DWORD );
-
-/* exported function in target VM */
-typedef jint (WINAPI* EnqueueOperationFunc)
-    (const char* cmd, const char* arg1, const char* arg2, const char* arg3, const char* pipename);
-
-/* OpenProcess with SE_DEBUG_NAME privilege */
-static HANDLE
-doPrivilegedOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
-
-/* convert jstring to C string */
-static void jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, int len);
-
-
-/*
- * Data copied to target process
- */
-
-#define MAX_LIBNAME_LENGTH      16
-#define MAX_FUNC_LENGTH         32
-#define MAX_CMD_LENGTH          16
-#define MAX_ARG_LENGTH          1024
-#define MAX_ARGS                3
-#define MAX_PIPE_NAME_LENGTH    256
-
-typedef struct {
-   GetModuleHandleFunc _GetModuleHandle;
-   GetProcAddressFunc _GetProcAddress;
-   char jvmLib[MAX_LIBNAME_LENGTH];         /* "jvm.dll" */
-   char func1[MAX_FUNC_LENGTH];
-   char func2[MAX_FUNC_LENGTH];
-   char cmd[MAX_CMD_LENGTH];                /* "load", "dump", ...      */
-   char arg[MAX_ARGS][MAX_ARG_LENGTH];      /* arguments to command     */
-   char pipename[MAX_PIPE_NAME_LENGTH];
-} DataBlock;
-
-/*
- * Return codes from enqueue function executed in target VM
- */
-#define ERR_OPEN_JVM_FAIL           200
-#define ERR_GET_ENQUEUE_FUNC_FAIL   201
-
-
-/*
- * Code copied to target process
- */
-#pragma check_stack (off)
-DWORD WINAPI jvm_attach_thread_func(DataBlock *pData)
-{
-    HINSTANCE h;
-    EnqueueOperationFunc addr;
-
-    h = pData->_GetModuleHandle(pData->jvmLib);
-    if (h == NULL) {
-        return ERR_OPEN_JVM_FAIL;
-    }
-
-    addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func1));
-    if (addr == NULL) {
-        addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func2));
-    }
-    if (addr == NULL) {
-        return ERR_GET_ENQUEUE_FUNC_FAIL;
-    }
-
-    /* "null" command - does nothing in the target VM */
-    if (pData->cmd[0] == '\0') {
-        return 0;
-    } else {
-        return (*addr)(pData->cmd, pData->arg[0], pData->arg[1], pData->arg[2], pData->pipename);
-    }
-}
-
-/* This function marks the end of jvm_attach_thread_func. */
-void jvm_attach_thread_func_end (void) {
-}
-#pragma check_stack
-
-
-/*
- * Class:     sun_tools_attach_WindowsVirtualMachine
- * Method:    init
- * Signature: ()V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_init
-  (JNIEnv *env, jclass cls)
-{
-    // All following APIs exist on Windows XP with SP2/Windows Server 2008
-    _GetModuleHandle = (GetModuleHandleFunc)GetModuleHandle;
-    _GetProcAddress = (GetProcAddressFunc)GetProcAddress;
-    _IsWow64Process = (IsWow64ProcessFunc)IsWow64Process;
-}
-
-
-/*
- * Class:     sun_tools_attach_WindowsVirtualMachine
- * Method:    generateStub
- * Signature: ()[B
- */
-JNIEXPORT jbyteArray JNICALL Java_sun_tools_attach_WindowsVirtualMachine_generateStub
-  (JNIEnv *env, jclass cls)
-{
-    /*
-     * We should replace this with a real stub generator at some point
-     */
-    DWORD len;
-    jbyteArray array;
-
-    len = (DWORD)((LPBYTE) jvm_attach_thread_func_end - (LPBYTE) jvm_attach_thread_func);
-    array= (*env)->NewByteArray(env, (jsize)len);
-    if (array != NULL) {
-        (*env)->SetByteArrayRegion(env, array, 0, (jint)len, (jbyte*)&jvm_attach_thread_func);
-    }
-    return array;
-}
-
-/*
- * Class:     sun_tools_attach_WindowsVirtualMachine
- * Method:    openProcess
- * Signature: (I)J
- */
-JNIEXPORT jlong JNICALL Java_sun_tools_attach_WindowsVirtualMachine_openProcess
-  (JNIEnv *env, jclass cls, jint pid)
-{
-    HANDLE hProcess = NULL;
-
-    if (pid == (jint) GetCurrentProcessId()) {
-        /* process is attaching to itself; get a pseudo handle instead */
-        hProcess = GetCurrentProcess();
-        /* duplicate the pseudo handle so it can be used in more contexts */
-        if (DuplicateHandle(hProcess, hProcess, hProcess, &hProcess,
-                PROCESS_ALL_ACCESS, FALSE, 0) == 0) {
-            /*
-             * Could not duplicate the handle which isn't a good sign,
-             * but we'll try again with OpenProcess() below.
-             */
-            hProcess = NULL;
-        }
-    }
-
-    if (hProcess == NULL) {
-        /*
-         * Attempt to open process. If it fails then we try to enable the
-         * SE_DEBUG_NAME privilege and retry.
-         */
-        hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
-        if (hProcess == NULL && GetLastError() == ERROR_ACCESS_DENIED) {
-            hProcess = doPrivilegedOpenProcess(PROCESS_ALL_ACCESS, FALSE,
-                           (DWORD)pid);
-        }
-
-        if (hProcess == NULL) {
-            if (GetLastError() == ERROR_INVALID_PARAMETER) {
-                JNU_ThrowIOException(env, "no such process");
-            } else {
-                char err_mesg[255];
-                /* include the last error in the default detail message */
-                sprintf(err_mesg, "OpenProcess(pid=%d) failed; LastError=0x%x",
-                    (int)pid, (int)GetLastError());
-                JNU_ThrowIOExceptionWithLastError(env, err_mesg);
-            }
-            return (jlong)0;
-        }
-    }
-
-    /*
-     * On Windows 64-bit we need to handle 32-bit tools trying to attach to 64-bit
-     * processes (and visa versa). X-architecture attaching is currently not supported
-     * by this implementation.
-     */
-    if (_IsWow64Process != NULL) {
-        BOOL isCurrent32bit, isTarget32bit;
-        (*_IsWow64Process)(GetCurrentProcess(), &isCurrent32bit);
-        (*_IsWow64Process)(hProcess, &isTarget32bit);
-
-        if (isCurrent32bit != isTarget32bit) {
-            CloseHandle(hProcess);
-            #ifdef _WIN64
-              JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException",
-                  "Unable to attach to 32-bit process running under WOW64");
-            #else
-              JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException",
-                  "Unable to attach to 64-bit process");
-            #endif
-        }
-    }
-
-    return (jlong)hProcess;
-}
-
-
-/*
- * Class:     sun_tools_attach_WindowsVirtualMachine
- * Method:    closeProcess
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_closeProcess
-  (JNIEnv *env, jclass cls, jlong hProcess)
-{
-    CloseHandle((HANDLE)hProcess);
-}
-
-
-/*
- * Class:     sun_tools_attach_WindowsVirtualMachine
- * Method:    createPipe
- * Signature: (Ljava/lang/String;)J
- */
-JNIEXPORT jlong JNICALL Java_sun_tools_attach_WindowsVirtualMachine_createPipe
-  (JNIEnv *env, jclass cls, jstring pipename)
-{
-    HANDLE hPipe;
-    char name[MAX_PIPE_NAME_LENGTH];
-
-    jstring_to_cstring(env, pipename, name, MAX_PIPE_NAME_LENGTH);
-
-    hPipe = CreateNamedPipe(
-          name,                         // pipe name
-          PIPE_ACCESS_INBOUND,          // read access
-          PIPE_TYPE_BYTE |              // byte mode
-            PIPE_READMODE_BYTE |
-            PIPE_WAIT,                  // blocking mode
-          1,                            // max. instances
-          128,                          // output buffer size
-          8192,                         // input buffer size
-          NMPWAIT_USE_DEFAULT_WAIT,     // client time-out
-          NULL);                        // default security attribute
-
-    if (hPipe == INVALID_HANDLE_VALUE) {
-        char msg[256];
-        _snprintf(msg, sizeof(msg), "CreateNamedPipe failed: %d", GetLastError());
-        JNU_ThrowIOExceptionWithLastError(env, msg);
-    }
-    return (jlong)hPipe;
-}
-
-/*
- * Class:     sun_tools_attach_WindowsVirtualMachine
- * Method:    closePipe
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_closePipe
-  (JNIEnv *env, jclass cls, jlong hPipe)
-{
-    CloseHandle( (HANDLE)hPipe );
-}
-
-/*
- * Class:     sun_tools_attach_WindowsVirtualMachine
- * Method:    connectPipe
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_connectPipe
-  (JNIEnv *env, jclass cls, jlong hPipe)
-{
-    BOOL fConnected;
-
-    fConnected = ConnectNamedPipe((HANDLE)hPipe, NULL) ?
-        TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
-    if (!fConnected) {
-        JNU_ThrowIOExceptionWithLastError(env, "ConnectNamedPipe failed");
-    }
-}
-
-/*
- * Class:     sun_tools_attach_WindowsVirtualMachine
- * Method:    readPipe
- * Signature: (J[BII)I
- */
-JNIEXPORT jint JNICALL Java_sun_tools_attach_WindowsVirtualMachine_readPipe
-  (JNIEnv *env, jclass cls, jlong hPipe, jbyteArray ba, jint off, jint baLen)
-{
-    unsigned char buf[128];
-    DWORD len, nread, remaining;
-    BOOL fSuccess;
-
-    len = sizeof(buf);
-    remaining = (DWORD)(baLen - off);
-    if (len > remaining) {
-        len = remaining;
-    }
-
-    fSuccess = ReadFile(
-         (HANDLE)hPipe,         // handle to pipe
-         buf,                   // buffer to receive data
-         len,                   // size of buffer
-         &nread,                // number of bytes read
-         NULL);                 // not overlapped I/O
-
-    if (!fSuccess) {
-        if (GetLastError() == ERROR_BROKEN_PIPE) {
-            return (jint)-1;
-        } else {
-            JNU_ThrowIOExceptionWithLastError(env, "ReadFile");
-        }
-    } else {
-        if (nread == 0) {
-            return (jint)-1;        // EOF
-        } else {
-            (*env)->SetByteArrayRegion(env, ba, off, (jint)nread, (jbyte *)(buf));
-        }
-    }
-
-    return (jint)nread;
-}
-
-
-/*
- * Class:     sun_tools_attach_WindowsVirtualMachine
- * Method:    enqueue
- * Signature: (JZLjava/lang/String;[Ljava/lang/Object;)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_enqueue
-  (JNIEnv *env, jclass cls, jlong handle, jbyteArray stub, jstring cmd,
-   jstring pipename, jobjectArray args)
-{
-    DataBlock data;
-    DataBlock* pData;
-    DWORD* pCode;
-    DWORD stubLen;
-    HANDLE hProcess, hThread;
-    jint argsLen, i;
-    jbyte* stubCode;
-    jboolean isCopy;
-
-    /*
-     * Setup data to copy to target process
-     */
-    data._GetModuleHandle = _GetModuleHandle;
-    data._GetProcAddress = _GetProcAddress;
-
-    strcpy(data.jvmLib, "jvm");
-    strcpy(data.func1, "JVM_EnqueueOperation");
-    strcpy(data.func2, "_JVM_EnqueueOperation@20");
-
-    /*
-     * Command and arguments
-     */
-    jstring_to_cstring(env, cmd, data.cmd, MAX_CMD_LENGTH);
-    argsLen = (*env)->GetArrayLength(env, args);
-
-    if (argsLen > 0) {
-        if (argsLen > MAX_ARGS) {
-            JNU_ThrowInternalError(env, "Too many arguments");
-            return;
-        }
-        for (i=0; i<argsLen; i++) {
-            jobject obj = (*env)->GetObjectArrayElement(env, args, i);
-            if (obj == NULL) {
-                data.arg[i][0] = '\0';
-            } else {
-                jstring_to_cstring(env, obj, data.arg[i], MAX_ARG_LENGTH);
-            }
-            if ((*env)->ExceptionOccurred(env)) return;
-        }
-    }
-    for (i=argsLen; i<MAX_ARGS; i++) {
-        data.arg[i][0] = '\0';
-    }
-
-    /* pipe name */
-    jstring_to_cstring(env, pipename, data.pipename, MAX_PIPE_NAME_LENGTH);
-
-    /*
-     * Allocate memory in target process for data and code stub
-     * (assumed aligned and matches architecture of target process)
-     */
-    hProcess = (HANDLE)handle;
-
-    pData = (DataBlock*) VirtualAllocEx( hProcess, 0, sizeof(DataBlock), MEM_COMMIT, PAGE_READWRITE );
-    if (pData == NULL) {
-        JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed");
-        return;
-    }
-    WriteProcessMemory( hProcess, (LPVOID)pData, (LPCVOID)&data, (SIZE_T)sizeof(DataBlock), NULL );
-
-
-    stubLen = (DWORD)(*env)->GetArrayLength(env, stub);
-    stubCode = (*env)->GetByteArrayElements(env, stub, &isCopy);
-
-    if ((*env)->ExceptionOccurred(env)) return;
-
-    pCode = (PDWORD) VirtualAllocEx( hProcess, 0, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
-    if (pCode == NULL) {
-        JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed");
-        VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE);
-        return;
-    }
-    WriteProcessMemory( hProcess, (LPVOID)pCode, (LPCVOID)stubCode, (SIZE_T)stubLen, NULL );
-    if (isCopy) {
-        (*env)->ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT);
-    }
-
-    /*
-     * Create thread in target process to execute code
-     */
-    hThread = CreateRemoteThread( hProcess,
-                                  NULL,
-                                  0,
-                                  (LPTHREAD_START_ROUTINE) pCode,
-                                  pData,
-                                  0,
-                                  NULL );
-    if (hThread != NULL) {
-        if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0) {
-            JNU_ThrowIOExceptionWithLastError(env, "WaitForSingleObject failed");
-        } else {
-            DWORD exitCode;
-            GetExitCodeThread(hThread, &exitCode);
-            if (exitCode) {
-                switch (exitCode) {
-                    case ERR_OPEN_JVM_FAIL :
-                        JNU_ThrowIOException(env,
-                            "jvm.dll not loaded by target process");
-                        break;
-                    case ERR_GET_ENQUEUE_FUNC_FAIL :
-                        JNU_ThrowIOException(env,
-                            "Unable to enqueue operation: the target VM does not support attach mechanism");
-                        break;
-                    default :
-                        JNU_ThrowInternalError(env,
-                            "Remote thread failed for unknown reason");
-                }
-            }
-        }
-        CloseHandle(hThread);
-    } else {
-        if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
-            //
-            // This error will occur when attaching to a process belonging to
-            // another terminal session. See "Remarks":
-            // http://msdn.microsoft.com/en-us/library/ms682437%28VS.85%29.aspx
-            //
-            JNU_ThrowIOException(env,
-                "Insufficient memory or insufficient privileges to attach");
-        } else {
-            JNU_ThrowIOExceptionWithLastError(env, "CreateRemoteThread failed");
-        }
-    }
-
-    VirtualFreeEx(hProcess, pCode, 0, MEM_RELEASE);
-    VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE);
-}
-
-/*
- * Attempts to enable the SE_DEBUG_NAME privilege and open the given process.
- */
-static HANDLE
-doPrivilegedOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) {
-    HANDLE hToken;
-    HANDLE hProcess = NULL;
-    LUID luid;
-    TOKEN_PRIVILEGES tp, tpPrevious;
-    DWORD retLength, error;
-
-    /*
-     * Get the access token
-     */
-    if (!OpenThreadToken(GetCurrentThread(),
-                         TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
-                         FALSE,
-                         &hToken)) {
-        if (GetLastError() != ERROR_NO_TOKEN) {
-            return (HANDLE)NULL;
-        }
-
-        /*
-         * No access token for the thread so impersonate the security context
-         * of the process.
-         */
-        if (!ImpersonateSelf(SecurityImpersonation)) {
-            return (HANDLE)NULL;
-        }
-        if (!OpenThreadToken(GetCurrentThread(),
-                             TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
-                             FALSE,
-                             &hToken)) {
-            return (HANDLE)NULL;
-        }
-    }
-
-    /*
-     * Get LUID for the privilege
-     */
-    if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
-        error = GetLastError();
-        CloseHandle(hToken);
-        SetLastError(error);
-        return (HANDLE)NULL;
-    }
-
-    /*
-     * Enable the privilege
-     */
-    ZeroMemory(&tp, sizeof(tp));
-    tp.PrivilegeCount = 1;
-    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
-    tp.Privileges[0].Luid = luid;
-
-    error = 0;
-    if (AdjustTokenPrivileges(hToken,
-                              FALSE,
-                              &tp,
-                              sizeof(TOKEN_PRIVILEGES),
-                              &tpPrevious,
-                              &retLength)) {
-        /*
-         * If we enabled the privilege then attempt to open the
-         * process.
-         */
-        if (GetLastError() == ERROR_SUCCESS) {
-            hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
-            if (hProcess == NULL) {
-                error = GetLastError();
-            }
-        } else {
-            error = ERROR_ACCESS_DENIED;
-        }
-
-        /*
-         * Revert to the previous privileges
-         */
-        AdjustTokenPrivileges(hToken,
-                              FALSE,
-                              &tpPrevious,
-                              retLength,
-                              NULL,
-                              NULL);
-    } else {
-        error = GetLastError();
-    }
-
-
-    /*
-     * Close token and restore error
-     */
-    CloseHandle(hToken);
-    SetLastError(error);
-
-    return hProcess;
-}
-
-/* convert jstring to C string */
-static void jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, int len) {
-    jboolean isCopy;
-    const char* str;
-
-    if (jstr == NULL) {
-        cstr[0] = '\0';
-    } else {
-        str = JNU_GetStringPlatformChars(env, jstr, &isCopy);
-        if ((*env)->ExceptionOccurred(env)) return;
-
-        strncpy(cstr, str, len);
-        cstr[len-1] = '\0';
-        if (isCopy) {
-            JNU_ReleaseStringPlatformChars(env, jstr, str);
-        }
-    }
-}