8055230: Rename attach provider implementation class be platform neutral
Reviewed-by: alanb, chegar, dfuchs, dholmes, erikj, sla
--- a/jdk/make/gensrc/GensrcProviders.gmk Tue Aug 26 11:43:19 2014 -0700
+++ b/jdk/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/jdk/make/lib/Lib-jdk.attach.gmk Tue Aug 26 11:43:19 2014 -0700
+++ b/jdk/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/jdk/make/mapfiles/libattach/mapfile-aix Tue Aug 26 11:43:19 2014 -0700
+++ b/jdk/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/jdk/make/mapfiles/libattach/mapfile-linux Tue Aug 26 11:43:19 2014 -0700
+++ b/jdk/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/jdk/make/mapfiles/libattach/mapfile-solaris Tue Aug 26 11:43:19 2014 -0700
+++ b/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider Tue Aug 26 11:43:19 2014 -0700
+++ b/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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);
- }
- }
-}