7104647: Adding a diagnostic command framework
authorfparain
Wed, 04 Jan 2012 03:49:35 -0800
changeset 11365 05d995976571
parent 11364 7907324fed4f
child 11366 a1271a2384e8
child 11506 905dbb3e77eb
child 11507 bd978326a655
7104647: Adding a diagnostic command framework Reviewed-by: mchung, dholmes
jdk/make/common/Release.gmk
jdk/make/java/management/mapfile-vers
jdk/make/launchers/Makefile
jdk/make/sun/tools/Makefile
jdk/src/linux/doc/man/jcmd.1
jdk/src/share/classes/com/sun/management/DiagnosticCommandArgumentInfo.java
jdk/src/share/classes/com/sun/management/DiagnosticCommandInfo.java
jdk/src/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java
jdk/src/share/classes/sun/management/HotSpotDiagnostic.java
jdk/src/share/classes/sun/tools/attach/HotSpotVirtualMachine.java
jdk/src/share/classes/sun/tools/jcmd/Arguments.java
jdk/src/share/classes/sun/tools/jcmd/JCmd.java
jdk/src/share/javavm/export/jmm.h
jdk/src/share/native/sun/management/HotSpotDiagnostic.c
jdk/src/solaris/doc/sun/man/man1/jcmd.1
jdk/test/com/sun/management/HotSpotDiagnosticMXBean/ExecuteDiagnosticCommand.java
jdk/test/com/sun/management/HotSpotDiagnosticMXBean/GetDiagnosticCommandInfo.java
jdk/test/com/sun/management/HotSpotDiagnosticMXBean/GetDiagnosticCommands.java
jdk/test/sun/tools/common/CommonSetup.sh
jdk/test/sun/tools/jcmd/dcmd-script.txt
jdk/test/sun/tools/jcmd/help_help.out
jdk/test/sun/tools/jcmd/jcmd-Defaults.sh
jdk/test/sun/tools/jcmd/jcmd-f.sh
jdk/test/sun/tools/jcmd/jcmd-help-help.sh
jdk/test/sun/tools/jcmd/jcmd-help.sh
jdk/test/sun/tools/jcmd/jcmd-pid.sh
jdk/test/sun/tools/jcmd/jcmd_Output1.awk
jdk/test/sun/tools/jcmd/jcmd_pid_Output1.awk
jdk/test/sun/tools/jcmd/jcmd_pid_Output2.awk
jdk/test/sun/tools/jcmd/usage.out
--- a/jdk/make/common/Release.gmk	Tue Jan 03 08:33:30 2012 -0800
+++ b/jdk/make/common/Release.gmk	Wed Jan 04 03:49:35 2012 -0800
@@ -320,6 +320,7 @@
 	sun/tools/jar		\
 	sun/tools/java		\
 	sun/tools/javac		\
+	sun/tools/jcmd		\
 	sun/tools/jps		\
 	sun/tools/jstat		\
 	sun/tools/jstatd	\
@@ -432,6 +433,7 @@
 	apt$(EXE_SUFFIX) \
 	javah$(EXE_SUFFIX) \
 	javap$(EXE_SUFFIX) \
+	jcmd$(EXE_SUFFIX) \
 	jdb$(EXE_SUFFIX) \
 	jps$(EXE_SUFFIX) \
 	jrunscript$(EXE_SUFFIX) \
@@ -535,6 +537,7 @@
 	$(ECHO) "sun/tools/javac/" >> $@
 	$(ECHO) "com/sun/tools/classfile/" >> $@
 	$(ECHO) "com/sun/tools/javap/" >> $@
+	$(ECHO) "sun/tools/jcmd/" >> $@
 	$(ECHO) "sun/tools/jconsole/" >> $@
 	$(ECHO) "sun/tools/jps/" >> $@
 	$(ECHO) "sun/tools/jstat/" >> $@
--- a/jdk/make/java/management/mapfile-vers	Tue Jan 03 08:33:30 2012 -0800
+++ b/jdk/make/java/management/mapfile-vers	Wed Jan 04 03:49:35 2012 -0800
@@ -54,6 +54,9 @@
 	    Java_sun_management_GcInfoBuilder_getLastGcInfo0;
 	    Java_sun_management_GcInfoBuilder_getNumGcExtAttributes;
 	    Java_sun_management_HotSpotDiagnostic_dumpHeap;
+	    Java_sun_management_HotSpotDiagnostic_executeDiagnosticCommand0;
+	    Java_sun_management_HotSpotDiagnostic_getDiagnosticCommandInfo0;
+	    Java_sun_management_HotSpotDiagnostic_getDiagnosticCommands0;
 	    Java_sun_management_HotspotThread_getInternalThreadCount;
 	    Java_sun_management_HotspotThread_getInternalThreadTimes0;
 	    Java_sun_management_MemoryImpl_getMemoryManagers0;
--- a/jdk/make/launchers/Makefile	Tue Jan 03 08:33:30 2012 -0800
+++ b/jdk/make/launchers/Makefile	Wed Jan 04 03:49:35 2012 -0800
@@ -64,6 +64,7 @@
 $(call make-launcher, javadoc, com.sun.tools.javadoc.Main, , )
 $(call make-launcher, javah, com.sun.tools.javah.Main, , )
 $(call make-launcher, javap, com.sun.tools.javap.Main, , )
+$(call make-launcher, jcmd, sun.tools.jcmd.JCmd, , )
 $(call make-launcher, jconsole, sun.tools.jconsole.JConsole, \
   -J-Djconsole.showOutputViewer, )
 $(call make-launcher, jdb, com.sun.tools.example.debug.tty.TTY, , )
--- a/jdk/make/sun/tools/Makefile	Tue Jan 03 08:33:30 2012 -0800
+++ b/jdk/make/sun/tools/Makefile	Wed Jan 04 03:49:35 2012 -0800
@@ -42,6 +42,7 @@
   sun/tools/jstack \
   sun/tools/jstat \
   sun/tools/jstatd \
