--- old/src/share/vm/prims/jvmtiExport.cpp 2016-01-19 22:13:45.146614740 +0900 +++ new/src/share/vm/prims/jvmtiExport.cpp 2016-01-19 22:13:44.964623673 +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); --- old/src/share/vm/prims/jvmtiExport.hpp 2016-01-19 22:13:45.855579942 +0900 +++ new/src/share/vm/prims/jvmtiExport.hpp 2016-01-19 22:13:45.657589660 +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 --- old/src/share/vm/services/diagnosticCommand.cpp 2016-01-19 22:13:46.467549904 +0900 +++ new/src/share/vm/services/diagnosticCommand.cpp 2016-01-19 22:13:46.299558149 +0900 @@ -71,6 +71,7 @@ #endif // INCLUDE_SERVICES #if INCLUDE_JVMTI DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); #endif // INCLUDE_JVMTI DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); @@ -254,6 +255,59 @@ } } +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 { + int opt_len = strlen(_libpath.value()) + strlen(_option.value()) + 2; + char *opt = (char *)os::malloc(opt_len, mtInternal); + if (opt == NULL) { + vm_exit_out_of_memory(opt_len, OOM_MALLOC_ERROR, + "JVMTIAgentLoadDCmd::execute"); + } + + 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(); --- old/src/share/vm/services/diagnosticCommand.hpp 2016-01-19 22:13:47.085519571 +0900 +++ new/src/share/vm/services/diagnosticCommand.hpp 2016-01-19 22:13:46.924527473 +0900 @@ -174,6 +174,26 @@ virtual void execute(DCmdSource source, TRAPS); }; +class JVMTIAgentLoadDCmd : public DCmdWithParser { +protected: + DCmdArgument _libpath; + DCmdArgument _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 2016-01-19 22:02:36.136235900 +0900 +++ new/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java 2016-01-19 22:13:47.519498270 +0900 @@ -0,0 +1,107 @@ +/* + * 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'."); + } + + String libname = Platform.isWindows() ? "instrument.dll" + : "libinstrument.so"; + Path libpath = Paths.get(jdkPath, "lib", Platform.getOsArch(), libname); + 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 2016-01-19 22:02:36.136235900 +0900 +++ new/test/serviceability/dcmd/jvmti/LoadJavaAgentDcmdTest.java 2016-01-19 22:13:48.051472159 +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 2016-01-19 22:02:36.136235900 +0900 +++ new/test/serviceability/dcmd/jvmti/SimpleJvmtiAgent.java 2016-01-19 22:13:48.580446195 +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 + "\")"); + } +}