8147388: Add diagnostic commands to attach JVMTI agent.
Reviewed-by: jbachorik, sspitsyn
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp Wed Feb 17 18:02:03 2016 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp Thu Feb 18 23:26:43 2016 +0900
@@ -2200,6 +2200,16 @@
}
jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) {
+ // get agent name and options
+ const char* agent = op->arg(0);
+ const char* absParam = op->arg(1);
+ const char* options = op->arg(2);
+
+ return load_agent_library(agent, absParam, options, st);
+}
+
+jint JvmtiExport::load_agent_library(const char *agent, const char *absParam,
+ const char *options, outputStream* st) {
char ebuf[1024];
char buffer[JVM_MAXPATHLEN];
void* library = NULL;
@@ -2207,11 +2217,6 @@
const char *on_attach_symbols[] = AGENT_ONATTACH_SYMBOLS;
size_t num_symbol_entries = ARRAY_SIZE(on_attach_symbols);
- // get agent name and options
- const char* agent = op->arg(0);
- const char* absParam = op->arg(1);
- const char* options = op->arg(2);
-
// The abs paramter should be "true" or "false"
bool is_absolute_path = (absParam != NULL) && (strcmp(absParam,"true")==0);
--- a/hotspot/src/share/vm/prims/jvmtiExport.hpp Wed Feb 17 18:02:03 2016 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp Thu Feb 18 23:26:43 2016 +0900
@@ -372,6 +372,7 @@
static void transition_pending_onload_raw_monitors() NOT_JVMTI_RETURN;
// attach support
+ static jint load_agent_library(const char *agent, const char *absParam, const char *options, outputStream* out) NOT_JVMTI_RETURN_(JNI_ERR);
static jint load_agent_library(AttachOperation* op, outputStream* out) NOT_JVMTI_RETURN_(JNI_ERR);
// SetNativeMethodPrefix support
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Feb 17 18:02:03 2016 -0500
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Thu Feb 18 23:26:43 2016 +0900
@@ -71,6 +71,7 @@
#endif // INCLUDE_SERVICES
#if INCLUDE_JVMTI
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIDataDumpDCmd>(full_export, true, false));
+ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIAgentLoadDCmd>(full_export, true, false));
#endif // INCLUDE_JVMTI
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false));
@@ -254,6 +255,66 @@
}
}
+JVMTIAgentLoadDCmd::JVMTIAgentLoadDCmd(outputStream* output, bool heap) :
+ DCmdWithParser(output, heap),
+ _libpath("library path", "Absolute path of the JVMTI agent to load.",
+ "STRING", true),
+ _option("agent option", "Option string to pass the agent.", "STRING", false) {
+ _dcmdparser.add_dcmd_argument(&_libpath);
+ _dcmdparser.add_dcmd_argument(&_option);
+}
+
+void JVMTIAgentLoadDCmd::execute(DCmdSource source, TRAPS) {
+
+ if (_libpath.value() == NULL) {
+ output()->print_cr("JVMTI.agent_load dcmd needs library path.");
+ return;
+ }
+
+ char *suffix = strrchr(_libpath.value(), '.');
+ bool is_java_agent = (suffix != NULL) && (strncmp(".jar", suffix, 4) == 0);
+
+ if (is_java_agent) {
+ if (_option.value() == NULL) {
+ JvmtiExport::load_agent_library("instrument", "false",
+ _libpath.value(), output());
+ } else {
+ size_t opt_len = strlen(_libpath.value()) + strlen(_option.value()) + 2;
+ if (opt_len > 4096) {
+ output()->print_cr("JVMTI agent attach failed: Options is too long.");
+ return;
+ }
+
+ char *opt = (char *)os::malloc(opt_len, mtInternal);
+ if (opt == NULL) {
+ output()->print_cr("JVMTI agent attach failed: "
+ "Could not allocate %zu bytes for argument.",
+ opt_len);
+ return;
+ }
+
+ jio_snprintf(opt, opt_len, "%s=%s", _libpath.value(), _option.value());
+ JvmtiExport::load_agent_library("instrument", "false", opt, output());
+
+ os::free(opt);
+ }
+ } else {
+ JvmtiExport::load_agent_library(_libpath.value(), "true",
+ _option.value(), output());
+ }
+}
+
+int JVMTIAgentLoadDCmd::num_arguments() {
+ ResourceMark rm;
+ JVMTIAgentLoadDCmd* dcmd = new JVMTIAgentLoadDCmd(NULL, false);
+ if (dcmd != NULL) {
+ DCmdMark mark(dcmd);
+ return dcmd->_dcmdparser.num_arguments();
+ } else {
+ return 0;
+ }
+}
+
void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) {
// load sun.misc.VMSupport
Symbol* klass = vmSymbols::sun_misc_VMSupport();
--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp Wed Feb 17 18:02:03 2016 -0500
+++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp Thu Feb 18 23:26:43 2016 +0900
@@ -174,6 +174,26 @@
virtual void execute(DCmdSource source, TRAPS);
};
+class JVMTIAgentLoadDCmd : public DCmdWithParser {
+protected:
+ DCmdArgument<char*> _libpath;
+ DCmdArgument<char*> _option;
+public:
+ JVMTIAgentLoadDCmd(outputStream* output, bool heap);
+ static const char* name() { return "JVMTI.agent_load"; }
+ static const char* description() {
+ return "Load JVMTI native agent.";
+ }
+ static const char* impact() { return "Low"; }
+ static const JavaPermission permission() {
+ JavaPermission p = {"java.lang.management.ManagementPermission",
+ "control", NULL};
+ return p;
+ }
+ static int num_arguments();
+ virtual void execute(DCmdSource source, TRAPS);
+};
+
class VMDynamicLibrariesDCmd : public DCmd {
public:
VMDynamicLibrariesDCmd(outputStream* output, bool heap);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java Thu Feb 18 23:26:43 2016 +0900
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.*;
+import java.nio.file.*;
+import jdk.test.lib.*;
+import jdk.test.lib.dcmd.*;
+import org.testng.annotations.Test;
+
+/*
+ * Test to attach JVMTI java agent.
+ *
+ * @test
+ * @bug 8147388
+ * @library /testlibrary
+ * @modules java.base/sun.misc
+ * java.compiler
+ * java.instrument
+ * java.management
+ * jdk.jvmstat/sun.jvmstat.monitor
+ * @build ClassFileInstaller jdk.test.lib.* SimpleJvmtiAgent
+ * @run main ClassFileInstaller SimpleJvmtiAgent
+ * @run testng LoadAgentDcmdTest
+ */
+public class LoadAgentDcmdTest {
+
+ public String getLibInstrumentPath() throws FileNotFoundException {
+ String jdkPath = System.getProperty("test.jdk");
+
+ if (jdkPath == null) {
+ throw new RuntimeException(
+ "System property 'test.jdk' not set. " +
+ "This property is normally set by jtreg. " +
+ "When running test separately, set this property using " +
+ "'-Dtest.jdk=/path/to/jdk'.");
+ }
+
+ Path libpath;
+ if (Platform.isWindows()) {
+ libpath = Paths.get(jdkPath, "bin", "instrument.dll");
+ } else {
+ libpath = Paths.get(jdkPath, "lib", Platform.getOsArch(), "libinstrument.so");
+ }
+
+ if (!libpath.toFile().exists()) {
+ throw new FileNotFoundException(
+ "Could not find " + libpath.toAbsolutePath());
+ }
+
+ return libpath.toAbsolutePath().toString();
+ }
+
+ public void run(CommandExecutor executor) {
+ try{
+ PrintWriter pw = new PrintWriter("MANIFEST.MF");
+ pw.println("Agent-Class: SimpleJvmtiAgent");
+ pw.close();
+
+ ProcessBuilder pb = new ProcessBuilder();
+ pb.command(new String[] { JDKToolFinder.getJDKTool("jar"),
+ "cmf",
+ "MANIFEST.MF",
+ "agent.jar",
+ "SimpleJvmtiAgent.class"});
+ pb.start().waitFor();
+
+ String libpath = getLibInstrumentPath();
+
+ // Test 1: No argument
+ OutputAnalyzer output = executor.execute("JVMTI.agent_load " +
+ libpath + " agent.jar");
+ output.stderrShouldBeEmpty();
+
+ // Test 2: With argument
+ output = executor.execute("JVMTI.agent_load " +
+ libpath + " \"agent.jar=foo=bar\"");
+ output.stderrShouldBeEmpty();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void jmx() throws Throwable {
+ run(new JMXExecutor());
+ }
+
+ @Test
+ public void cli() throws Throwable {
+ run(new PidJcmdExecutor());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/jvmti/LoadJavaAgentDcmdTest.java Thu Feb 18 23:26:43 2016 +0900
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.*;
+import jdk.test.lib.*;
+import jdk.test.lib.dcmd.*;
+import org.testng.annotations.Test;
+
+/*
+ * Test to attach JVMTI java agent.
+ *
+ * @test
+ * @bug 8147388
+ * @library /testlibrary
+ * @modules java.base/sun.misc
+ * java.compiler
+ * java.instrument
+ * java.management
+ * jdk.jvmstat/sun.jvmstat.monitor
+ * @build ClassFileInstaller jdk.test.lib.* SimpleJvmtiAgent
+ * @run main ClassFileInstaller SimpleJvmtiAgent
+ * @run testng LoadJavaAgentDcmdTest
+ */
+public class LoadJavaAgentDcmdTest {
+ public void run(CommandExecutor executor) {
+ try{
+ PrintWriter pw = new PrintWriter("MANIFEST.MF");
+ pw.println("Agent-Class: SimpleJvmtiAgent");
+ pw.close();
+
+ ProcessBuilder pb = new ProcessBuilder();
+ pb.command(new String[] { JDKToolFinder.getJDKTool("jar"),
+ "cmf",
+ "MANIFEST.MF",
+ "agent.jar",
+ "SimpleJvmtiAgent.class"});
+ pb.start().waitFor();
+
+ // Test 1: No argument
+ OutputAnalyzer output = executor.execute("JVMTI.agent_load " +
+ "agent.jar");
+ output.stderrShouldBeEmpty();
+
+ // Test 2: With argument
+ output = executor.execute("JVMTI.agent_load " +
+ "\"agent.jar=foo=bar\"");
+ output.stderrShouldBeEmpty();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void jmx() throws Throwable {
+ run(new JMXExecutor());
+ }
+
+ @Test
+ public void cli() throws Throwable {
+ run(new PidJcmdExecutor());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/jvmti/SimpleJvmtiAgent.java Thu Feb 18 23:26:43 2016 +0900
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.lang.instrument.*;
+
+public class SimpleJvmtiAgent {
+ public static void agentmain(String agentArgs, Instrumentation instrumentation) {
+ System.out.println("attach succeeded (args: \"" + agentArgs + "\")");
+ }
+}