+  sun/tools/jcmd \
   com/sun/tools/hat \
   com/sun/tools/script/shell \
   sun/jvmstat
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/linux/doc/man/jcmd.1	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,124 @@
+." Copyright (c) 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.
+."
+." 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.
+."
+.TH jcmd 1 "22 Novembre 2011"
+
+.LP
+.SH "Name"
+jcmd \- Diagnostic Command
+.br
+
+.LP
+.SH "SYNOPSIS"
+.LP
+.nf
+\f3
+.fl
+\fP\f3jcmd\fP [ option ]
+.fl
+\f3jcmd\fP <\fIpid\fR | \fImain class\fR> PerfCounter.print
+.fl
+\f3jcmd\fP <\fIpid\fR | \fImain class\fR> \fIcommand\fR [\fIarguments\fR]
+.fl
+\f3jcmd\fP <\fIpid\fR | \fImain class\fR> -f \fIfile\fR
+.fl
+.fl
+.fi
+
+.LP
+.SH "DESCRIPTION"
+.LP
+.LP
+\f3jcmd\fP is a utility to send diagnostic command requests to a Java 
+Virtual Machine supporting this feature. Used without arguments or with the \-l option, jcmd prints the list of running Java processes with their process id, their main class and their command line arguments. When a process id is specified on the command line, jcmd sends the diagnostic command request to the process with this id. When a main class is specified on the command line, jcmd sends the diagnostic command request to all Java processes with this main class. With the PerfCounter.print argument, jcmd prints the performance counters available on the targeted Java process(es). With the \-f option, jcmd sends to the targeted Java process(es) the diagnostic commands stored in the file \fIfile\fR.
+.LP
+\fP
+.fi
+
+.SH "OPTIONS"
+.LP
+.LP
+Options are mutually exclusive. Options, if used, should follow immediately after the command name.
+.LP
+.RS 3
+.TP 3
+\-l 
+prints the list of running Java processes with their process id, their
+main class and their command line arguments. 
+.TP 3
+\-h 
+prints a help message.
+.br
+.br
+.TP 3
+\-help 
+prints a help message
+.br
+.RE
+
+.LP
+.SH "PARAMETERS"
+.LP
+.RS 3
+.TP 3
+\fIpid\fR
+Identifies the process which will receive the diagnostic command requests. The process must be a Java process. To get a list of Java processes running on a machine, jps(1) or jcmd(1) may be used. 
+.RE
+.LP
+.RS 3
+.TP 3
+\fImain class\fR
+Main class of the process which will receive the diagnostic command requests. If several running Java processes share this main class, the diagnostic command request will be sent to all these processes. To get a list of Java processes running on a machine, jps(1) or jcmd(1) may be used. 
+.RE
+.RS 3
+.TP 3
+\fIcommand\fR [\fIarguments\fR]
+Invoke the diagnostic command called \fIcommand\fR on the targeted Java
+process(es). The list of available diagnostic commands for a given
+process can be obtained by invoking the 'help' command on this process.
+Each diagnostic command has its own set of \fIarguments\fR which can be 
+obtained by invoking the 'help' command followed by the command name.
+.RE
+.RS 3
+.TP 3
+\fIPerfCounter.print\fR
+Print the performance counters available on the targeted Java
+process(es). The list of performance counters may vary with the Java
+process.
+.RE
+.RS 3
+.TP 3
+\fI-f file\fR
+Read commands from \fIfile\fR and invoke them on the targeted Java
+process(es). In  \fIfile\fR, each command must be written on a single line. 
+Lines starting with # are ignored. Processing of \fIfile\fR ends when
+all lines have been invoked or when a line containing the 'stop' keyword
+is read.
+.LP
+.SH "SEE ALSO"
+.LP
+.RS 3
+.TP 2
+o
+jps(1) 
+.RE
+
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/management/DiagnosticCommandArgumentInfo.java	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 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 com.sun.management;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * Diagnostic Command Argument information. It contains the description
+ * of one parameter of the diagnostic command. A parameter can either be an
+ * option or an argument. Options are identified by the option name while
+ * arguments are identified by their position in the command line. The generic
+ * syntax of a diagnostic command is:
+ *  <blockquote>
+ *    &lt;command name&gt; [&lt;option&gt;=&lt;value&gt;] [&lt;argument_value&gt;]
+ * </blockquote>
+ * Example:
+ * <blockquote>
+ * command_name option1=value1 option2=value argumentA argumentB argumentC
+ * </blockquote>
+ * In this command line, the diagnostic command receives five parameters, two
+ * options named {@code option1} and {@code option2}, and three arguments.
+ * argumentA's position is 0, argumentB's position is 1 and argumentC's
+ * position is 2.
+ *
+ * @author  Frederic Parain
+ * @since   7u4
+ */
+
+public class DiagnosticCommandArgumentInfo {
+    private final String name;
+    private final String description;
+    private final String type;
+    private final String defaultValue;
+    private final boolean mandatory;
+    private final boolean option;
+    private final int position;
+
+    /**
+     * Returns the argument name
+     *
+     * @return the argument name
+     */
+    public String getName() {
+        return name;
+    }
+
+   /**
+     * Returns the argument description
+     *
+     * @return the argument description
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Returns the argument type
+     *
+     * @return the argument type
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Returns the default value as a String if a default value
+     * is defined, null otherwise.
+     *
+     * @return the default value as a String if a default value
+     * is defined, null otherwise.
+     */
+    public String getDefault() {
+        return defaultValue;
+    }
+
+    /**
+     * Returns {@code true} if the argument is mandatory,
+     *         {@code false} otherwise
+     *
+     * @return {@code true} if the argument is mandatory,
+     *         {@code false} otherwise
+     */
+    public boolean isMandatory() {
+        return mandatory;
+    }
+
+    /**
+     * Returns {@code true} if the argument is an option,
+     *         {@code false} otherwise. Options have to be specified using the
+     *         &lt;key&gt;=&lt;value&gt; syntax on the command line, while other
+     *         arguments are specified with a single &lt;value&gt; field and are
+     *         identified by their position on command line.
+     *
+     * @return {@code true} if the argument is an option,
+     *         {@code false} otherwise
+     */
+    public boolean isOption() {
+        return option;
+    }
+
+    /**
+     * Returns the expected position of this argument if it is not an option,
+     *         -1 otherwise. Argument position if defined from left to right,
+     *         starting at zero and ignoring the diagnostic command name and
+     *         options.
+     *
+     * @return the expected position of this argument if it is not an option,
+     *         -1 otherwise.
+     */
+    public int getPosition() {
+        return position;
+    }
+
+    @ConstructorProperties({"name","description","type","default",
+                "mandatory","option","position"})
+    public DiagnosticCommandArgumentInfo(String name, String description,
+                                         String type, String defaultValue,
+                                         boolean mandatory, boolean option,
+                                         int position) {
+        this.name = name;
+        this.description = description;
+        this.type = type;
+        this.defaultValue = defaultValue;
+        this.mandatory = mandatory;
+        this.option = option;
+        this.position = position;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/management/DiagnosticCommandInfo.java	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 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 com.sun.management;
+
+import java.beans.ConstructorProperties;
+import java.util.List;
+
+/**
+ * Diagnostic command information. It contains the description of a
+ * diagnostic command.
+ *
+ * @author  Frederic Parain
+ * @since   7u4
+ */
+
+public class DiagnosticCommandInfo {
+    private final String name;
+    private final String description;
+    private final String impact;
+    private final boolean enabled;
+    private final List<DiagnosticCommandArgumentInfo> arguments;
+
+    /**
+     * Returns the diagnostic command name
+     *
+     * @return the diagnostic command name
+     */
+    public String getName() {
+        return name;
+    }
+
+   /**
+     * Returns the diagnostic command description
+     *
+     * @return the diagnostic command description
+     */
+    public String getDescription() {
+        return description;
+    }
+
+     /**
+     * Returns the potential impact of the diagnostic command execution
+     *         on the Java virtual machine behavior
+     *
+     * @return the potential impact of the diagnostic command execution
+     *         on the Java virtual machine behavior
+     */
+    public String getImpact() {
+        return impact;
+    }
+
+    /**
+     * Returns {@code true} if the diagnostic command is enabled,
+     *         {@code false} otherwise. The enabled/disabled
+     *         status of a diagnostic command can evolve during
+     *         the lifetime of the Java virtual machine.
+     *
+     * @return {@code true} if the diagnostic command is enabled,
+     *         {@code false} otherwise
+     */
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * Returns the list of the diagnostic command arguments description.
+     * If the diagnostic command has no arguments, it returns an empty list.
+     *
+     * @return a list of the diagnostic command arguments description
+     */
+    public List<DiagnosticCommandArgumentInfo> getArgumentsInfo() {
+        return arguments;
+    }
+
+    @ConstructorProperties({"name", "description","impact","enabled",
+                "argumentsInfo"})
+    public DiagnosticCommandInfo(String name, String description,
+                                 String impact, boolean enabled,
+                                 List<DiagnosticCommandArgumentInfo> arguments)
+    {
+        this.name = name;
+        this.description = description;
+        this.impact = impact;
+        this.enabled = enabled;
+        this.arguments = arguments;
+    }
+}
--- a/jdk/src/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java	Tue Jan 03 08:33:30 2012 -0800
+++ b/jdk/src/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java	Wed Jan 04 03:49:35 2012 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -25,11 +25,18 @@
 
 package com.sun.management;
 
+import java.util.List;
 import java.lang.management.PlatformManagedObject;
 
 /**
  * Diagnostic management interface for the HotSpot Virtual Machine.
- * The diagnostic MBean is registered to the platform MBeanServer
+ *
+ * <p>{@linkplain #getDiagnosticCommands Diagnostic commands}
+ * are actions that can be invoked dynamically and
+ * executed in a target Java virtual machine, mainly for troubleshooting
+ * and diagnosis.
+ *
+ * <p>The diagnostic MBean is registered to the platform MBeanServer
  * as are other platform MBeans.
  *
  * <p>The <tt>ObjectName</tt> for uniquely identifying the diagnostic
@@ -41,6 +48,9 @@
  * It can be obtained by calling the
  * {@link PlatformManagedObject#getObjectName} method.
  *
+ * All methods throw a {@code NullPointerException} if any input argument is
+ * {@code null} unless it's stated otherwise.
+ *
  * @see ManagementFactory#getPlatformMXBeans(Class)
  */
 public interface HotSpotDiagnosticMXBean extends PlatformManagedObject {
@@ -101,9 +111,113 @@
      * @throws IllegalArgumentException if the VM option is not writeable.
      * @throws NullPointerException if name or value is <tt>null</tt>.
      *
-     * @throws  java.security.SecurityException
+     * @throws  java.lang.SecurityException
      *     if a security manager exists and the caller does not have
      *     ManagementPermission("control").
      */
     public void setVMOption(String name, String value);
+
+    /**
+     * Returns the {@linkplain DiagnosticCommandInfo#getName() names}
+     * of all diagnostic commands.
+     * A diagnostic command is an action that can be invoked dynamically
+     * mainly for troubleshooting and diagnosis.  The list of diagnostic
+     * commands may change at runtime.  A diagnostic command may be
+     * {@linkplain DiagnosticCommandInfo#isEnabled disabled} but will
+     * not be removed from a previously returned list.
+     *
+     * @return the names of all diagnostic commands.
+     *
+     * @since 7u4
+     */
+    public List<String> getDiagnosticCommands();
+
+    /**
+     * Returns a {@code DiagnosticCommandInfo} object describing the
+     * diagnostic command of the specified name {@code command}
+     *
+     * @param command a diagnostic command name
+     * @return a {@code DiagnosticCommandInfo} object
+     * @throws java.lang.IllegalArgumentException if the {@code command}
+     *         doesn't match any diagnostic command registered in the
+     *         targeted Java virtual machine.
+     *
+     * @since 7u4
+     */
+    public DiagnosticCommandInfo getDiagnosticCommandInfo(String command);
+
+    /**
+     * Returns a list of {@code DiagnosticCommandInfo} object describing
+     * all diagnostic commands available on the targeted Java virtual machine
+     *
+     * @return a list of {@code DiagnosticCommandInfo} objects
+     *
+     * @since 7u4
+     */
+    public List<DiagnosticCommandInfo> getDiagnosticCommandInfo();
+
+    /**
+     * Returns a list of {@code DiagnosticCommandInfo} object describing
+     * all diagnostic commands specified in the {@code commands} list.
+     *
+     * @param commands {@code List} of {@code String} containing diagnostic
+     *        command names
+     * @return a {@code List} of {@code DiagnosticCommandInfo} objects
+     *
+     * @throws java.lang.IllegalArgumentException if at least one
+     *         command specified in the {@code commands } list
+     *         doesn't match any diagnostic command registered in the
+     *         targeted Java virtual machine.
+     *
+     * @since 7u4
+     */
+    public List<DiagnosticCommandInfo> getDiagnosticCommandInfo(List<String> commands);
+
+    /**
+     * Executes the command line {@code commandLine}. The command line must
+     * start with a diagnostic command name, optionally followed by parameters.
+     * Each command has its own syntax but the generic syntax for a diagnostic
+     * command line is:
+     * <blockquote>
+     *    &lt;command name&gt; [&lt;option&gt;=&lt;value&gt;] [&lt;argument_value&gt;]
+     * </blockquote>
+     *
+     * @param commandLine command line to execute
+     * @return a {@code String} object containing the diagnostic command
+     *         output.
+     *
+     * @throws java.lang.IllegalArgumentException if the command line doesn't
+     *         match any diagnostic command registered in the virtual machine
+     *         of if the parameters don't match the diagnostic command syntax.
+     * @throws java.lang.SecurityException
+     *         if a security manager exists and the caller does not have
+     *         ManagementPermission("control").
+     *
+     * @since 7u4
+     */
+    public String execute(String commandLine);
+
+    /**
+     * Invokes the diagnostic command named {@code cmd} with the parameters
+     * specified in {@code args}. Each command has its own syntax but
+     * the generic syntax for parameters is:
+     * <blockquote>
+     *    [&lt;option&gt;=&lt;value&gt;] [&lt;argument_value&gt;]
+     * </blockquote>
+     *
+     * @param cmd a diagnostic command name
+     * @param args the command parameters
+     * @return a {@code String} object containing the diagnostic command
+     *         output.
+     *
+     * @throws java.lang.IllegalArgumentException if the command line doesn't
+     *         match any diagnostic command registered in the virtual machine
+     *         of if the parameters don't match the diagnostic command syntax.
+     * @throws java.lang.SecurityException
+     *         if a security manager exists and the caller does not have
+     *         ManagementPermission("control").
+     *
+     * @since 7u4
+     */
+    public String execute(String cmd, String... args);
 }
--- a/jdk/src/share/classes/sun/management/HotSpotDiagnostic.java	Tue Jan 03 08:33:30 2012 -0800
+++ b/jdk/src/share/classes/sun/management/HotSpotDiagnostic.java	Wed Jan 04 03:49:35 2012 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -27,9 +27,13 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import javax.management.ObjectName;
 
+import com.sun.management.DiagnosticCommandInfo;
+import com.sun.management.DiagnosticCommandArgumentInfo;
 import com.sun.management.HotSpotDiagnosticMXBean;
 import com.sun.management.VMOption;
 
@@ -116,7 +120,54 @@
         }
     }
 
+    public List<String> getDiagnosticCommands() {
+        String[] commands = getDiagnosticCommands0();
+        return commands == null ? Collections.<String>emptyList() :
+            Arrays.asList(commands);
+    }
+
+    public DiagnosticCommandInfo getDiagnosticCommandInfo(String command) {
+        String[] array = new String[] { command };
+        return getDiagnosticCommandInfo0(array)[0];
+    }
+
+    public List<DiagnosticCommandInfo> getDiagnosticCommandInfo() {
+        String[] commands = getDiagnosticCommands0();
+        return Arrays.asList(getDiagnosticCommandInfo0(commands));
+    }
+
+    public List<DiagnosticCommandInfo> getDiagnosticCommandInfo(
+        List<String> commands) {
+        return Arrays.asList(getDiagnosticCommandInfo0(
+            commands.toArray(new String[commands.size()])));
+    }
+
+    public String execute(String command) {
+        Util.checkControlAccess();
+        return executeDiagnosticCommand0(command);
+    }
+
+    public String execute(String cmd, String... arguments) {
+        if(cmd == null) {
+            throw new NullPointerException("Missing command name");
+        }
+        StringBuilder sb = new StringBuilder();
+        sb.append(cmd);
+        sb.append(" ");
+        for(String arg : arguments) {
+            sb.append(arg);
+            sb.append(" ");
+        }
+        return execute(sb.toString());
+    }
+
     public ObjectName getObjectName() {
         return Util.newObjectName("com.sun.management:type=HotSpotDiagnostic");
     }
+
+    private native String[] getDiagnosticCommands0();
+    private native DiagnosticCommandInfo[] getDiagnosticCommandInfo0(
+        String[] commands) throws IllegalArgumentException;
+    private native String executeDiagnosticCommand0(String command)
+        throws IllegalArgumentException;
 }
--- a/jdk/src/share/classes/sun/tools/attach/HotSpotVirtualMachine.java	Tue Jan 03 08:33:30 2012 -0800
+++ b/jdk/src/share/classes/sun/tools/attach/HotSpotVirtualMachine.java	Wed Jan 04 03:49:35 2012 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -195,6 +195,10 @@
         return executeCommand("printflag", name);
     }
 
+    public InputStream executeJCmd(String command) throws IOException {
+        return executeCommand("jcmd", command);
+    }
+
     // -- Supporting methods
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/tools/jcmd/Arguments.java	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 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.jcmd;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+class Arguments {
+    private boolean listProcesses = false;
+    private boolean listCounters  = false;
+    private boolean showUsage     = false;
+    private int     pid           = -1;
+    private String  command       = null;
+    private String  processSubstring;
+
+    public boolean isListProcesses() { return listProcesses; }
+    public boolean isListCounters() { return listCounters; }
+    public boolean isShowUsage() { return showUsage; }
+    public int getPid() { return pid; }
+    public String getCommand() { return command; }
+    public String getProcessSubstring() { return processSubstring; }
+
+    public Arguments(String[] args) {
+        if (args.length == 0 || args[0].equals("-l")) {
+            listProcesses = true;
+            return;
+        }
+
+        if (args[0].equals("-h") || args[0].equals("-help") ) {
+            showUsage = true;
+            return;
+        }
+
+        try {
+            pid = Integer.parseInt(args[0]);
+        } catch (NumberFormatException ex) {
+            // use as a partial class-name instead
+            if (args[0].charAt(0) != '-') {
+                // unless it starts with a '-'
+                processSubstring = args[0];
+            }
+        }
+
+        StringBuilder sb = new StringBuilder();
+        for (int i = 1; i < args.length; i++) {
+            if (args[i].equals("-f")) {
+                if (args.length == i + 1) {
+                    throw new IllegalArgumentException(
+                        "No file specified for parameter -f");
+                } else if (args.length == i + 2) {
+                    try {
+                        readCommandFile(args[i + 1]);
+                    } catch(IOException e) {
+                        throw new IllegalArgumentException(
+                            "Could not read from file specified with -f option: "
+                            + args[i + 1]);
+                    }
+                    return;
+                } else {
+                    throw new IllegalArgumentException(
+                        "Options after -f are not allowed");
+                }
+            } else if (args[i].equals("PerfCounter.print")) {
+                listCounters = true;
+            } else {
+                sb.append(args[i]).append(" ");
+            }
+        }
+
+        if (listCounters != true && sb.length() == 0) {
+            throw new IllegalArgumentException("No command specified");
+        }
+
+        command = sb.toString().trim();
+    }
+
+    private void readCommandFile(String path) throws IOException {
+        try (BufferedReader bf = new BufferedReader(new FileReader(path));) {
+                StringBuilder sb = new StringBuilder();
+                String s;
+                while ((s = bf.readLine()) != null) {
+                    sb.append(s).append("\n");
+                }
+                command = sb.toString();
+            }
+    }
+
+    public static void usage() {
+        System.out.println("Usage: jcmd <pid | main class> <command ...|PerfCounter.print|-f file>");
+        System.out.println("   or: jcmd -l                                                    ");
+        System.out.println("   or: jcmd -h                                                    ");
+        System.out.println("                                                                  ");
+        System.out.println("  command must be a valid jcmd command for the selected jvm.      ");
+        System.out.println("  Use the command \"help\" to see which commands are available.   ");
+        System.out.println("  If the pid is 0, commands will be sent to all Java processes.   ");
+        System.out.println("  The main class argument will be used to match (either partially ");
+        System.out.println("  or fully) the class used to start Java.                         ");
+        System.out.println("  If no options are given, lists Java processes (same as -p).     ");
+        System.out.println("                                                                  ");
+        System.out.println("  PerfCounter.print display the counters exposed by this process  ");
+        System.out.println("  -f  read and execute commands from the file                     ");
+        System.out.println("  -l  list JVM processes on the local machine                     ");
+        System.out.println("  -h  this help                                                   ");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/tools/jcmd/JCmd.java	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *com.sun.tools.attach.AttachNotSupportedException
+
+ * 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.jcmd;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.net.URISyntaxException;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.VirtualMachineDescriptor;
+import com.sun.tools.attach.AgentLoadException;
+import com.sun.tools.attach.AttachNotSupportedException;
+import sun.tools.attach.HotSpotVirtualMachine;
+import sun.tools.jstat.JStatLogger;
+import sun.jvmstat.monitor.Monitor;
+import sun.jvmstat.monitor.MonitoredHost;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.MonitoredVmUtil;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.VmIdentifier;
+
+public class JCmd {
+    public static void main(String[] args) {
+        Arguments arg = null;
+        try {
+            arg = new Arguments(args);
+        } catch (IllegalArgumentException ex) {
+            System.err.println("Error parsing arguments: " + ex.getMessage()
+                               + "\n");
+            Arguments.usage();
+            System.exit(1);
+        }
+
+        if (arg.isShowUsage()) {
+            Arguments.usage();
+            System.exit(1);
+        }
+
+        if (arg.isListProcesses()) {
+            List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
+            for (VirtualMachineDescriptor vmd : vmds) {
+                System.out.println(vmd.id() + " " + vmd.displayName());
+            }
+            System.exit(0);
+        }
+
+        List<String> pids = new ArrayList<String>();
+        if (arg.getPid() == 0) {
+            // find all VMs
+            List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
+            for (VirtualMachineDescriptor vmd : vmds) {
+                if (!isJCmdProcess(vmd)) {
+                    pids.add(vmd.id());
+                }
+            }
+        } else if (arg.getProcessSubstring() != null) {
+            // use the partial class-name match
+            List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
+            for (VirtualMachineDescriptor vmd : vmds) {
+                if (isJCmdProcess(vmd)) {
+                    continue;
+                }
+                try {
+                    String mainClass = getMainClass(vmd);
+                    if (mainClass != null
+                        && mainClass.indexOf(arg.getProcessSubstring()) != -1) {
+                            pids.add(vmd.id());
+                    }
+                } catch (MonitorException|URISyntaxException e) {
+                    if (e.getMessage() != null) {
+                        System.err.println(e.getMessage());
+                    } else {
+                        Throwable cause = e.getCause();
+                        if ((cause != null) && (cause.getMessage() != null)) {
+                            System.err.println(cause.getMessage());
+                        } else {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            }
+            if (pids.isEmpty()) {
+                System.err.println("Could not find any processes matching : '"
+                                   + arg.getProcessSubstring() + "'");
+                System.exit(1);
+            }
+        } else if (arg.getPid() == -1) {
+            System.err.println("Invalid pid specified");
+            System.exit(1);
+        } else {
+            // Use the found pid
+            pids.add(arg.getPid() + "");
+        }
+
+        for (String pid : pids) {
+            System.out.println(pid + ":");
+            if (arg.isListCounters()) {
+                listCounters(pid);
+            } else {
+                try {
+                    executeCommandForPid(pid, arg.getCommand());
+                } catch(Exception ex) {
+                    ex.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private static void executeCommandForPid(String pid, String command)
+        throws AttachNotSupportedException, IOException,
+               UnsupportedEncodingException {
+        VirtualMachine vm = VirtualMachine.attach(pid);
+
+        // Cast to HotSpotVirtualMachine as this is an
+        // implementation specific method.
+        HotSpotVirtualMachine hvm = (HotSpotVirtualMachine) vm;
+        try (InputStream in = hvm.executeJCmd(command);) {
+            // read to EOF and just print output
+            byte b[] = new byte[256];
+            int n;
+            do {
+                n = in.read(b);
+                if (n > 0) {
+                    String s = new String(b, 0, n, "UTF-8");
+                    System.out.print(s);
+                }
+            } while (n > 0);
+        }
+        vm.detach();
+    }
+
+    private static void listCounters(String pid) {
+        // Code from JStat (can't call it directly since it does System.exit)
+        VmIdentifier vmId = null;
+        try {
+            vmId = new VmIdentifier(pid);
+        } catch (URISyntaxException e) {
+            System.err.println("Malformed VM Identifier: " + pid);
+            return;
+        }
+        try {
+            MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId);
+            MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1);
+            JStatLogger logger = new JStatLogger(monitoredVm);
+            logger.printSnapShot("\\w*", // all names
+                    new AscendingMonitorComparator(), // comparator
+                    false, // not verbose
+                    true, // show unsupported
+                    System.out);
+            monitoredHost.detach(monitoredVm);
+        } catch (MonitorException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    private static boolean isJCmdProcess(VirtualMachineDescriptor vmd) {
+        try {
+            String mainClass = getMainClass(vmd);
+            return mainClass != null && mainClass.equals(JCmd.class.getName());
+        } catch (URISyntaxException|MonitorException ex) {
+            return false;
+        }
+    }
+
+    private static String getMainClass(VirtualMachineDescriptor vmd)
+            throws URISyntaxException, MonitorException {
+        try {
+            String mainClass = null;
+            VmIdentifier vmId = new VmIdentifier(vmd.id());
+            MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId);
+            MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1);
+            mainClass = MonitoredVmUtil.mainClass(monitoredVm, true);
+            monitoredHost.detach(monitoredVm);
+            return mainClass;
+        } catch(NullPointerException e) {
+            // There is a potential race, where a running java app is being
+            // queried, unfortunately the java app has shutdown after this
+            // method is started but before getMonitoredVM is called.
+            // If this is the case, then the /tmp/hsperfdata_xxx/pid file
+            // will have disappeared and we will get a NullPointerException.
+            // Handle this gracefully....
+            return null;
+        }
+    }
+
+    /**
+     * Class to compare two Monitor objects by name in ascending order.
+     * (from jstat)
+     */
+    static class AscendingMonitorComparator implements Comparator<Monitor> {
+
+        public int compare(Monitor m1, Monitor m2) {
+            String name1 = m1.getName();
+            String name2 = m2.getName();
+            return name1.compareTo(name2);
+        }
+    }
+}
--- a/jdk/src/share/javavm/export/jmm.h	Tue Jan 03 08:33:30 2012 -0800
+++ b/jdk/src/share/javavm/export/jmm.h	Wed Jan 04 03:49:35 2012 -0800
@@ -48,7 +48,8 @@
   JMM_VERSION_1_0 = 0x20010000,
   JMM_VERSION_1_1 = 0x20010100, // JDK 6
   JMM_VERSION_1_2 = 0x20010200, // JDK 7
-  JMM_VERSION     = 0x20010201
+  JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
+  JMM_VERSION     = 0x20010202
 };
 
 typedef struct {
@@ -188,6 +189,24 @@
                                                /* -1 indicates gc_ext_attribute_values is not big enough */
 } jmmGCStat;
 
+typedef struct {
+  const char* name;
+  const char* description;
+  const char* impact;
+  int         num_arguments;
+  jboolean    enabled;
+} dcmdInfo;
+
+typedef struct {
+  const char* name;
+  const char* description;
+  const char* type;
+  const char* default_string;
+  jboolean    mandatory;
+  jboolean    option;
+  int         position;
+} dcmdArgInfo;
+
 typedef struct jmmInterface_1_ {
   void*        reserved1;
   void*        reserved2;
@@ -293,9 +312,21 @@
                                                   jlongArray ids,
                                                   jboolean lockedMonitors,
                                                   jboolean lockedSynchronizers);
-   void         (JNICALL *SetGCNotificationEnabled) (JNIEnv *env,
-                                                  jobject mgr,
-                                                  jboolean enabled);
+  void         (JNICALL *SetGCNotificationEnabled) (JNIEnv *env,
+                                                    jobject mgr,
+                                                    jboolean enabled);
+  jobjectArray (JNICALL *GetDiagnosticCommands)  (JNIEnv *env);
+  void         (JNICALL *GetDiagnosticCommandInfo)
+                                                 (JNIEnv *env,
+                                                  jobjectArray cmds,
+                                                  dcmdInfo *infoArray);
+  void         (JNICALL *GetDiagnosticCommandArgumentsInfo)
+                                                 (JNIEnv *env,
+                                                  jstring commandName,
+                                                  dcmdArgInfo *infoArray);
+  jstring      (JNICALL *ExecuteDiagnosticCommand)
+                                                 (JNIEnv *env,
+                                                  jstring command);
 } JmmInterface;
 
 #ifdef __cplusplus
--- a/jdk/src/share/native/sun/management/HotSpotDiagnostic.c	Tue Jan 03 08:33:30 2012 -0800
+++ b/jdk/src/share/native/sun/management/HotSpotDiagnostic.c	Wed Jan 04 03:49:35 2012 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -34,3 +34,141 @@
 {
     jmm_interface->DumpHeap0(env, outputfile, live);
 }
+
+JNIEXPORT jobjectArray JNICALL
+Java_sun_management_HotSpotDiagnostic_getDiagnosticCommands0
+  (JNIEnv *env, jobject dummy)
+{
+  if ((jmm_version > JMM_VERSION_1_2_1)
+      || (jmm_version == JMM_VERSION_1_2 && ((jmm_version&0xFF)>=2))) {
+    return jmm_interface->GetDiagnosticCommands(env);
+  }
+  JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+                  "Diagnostic commands are not supported by this VM");
+}
+
+jobject getDiagnosticCommandArgumentInfoArray(JNIEnv *env, jstring command,
+                                              int num_arg) {
+  int i;
+  jobject obj;
+  jobjectArray result;
+  dcmdArgInfo* dcmd_arg_info_array;
+  jclass dcmdArgInfoCls;
+  jclass arraysCls;
+  jmethodID mid;
+  jobject resultList;
+
+  dcmd_arg_info_array = (dcmdArgInfo*) malloc(num_arg * sizeof(dcmdArgInfo));
+  if (dcmd_arg_info_array == NULL) {
+    return NULL;
+  }
+  jmm_interface->GetDiagnosticCommandArgumentsInfo(env, command,
+                                                   dcmd_arg_info_array);
+  dcmdArgInfoCls = (*env)->FindClass(env,
+                                     "com/sun/management/DiagnosticCommandArgumentInfo");
+  result = (*env)->NewObjectArray(env, num_arg, dcmdArgInfoCls, NULL);
+  if (result == NULL) {
+    free(dcmd_arg_info_array);
+    return NULL;
+  }
+  for (i=0; i<num_arg; i++) {
+    obj = JNU_NewObjectByName(env,
+                              "com/sun/management/DiagnosticCommandArgumentInfo",
+                              "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZI)V",
+                              (*env)->NewStringUTF(env,dcmd_arg_info_array[i].name),
+                              (*env)->NewStringUTF(env,dcmd_arg_info_array[i].description),
+                              (*env)->NewStringUTF(env,dcmd_arg_info_array[i].type),
+                              dcmd_arg_info_array[i].default_string == NULL ? NULL:
+                              (*env)->NewStringUTF(env, dcmd_arg_info_array[i].default_string),
+                              dcmd_arg_info_array[i].mandatory,
+                              dcmd_arg_info_array[i].option,
+                              dcmd_arg_info_array[i].position);
+    if (obj == NULL) {
+      free(dcmd_arg_info_array);
+      return NULL;
+    }
+    (*env)->SetObjectArrayElement(env, result, i, obj);
+  }
+  free(dcmd_arg_info_array);
+  arraysCls = (*env)->FindClass(env, "java/util/Arrays");
+  mid = (*env)->GetStaticMethodID(env, arraysCls,
+                                  "asList", "([Ljava/lang/Object;)Ljava/util/List;");
+  resultList = (*env)->CallStaticObjectMethod(env, arraysCls, mid, result);
+  return resultList;
+}
+
+/* Throws IllegalArgumentException if at least one the diagnostic command
+ * passed in argument is not supported by the JVM
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_sun_management_HotSpotDiagnostic_getDiagnosticCommandInfo0
+(JNIEnv *env, jobject dummy, jobjectArray commands)
+{
+  int i;
+  jclass dcmdInfoCls;
+  jobject result;
+  jobjectArray args;
+  jobject obj;
+
+  if (commands == NULL) {
+    JNU_ThrowNullPointerException(env, "Invalid String Array");
+    return NULL;
+  }
+  if ((jmm_version > JMM_VERSION_1_2_1)
+      || (jmm_version == JMM_VERSION_1_2 && ((jmm_version&0xFF)>=2))) {
+    jsize num_commands = (*env)->GetArrayLength(env, commands);
+    dcmdInfo* dcmd_info_array = (dcmdInfo*) malloc(num_commands *
+                                                   sizeof(dcmdInfo));
+    if (dcmd_info_array == NULL) {
+      JNU_ThrowOutOfMemoryError(env, NULL);
+    }
+    jmm_interface->GetDiagnosticCommandInfo(env, commands, dcmd_info_array);
+    dcmdInfoCls = (*env)->FindClass(env,
+                                    "com/sun/management/DiagnosticCommandInfo");
+    result = (*env)->NewObjectArray(env, num_commands, dcmdInfoCls, NULL);
+    if (result == NULL) {
+      free(dcmd_info_array);
+      JNU_ThrowOutOfMemoryError(env, 0);
+    }
+    for (i=0; i<num_commands; i++) {
+      args = getDiagnosticCommandArgumentInfoArray(env,
+                                                   (*env)->GetObjectArrayElement(env,commands,i),
+                                                   dcmd_info_array[i].num_arguments);
+      if (args == NULL) {
+        free(dcmd_info_array);
+        JNU_ThrowOutOfMemoryError(env, 0);
+      }
+      obj = JNU_NewObjectByName(env,
+                                "com/sun/management/DiagnosticCommandInfo",
+                                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/util/List;)V",
+                                (*env)->NewStringUTF(env,dcmd_info_array[i].name),
+                                (*env)->NewStringUTF(env,dcmd_info_array[i].description),
+                                (*env)->NewStringUTF(env,dcmd_info_array[i].impact),
+                                dcmd_info_array[i].enabled,
+                                args);
+      if (obj == NULL) {
+        free(dcmd_info_array);
+        JNU_ThrowOutOfMemoryError(env, 0);
+      }
+      (*env)->SetObjectArrayElement(env, result, i, obj);
+    }
+    free(dcmd_info_array);
+    return result;
+  }
+  JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+                  "Diagnostic commands are not supported by this VM");
+}
+
+/* Throws IllegalArgumentException if the diagnostic command
+ * passed in argument is not supported by the JVM
+ */
+JNIEXPORT jstring JNICALL
+Java_sun_management_HotSpotDiagnostic_executeDiagnosticCommand0
+(JNIEnv *env, jobject dummy, jstring command) {
+  if((jmm_version > JMM_VERSION_1_2_1 )
+     || (jmm_version == JMM_VERSION_1_2 && ((jmm_version&0xFF)>=2))) {
+    return jmm_interface->ExecuteDiagnosticCommand(env, command);
+  }
+  JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+                  "Diagnostic commands are not supported by this VM");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/doc/sun/man/man1/jcmd.1	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,124 @@
+." Copyright (c) 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.
+."
+." 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.
+."
+.TH jcmd 1 "22 Novembre 2011"
+
+.LP
+.SH "Name"
+jcmd \- Diagnostic Command
+.br
+
+.LP
+.SH "SYNOPSIS"
+.LP
+.nf
+\f3
+.fl
+\fP\f3jcmd\fP [ option ]
+.fl
+\f3jcmd\fP <\fIpid\fR | \fImain class\fR> PerfCounter.print
+.fl
+\f3jcmd\fP <\fIpid\fR | \fImain class\fR> \fIcommand\fR [\fIarguments\fR]
+.fl
+\f3jcmd\fP <\fIpid\fR | \fImain class\fR> -f \fIfile\fR
+.fl
+.fl
+.fi
+
+.LP
+.SH "DESCRIPTION"
+.LP
+.LP
+\f3jcmd\fP is a utility to send diagnostic command requests to a Java 
+Virtual Machine supporting this feature. Used without arguments or with the \-l option, jcmd prints the list of running Java processes with their process id, their main class and their command line arguments. When a process id is specified on the command line, jcmd sends the diagnostic command request to the process with this id. When a main class is specified on the command line, jcmd sends the diagnostic command request to all Java processes with this main class. With the PerfCounter.print argument, jcmd prints the performance counters available on the targeted Java process(es). With the \-f option, jcmd sends to the targeted Java process(es) the diagnostic commands stored in the file \fIfile\fR.
+.LP
+\fP
+.fi
+
+.SH "OPTIONS"
+.LP
+.LP
+Options are mutually exclusive. Options, if used, should follow immediately after the command name.
+.LP
+.RS 3
+.TP 3
+\-l 
+prints the list of running Java processes with their process id, their
+main class and their command line arguments. 
+.TP 3
+\-h 
+prints a help message.
+.br
+.br
+.TP 3
+\-help 
+prints a help message
+.br
+.RE
+
+.LP
+.SH "PARAMETERS"
+.LP
+.RS 3
+.TP 3
+\fIpid\fR
+Identifies the process which will receive the diagnostic command requests. The process must be a Java process. To get a list of Java processes running on a machine, jps(1) or jcmd(1) may be used. 
+.RE
+.LP
+.RS 3
+.TP 3
+\fImain class\fR
+Main class of the process which will receive the diagnostic command requests. If several running Java processes share this main class, the diagnostic command request will be sent to all these processes. To get a list of Java processes running on a machine, jps(1) or jcmd(1) may be used. 
+.RE
+.RS 3
+.TP 3
+\fIcommand\fR [\fIarguments\fR]
+Invoke the diagnostic command called \fIcommand\fR on the targeted Java
+process(es). The list of available diagnostic commands for a given
+process can be obtained by invoking the 'help' command on this process.
+Each diagnostic command has its own set of \fIarguments\fR which can be 
+obtained by invoking the 'help' command followed by the command name.
+.RE
+.RS 3
+.TP 3
+\fIPerfCounter.print\fR
+Print the performance counters available on the targeted Java
+process(es). The list of performance counters may vary with the Java
+process.
+.RE
+.RS 3
+.TP 3
+\fI-f file\fR
+Read commands from \fIfile\fR and invoke them on the targeted Java
+process(es). In  \fIfile\fR, each command must be written on a single line. 
+Lines starting with # are ignored. Processing of \fIfile\fR ends when
+all lines have been invoked or when a line containing the 'stop' keyword
+is read.
+.LP
+.SH "SEE ALSO"
+.LP
+.RS 3
+.TP 2
+o
+jps(1) 
+.RE
+
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/ExecuteDiagnosticCommand.java	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug     7104647
+ * @summary Basic Test for HotSpotDiagnosticMXBean.execute()
+ * @author  Frederic Parain
+ *
+ * @run main ExecuteDiagnosticCommand
+ */
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import javax.management.MBeanServer;
+
+public class ExecuteDiagnosticCommand {
+    private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
+        "com.sun.management:type=HotSpotDiagnostic";
+
+    public static void main(String[] args) throws Exception {
+        HotSpotDiagnosticMXBean mbean =
+            ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
+        executeDiagnosticCommand(mbean);
+
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        mbean = ManagementFactory.newPlatformMXBeanProxy(mbs,
+                    HOTSPOT_DIAGNOSTIC_MXBEAN_NAME,
+                    HotSpotDiagnosticMXBean.class);
+        executeDiagnosticCommand(mbean);
+    }
+
+    private static void executeDiagnosticCommand(HotSpotDiagnosticMXBean mbean) {
+        String s = mbean.execute("help help");
+        System.out.println(s);
+        s = mbean.execute("help", "help");
+        System.out.println(s);
+        String tab[] = { "help"};
+        s = mbean.execute("help", tab);
+        System.out.println(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/GetDiagnosticCommandInfo.java	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug     7104647
+ * @summary Basic Test for HotSpotDiagnosticMXBean.getDiagnosticCommandInfo()
+ * @author  Frederic Parain
+ *
+ * @run main GetDiagnosticCommandInfo
+ */
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.DiagnosticCommandInfo;
+import com.sun.management.DiagnosticCommandArgumentInfo;
+import com.sun.management.VMOption;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import javax.management.MBeanServer;
+
+public class GetDiagnosticCommandInfo {
+    private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
+        "com.sun.management:type=HotSpotDiagnostic";
+
+    public static void main(String[] args) throws Exception {
+        HotSpotDiagnosticMXBean mbean =
+            ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
+        checkDiagnosticCommandArguments(mbean);
+
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        mbean = ManagementFactory.newPlatformMXBeanProxy(mbs,
+                    HOTSPOT_DIAGNOSTIC_MXBEAN_NAME,
+                    HotSpotDiagnosticMXBean.class);
+        checkDiagnosticCommandArguments(mbean);
+    }
+
+    private static void checkDiagnosticCommandArguments(HotSpotDiagnosticMXBean mbean) {
+        // check getDiagnosticCommandInfo()
+        StringBuilder sb = new StringBuilder();
+        List<DiagnosticCommandInfo> infoList = mbean.getDiagnosticCommandInfo();
+        for(DiagnosticCommandInfo info : infoList) {
+            printCommandInfo(info,sb);
+        }
+        // check getDiagnosticCommandInfo(List<String>)
+        List<String> commands = mbean.getDiagnosticCommands();
+        List<DiagnosticCommandInfo> list2 =
+            mbean.getDiagnosticCommandInfo(commands);
+        for(DiagnosticCommandInfo info : list2) {
+            printCommandInfo(info,sb);
+        }
+        // check getDiagnosticCommandInfo(String)
+        for(String cmd : commands) {
+            DiagnosticCommandInfo info2 = mbean.getDiagnosticCommandInfo(cmd);
+            printCommandInfo(info2,sb);
+        }
+        System.out.println(sb.toString());
+    }
+
+    private static void printCommandInfo(DiagnosticCommandInfo info,
+                                         StringBuilder sb) {
+        sb.append("\t").append(info.getName()).append(":\n");
+        sb.append("\t\tDescription=").append(info.getDescription()).append("\n");
+        sb.append("\t\tImpact=").append(info.getImpact()).append("\n");
+        sb.append("\t\tStatus=");
+        if (info.isEnabled()) {
+            sb.append("Enabled\n");
+        } else {
+            sb.append("Disbled\n");
+        }
+        sb.append("\t\tArguments=");
+        for(DiagnosticCommandArgumentInfo arg : info.getArgumentsInfo()) {
+            printArgumentInfo(arg,sb);
+        }
+    }
+
+    private static void printArgumentInfo(DiagnosticCommandArgumentInfo info,
+                                          StringBuilder sb) {
+        sb.append("\t\t\t").append(info.getName()).append(":\n");
+        sb.append("\t\t\t\tType=").append(info.getType()).append("\n");
+        sb.append("\t\t\t\tDescription=").append(info.getDescription()).append("\n");
+        if(info.getDefault() != null) {
+            sb.append("\t\t\t\tDefault=").append(info.getDefault()).append("\n");
+        }
+        if(info.isMandatory()) {
+            sb.append("\t\t\t\tMandatory\n");
+        } else {
+            sb.append("\t\t\t\tOptional\n");
+        }
+        if(info.isOption()) {
+            sb.append("\t\t\t\tIs an option\n");
+        } else {
+            sb.append("\t\t\t\tIs an argument expected at position");
+            sb.append(info.getPosition());
+            sb.append("\n");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/GetDiagnosticCommands.java	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug     7104647
+ * @summary Basic Test for HotSpotDiagnosticMXBean.getDiagnosticCommands()
+ * @author  Frederic Parain
+ *
+ * @run main GetDiagnosticCommands
+ */
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import javax.management.MBeanServer;
+
+public class GetDiagnosticCommands {
+    private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
+        "com.sun.management:type=HotSpotDiagnostic";
+
+    public static void main(String[] args) throws Exception {
+        HotSpotDiagnosticMXBean mbean =
+            ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
+        checkDiagnosticCommands(mbean);
+
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        mbean = ManagementFactory.newPlatformMXBeanProxy(mbs,
+                    HOTSPOT_DIAGNOSTIC_MXBEAN_NAME,
+                    HotSpotDiagnosticMXBean.class);
+        checkDiagnosticCommands(mbean);
+    }
+
+    private static void checkDiagnosticCommands(HotSpotDiagnosticMXBean mbean) {
+        List<String> commands = mbean.getDiagnosticCommands();
+        System.out.println("Commands:");
+        for (String cmd : commands) {
+            System.out.println(cmd);
+        }
+    }
+}
--- a/jdk/test/sun/tools/common/CommonSetup.sh	Tue Jan 03 08:33:30 2012 -0800
+++ b/jdk/test/sun/tools/common/CommonSetup.sh	Wed Jan 04 03:49:35 2012 -0800
@@ -34,6 +34,7 @@
 #   JMAP        - jmap utility
 #   JPS         - jps utility
 #   JSTACK      - jstack utility
+#   JCMD        - jcmd utility
 #   OS          - operating system name
 #   PATTERN_EOL - grep or sed end-of-line pattern
 #   PATTERN_WS  - grep or sed whitespace pattern
@@ -72,6 +73,7 @@
 JMAP="${TESTJAVA}/bin/jmap"
 JPS="${TESTJAVA}/bin/jps"
 JSTACK="${TESTJAVA}/bin/jstack"
+JCMD="${TESTJAVA}/bin/jcmd"
 
 isCygwin=false
 isMKS=false
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/dcmd-script.txt	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,2 @@
+help help
+stop
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/help_help.out	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,12 @@
+help
+For more information about a specific command use 'help <command>'. With no argument this will show a list of available commands. 'help all' will show help for all commands.
+
+Impact: Low: 
+
+Syntax : help [options] [<command name>]
+
+Arguments:
+	command name : [optional] The name of the command for which we want help (STRING, no default value)
+
+Options: (options must be specified using the <key> or <key>=<value> syntax)
+	-all : [optional] Show help for all commands (BOOLEAN, false)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/jcmd-Defaults.sh	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 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.
+#
+# 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.
+#
+
+# @test
+# @bug 7104647
+# @run shell jcmd-Defaults.sh
+# @summary Test that output of 'jcmd' and 'jcmd -l' match a specific pattern
+
+JCMD="${TESTJAVA}/bin/jcmd"
+
+${JCMD} 2>&1 | awk -f ${TESTSRC}/jcmd_Output1.awk
+
+${JCMD} -l 2>&1 | awk -f ${TESTSRC}/jcmd_Output1.awk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/jcmd-f.sh	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+#
+# Copyright (c) 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.
+#
+# 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.
+#
+
+
+# @test
+# @bug 7104647
+# @summary Unit test for jcmd utility
+#
+# @library ../common
+# @build SimpleApplication ShutdownSimpleApplication
+# @run shell jcmd-f.sh
+
+. ${TESTSRC}/../common/CommonSetup.sh
+. ${TESTSRC}/../common/ApplicationSetup.sh
+
+# Start application and use PORTFILE for coordination
+PORTFILE="${TESTCLASSES}"/shutdown.port
+startApplication SimpleApplication "${PORTFILE}"
+
+# all return statuses are checked in this test
+set +e
+
+failed=0
+
+# -f <script>
+rm -f jcmd.out 2>/dev/null
+${JCMD} $appJavaPid -f ${TESTSRC}/dcmd-script.txt | awk '{ if (NR>1) print $0;}' > jcmd.out 2>&1
+echo jcmd.out
+diff -w jcmd.out ${TESTSRC}/help_help.out
+if [ $? != 0 ]; then
+  echo "Output of jcmd [pid] -f dcmd-script.txt  differ from expected output. Failed."
+  rm -f jcmd.out 2>/dev/null
+  failed=1;
+fi
+
+set -e
+
+stopApplication "${PORTFILE}"
+waitForApplication
+
+exit $failed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/jcmd-help-help.sh	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+#
+# Copyright (c) 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.
+#
+# 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.
+#
+
+
+# @test
+# @bug 7104647
+# @summary Unit test for jcmd utility
+#
+# @library ../common
+# @build SimpleApplication ShutdownSimpleApplication
+# @run shell jcmd-help-help.sh
+
+. ${TESTSRC}/../common/CommonSetup.sh
+. ${TESTSRC}/../common/ApplicationSetup.sh
+
+# Start application and use PORTFILE for coordination
+PORTFILE="${TESTCLASSES}"/shutdown.port
+startApplication SimpleApplication "${PORTFILE}"
+
+# all return statuses are checked in this test
+set +e
+
+failed=0
+
+# help help
+rm -f jcmd.out 2>/dev/null
+${JCMD} $appJavaPid help help | awk '{ if (NR>1) print $0;}' > jcmd.out 2>&1
+echo jcmd.out
+diff -w jcmd.out ${TESTSRC}/help_help.out
+if [ $? != 0 ]; then
+  echo "Output of jcmd [pid] help help differ from expected output. Failed."
+  rm -f jcmd.out 2>/dev/null
+  failed=1;
+fi
+
+set -e
+
+stopApplication "${PORTFILE}"
+waitForApplication
+
+exit $failed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/jcmd-help.sh	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 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.
+#
+# 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.
+#
+
+# @test
+# @bug 7104647
+# @run shell jcmd-help.sh
+# @summary Test that output of 'jcmd -h' matches the usage.out file
+
+JCMD="${TESTJAVA}/bin/jcmd"
+
+rm -f jcmd.out 2>/dev/null
+${JCMD} -h > jcmd.out 2>&1
+
+diff -w jcmd.out ${TESTSRC}/usage.out
+if [ $? != 0 ]
+then
+  echo "Output of jcmd -h differ from expected output. Failed."
+  rm -f jcmd.out 2>/dev/null
+  exit 1
+fi
+
+rm -f jcmd.out 2>/dev/null
+${JCMD} -help > jcmd.out 2>&1
+
+diff -w jcmd.out ${TESTSRC}/usage.out
+if [ $? != 0 ]
+then
+  echo "Output of jcmd -help differ from expected output. Failed."
+  rm -f jcmd.out 2>/dev/null
+  exit 1
+fi
+
+rm -f jcmd.out 2>/dev/null
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/jcmd-pid.sh	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+#
+# Copyright (c) 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.
+#
+# 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.
+#
+
+
+# @test
+# @bug 7104647
+# @summary Unit test for jcmd utility
+#
+# @library ../common
+# @build SimpleApplication ShutdownSimpleApplication
+# @run shell jcmd-pid.sh
+
+. ${TESTSRC}/../common/CommonSetup.sh
+. ${TESTSRC}/../common/ApplicationSetup.sh
+
+# Start application and use PORTFILE for coordination
+PORTFILE="${TESTCLASSES}"/shutdown.port
+startApplication SimpleApplication "${PORTFILE}"
+
+# all return statuses are checked in this test
+set +e
+
+failed=0
+
+# help command 
+${JCMD} $appJavaPid help 2>&1 | awk -f ${TESTSRC}/jcmd_pid_Output1.awk
+if [ $? != 0 ]; then failed=1; fi
+
+# PerfCounter.list option
+${JCMD} $appJavaPid PerfCounter.print 2>&1 | awk -f ${TESTSRC}/jcmd_pid_Output2.awk
+if [ $? != 0 ]; then failed=1; fi
+
+set -e
+
+stopApplication "${PORTFILE}"
+waitForApplication
+
+exit $failed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/jcmd_Output1.awk	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,32 @@
+#
+BEGIN	{
+	    totallines=0; matched=0
+	}
+
+# match on a main class name followed by arbitrary arguments
+/^[0-9]+ [a-z|A-Z][a-z|A-Z|0-9|\.]*($| .*$)/	{
+	    matched++;
+	}
+
+# or match on a path name to a jar file followed by arbitraty arguments
+# - note, jar files ending with ".jar" is only a convention, not a requirement.
+#Theoretically, any valid file name could occur here.
+/^[0-9]+ .*\.jar($| .*$)/	{
+	    matched++;
+}
+
+# or match on the condition that the class name is not available
+/^[0-9]+ -- process information unavailable$/	{
+	    matched++;
+	}
+
+	{ totallines++; print $0 }
+
+END	{
+	    if ((totallines > 0) && (matched == totallines)) {
+	        exit 0
+	    }
+	    else {
+	        exit 1
+	    }
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/jcmd_pid_Output1.awk	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,58 @@
+#
+
+# section 0 = [PID]:
+# section 1 = "The following commands are available:"
+# section 2 = <list of commands, one command per line>
+# section 3 = blank line
+# section 4 = "For more information about a specific command use 'help <command>'."
+
+BEGIN	{
+    totallines=0; matched=0; section=0;
+}
+
+# match the first line (PID of the JVM followed by ':')
+/^[0-9]+:/{
+    if(section==0) {
+	matched++;
+	section=1;
+    }
+}
+
+/^The following commands are available:$/{
+    if(section==1) {
+	matched++;
+	section=2;
+    }
+}
+
+# match a command name
+/^[a-z|A-Z][a-z|A-Z|0-9|\.|_]*$/{
+    if(section==2) {
+	matched++;
+    }
+}
+
+/^$/{
+    if(section==2) {
+	matched++;
+	section=4;
+    }
+}
+
+/^For more information about a specific command use 'help <command>'\.$/{
+    if(section==4) {
+	matched++;
+	section=5;
+    }
+}
+
+{ totallines++; print $0 }
+
+END {
+    if ((totallines > 0) && (matched == totallines)) {
+	exit 0
+    }
+    else {
+	exit 1
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/jcmd_pid_Output2.awk	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,25 @@
+#
+BEGIN	{
+	    totallines=0; matched=0
+	}
+
+# match on counter name followed '=' and an arbitrary value
+/^[a-z|A-Z][a-z|A-Z|0-9|\.|_]*=.*$/	{
+	    matched++;
+	}
+
+# or match the first line (PID of the JVM followed by ':')
+/^[0-9]+:/	{
+	    matched++;
+	}
+
+	{ totallines++; print $0 }
+
+END	{
+    if ((totallines > 0) && (matched == totallines)) {
+	exit 0
+    }
+    else {
+	exit 1
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jcmd/usage.out	Wed Jan 04 03:49:35 2012 -0800
@@ -0,0 +1,15 @@
+Usage: jcmd <pid | main class> <command ...|PerfCounter.print|-f file>
+   or: jcmd -l                                                       
+   or: jcmd -h                                                       
+                                                                  
+  command must be a valid jcmd command for the selected jvm.    
+  Use the command "help" to see which commands are available.   
+  If the pid is 0, commands will be sent to all Java processes.   
+  The main class argument will be used to match (either partially 
+  or fully) the class used to start Java.                         
+  If no options are given, lists Java processes (same as -p).     
+                                                                  
+  PerfCounter.print display the counters exposed by this process   
+  -f  read and execute commands from the file                     
+  -l  list JVM processes on the local machine                     
+  -h  this help