8209790: SA tools not providing option to connect to debug server
Reviewed-by: sspitsyn, cjplummer
This commit is contained in:
parent
dc300483a7
commit
cf39d96d3a
@ -46,37 +46,59 @@ public class SALauncher {
|
||||
}
|
||||
|
||||
private static boolean commonHelp(String mode) {
|
||||
return commonHelp(mode, false);
|
||||
}
|
||||
|
||||
private static boolean commonHelpWithConnect(String mode) {
|
||||
return commonHelp(mode, true);
|
||||
}
|
||||
|
||||
private static boolean commonHelp(String mode, boolean canConnectToRemote) {
|
||||
// --pid <pid>
|
||||
// --exe <exe>
|
||||
// --core <core>
|
||||
System.out.println(" --pid <pid> \tTo attach to and operate on the given live process.");
|
||||
System.out.println(" --core <corefile>\tTo operate on the given core file.");
|
||||
// --connect [<id>@]<host>
|
||||
System.out.println(" --pid <pid> To attach to and operate on the given live process.");
|
||||
System.out.println(" --core <corefile> To operate on the given core file.");
|
||||
System.out.println(" --exe <executable for corefile>");
|
||||
if (canConnectToRemote) {
|
||||
System.out.println(" --connect [<id>@]<host> To connect to a remote debug server (debugd).");
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println(" The --core and --exe options must be set together to give the core");
|
||||
System.out.println(" file, and associated executable, to operate on. Otherwise the --pid");
|
||||
System.out.println(" option can be set to operate on a live process.");
|
||||
System.out.println(" The arguments for --exe and --core can use absolute or relative paths.");
|
||||
System.out.println(" file, and associated executable, to operate on. They can use");
|
||||
System.out.println(" absolute or relative paths.");
|
||||
System.out.println(" The --pid option can be set to operate on a live process.");
|
||||
if (canConnectToRemote) {
|
||||
System.out.println(" The --connect option can be set to connect to a debug server (debugd).");
|
||||
System.out.println(" --core, --pid, and --connect are mutually exclusive.");
|
||||
} else {
|
||||
System.out.println(" --core and --pid are mutually exclusive.");
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println(" Examples: jhsdb " + mode + " --pid 1234");
|
||||
System.out.println(" or jhsdb " + mode + " --core ./core.1234 --exe ./myexe");
|
||||
if (canConnectToRemote) {
|
||||
System.out.println(" or jhsdb " + mode + " --connect debugserver");
|
||||
System.out.println(" or jhsdb " + mode + " --connect id@debugserver");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean debugdHelp() {
|
||||
// [options] <pid> [server-id]
|
||||
// [options] <executable> <core> [server-id]
|
||||
System.out.println(" --serverid <id> \tA unique identifier for this debug server.");
|
||||
System.out.println(" --serverid <id> A unique identifier for this debug server.");
|
||||
return commonHelp("debugd");
|
||||
}
|
||||
|
||||
private static boolean jinfoHelp() {
|
||||
// --flags -> -flags
|
||||
// --sysprops -> -sysprops
|
||||
System.out.println(" --flags \tTo print VM flags.");
|
||||
System.out.println(" --sysprops \tTo print Java System properties.");
|
||||
System.out.println(" <no option> \tTo print both of the above.");
|
||||
return commonHelp("jinfo");
|
||||
System.out.println(" --flags To print VM flags.");
|
||||
System.out.println(" --sysprops To print Java System properties.");
|
||||
System.out.println(" <no option> To print both of the above.");
|
||||
return commonHelpWithConnect("jinfo");
|
||||
}
|
||||
|
||||
private static boolean jmapHelp() {
|
||||
@ -86,27 +108,27 @@ public class SALauncher {
|
||||
// --clstats -> -clstats
|
||||
// --finalizerinfo -> -finalizerinfo
|
||||
|
||||
System.out.println(" <no option> \tTo print same info as Solaris pmap.");
|
||||
System.out.println(" --heap \tTo print java heap summary.");
|
||||
System.out.println(" --binaryheap \tTo dump java heap in hprof binary format.");
|
||||
System.out.println(" --dumpfile <name>\tThe name of the dump file.");
|
||||
System.out.println(" --histo \tTo print histogram of java object heap.");
|
||||
System.out.println(" --clstats \tTo print class loader statistics.");
|
||||
System.out.println(" --finalizerinfo \tTo print information on objects awaiting finalization.");
|
||||
return commonHelp("jmap");
|
||||
System.out.println(" <no option> To print same info as Solaris pmap.");
|
||||
System.out.println(" --heap To print java heap summary.");
|
||||
System.out.println(" --binaryheap To dump java heap in hprof binary format.");
|
||||
System.out.println(" --dumpfile <name> The name of the dump file.");
|
||||
System.out.println(" --histo To print histogram of java object heap.");
|
||||
System.out.println(" --clstats To print class loader statistics.");
|
||||
System.out.println(" --finalizerinfo To print information on objects awaiting finalization.");
|
||||
return commonHelpWithConnect("jmap");
|
||||
}
|
||||
|
||||
private static boolean jstackHelp() {
|
||||
// --locks -> -l
|
||||
// --mixed -> -m
|
||||
System.out.println(" --locks \tTo print java.util.concurrent locks.");
|
||||
System.out.println(" --mixed \tTo print both Java and native frames (mixed mode).");
|
||||
return commonHelp("jstack");
|
||||
System.out.println(" --locks To print java.util.concurrent locks.");
|
||||
System.out.println(" --mixed To print both Java and native frames (mixed mode).");
|
||||
return commonHelpWithConnect("jstack");
|
||||
}
|
||||
|
||||
private static boolean jsnapHelp() {
|
||||
System.out.println(" --all \tTo print all performance counters.");
|
||||
return commonHelp("jsnap");
|
||||
System.out.println(" --all To print all performance counters.");
|
||||
return commonHelpWithConnect("jsnap");
|
||||
}
|
||||
|
||||
private static boolean toolHelp(String toolName) {
|
||||
@ -134,10 +156,12 @@ public class SALauncher {
|
||||
return launcherHelp();
|
||||
}
|
||||
|
||||
private static final String NO_REMOTE = null;
|
||||
|
||||
private static void buildAttachArgs(ArrayList<String> newArgs, String pid,
|
||||
String exe, String core, boolean allowEmpty) {
|
||||
if (!allowEmpty && (pid == null) && (exe == null)) {
|
||||
throw new SAGetoptException("You have to set --pid or --exe.");
|
||||
String exe, String core, String remote, boolean allowEmpty) {
|
||||
if (!allowEmpty && (pid == null) && (exe == null) && (remote == NO_REMOTE)) {
|
||||
throw new SAGetoptException("You have to set --pid or --exe or --connect.");
|
||||
}
|
||||
|
||||
if (pid != null) { // Attach to live process
|
||||
@ -145,13 +169,17 @@ public class SALauncher {
|
||||
throw new SAGetoptException("Unnecessary argument: --exe");
|
||||
} else if (core != null) {
|
||||
throw new SAGetoptException("Unnecessary argument: --core");
|
||||
} else if (remote != NO_REMOTE) {
|
||||
throw new SAGetoptException("Unnecessary argument: --connect");
|
||||
} else if (!pid.matches("^\\d+$")) {
|
||||
throw new SAGetoptException("Invalid pid: " + pid);
|
||||
}
|
||||
|
||||
newArgs.add(pid);
|
||||
} else if (exe != null) {
|
||||
if (exe.length() == 0) {
|
||||
if (remote != NO_REMOTE) {
|
||||
throw new SAGetoptException("Unnecessary argument: --connect");
|
||||
} else if (exe.length() == 0) {
|
||||
throw new SAGetoptException("You have to set --exe.");
|
||||
}
|
||||
|
||||
@ -162,6 +190,8 @@ public class SALauncher {
|
||||
}
|
||||
|
||||
newArgs.add(core);
|
||||
} else if (remote != NO_REMOTE) {
|
||||
newArgs.add(remote);
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +220,7 @@ public class SALauncher {
|
||||
}
|
||||
}
|
||||
|
||||
buildAttachArgs(newArgs, pid, exe, core, true);
|
||||
buildAttachArgs(newArgs, pid, exe, core, NO_REMOTE, true);
|
||||
CLHSDB.main(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
@ -219,19 +249,20 @@ public class SALauncher {
|
||||
}
|
||||
}
|
||||
|
||||
buildAttachArgs(newArgs, pid, exe, core, true);
|
||||
buildAttachArgs(newArgs, pid, exe, core, NO_REMOTE, true);
|
||||
HSDB.main(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
private static void runJSTACK(String[] oldArgs) {
|
||||
SAGetopt sg = new SAGetopt(oldArgs);
|
||||
String[] longOpts = {"exe=", "core=", "pid=",
|
||||
String[] longOpts = {"exe=", "core=", "pid=", "connect=",
|
||||
"mixed", "locks"};
|
||||
|
||||
ArrayList<String> newArgs = new ArrayList();
|
||||
String pid = null;
|
||||
String exe = null;
|
||||
String core = null;
|
||||
String remote = NO_REMOTE;
|
||||
String s = null;
|
||||
|
||||
while((s = sg.next(null, longOpts)) != null) {
|
||||
@ -247,6 +278,10 @@ public class SALauncher {
|
||||
pid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("connect")) {
|
||||
remote = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("mixed")) {
|
||||
newArgs.add("-m");
|
||||
continue;
|
||||
@ -257,20 +292,21 @@ public class SALauncher {
|
||||
}
|
||||
}
|
||||
|
||||
buildAttachArgs(newArgs, pid, exe, core, false);
|
||||
buildAttachArgs(newArgs, pid, exe, core, remote, false);
|
||||
JStack jstack = new JStack(false, false);
|
||||
jstack.runWithArgs(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
private static void runJMAP(String[] oldArgs) {
|
||||
SAGetopt sg = new SAGetopt(oldArgs);
|
||||
String[] longOpts = {"exe=", "core=", "pid=",
|
||||
String[] longOpts = {"exe=", "core=", "pid=", "connect=",
|
||||
"heap", "binaryheap", "dumpfile=", "histo", "clstats", "finalizerinfo"};
|
||||
|
||||
ArrayList<String> newArgs = new ArrayList();
|
||||
String pid = null;
|
||||
String exe = null;
|
||||
String core = null;
|
||||
String remote = NO_REMOTE;
|
||||
String s = null;
|
||||
String dumpfile = null;
|
||||
boolean requestHeapdump = false;
|
||||
@ -288,6 +324,10 @@ public class SALauncher {
|
||||
pid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("connect")) {
|
||||
remote = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("heap")) {
|
||||
newArgs.add("-heap");
|
||||
continue;
|
||||
@ -325,19 +365,20 @@ public class SALauncher {
|
||||
}
|
||||
}
|
||||
|
||||
buildAttachArgs(newArgs, pid, exe, core, false);
|
||||
buildAttachArgs(newArgs, pid, exe, core, remote, false);
|
||||
JMap.main(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
private static void runJINFO(String[] oldArgs) {
|
||||
SAGetopt sg = new SAGetopt(oldArgs);
|
||||
String[] longOpts = {"exe=", "core=", "pid=",
|
||||
String[] longOpts = {"exe=", "core=", "pid=", "connect=",
|
||||
"flags", "sysprops"};
|
||||
|
||||
ArrayList<String> newArgs = new ArrayList();
|
||||
String exe = null;
|
||||
String pid = null;
|
||||
String core = null;
|
||||
String remote = NO_REMOTE;
|
||||
String s = null;
|
||||
|
||||
while((s = sg.next(null, longOpts)) != null) {
|
||||
@ -353,6 +394,10 @@ public class SALauncher {
|
||||
pid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("connect")) {
|
||||
remote = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("flags")) {
|
||||
newArgs.add("-flags");
|
||||
continue;
|
||||
@ -363,18 +408,19 @@ public class SALauncher {
|
||||
}
|
||||
}
|
||||
|
||||
buildAttachArgs(newArgs, pid, exe, core, false);
|
||||
buildAttachArgs(newArgs, pid, exe, core, remote, false);
|
||||
JInfo.main(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
private static void runJSNAP(String[] oldArgs) {
|
||||
SAGetopt sg = new SAGetopt(oldArgs);
|
||||
String[] longOpts = {"exe=", "core=", "pid=", "all"};
|
||||
String[] longOpts = {"exe=", "core=", "pid=", "connect=", "all"};
|
||||
|
||||
ArrayList<String> newArgs = new ArrayList();
|
||||
String exe = null;
|
||||
String pid = null;
|
||||
String core = null;
|
||||
String remote = NO_REMOTE;
|
||||
String s = null;
|
||||
|
||||
while((s = sg.next(null, longOpts)) != null) {
|
||||
@ -390,13 +436,17 @@ public class SALauncher {
|
||||
pid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("connect")) {
|
||||
remote = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("all")) {
|
||||
newArgs.add("-a");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
buildAttachArgs(newArgs, pid, exe, core, false);
|
||||
buildAttachArgs(newArgs, pid, exe, core, remote, false);
|
||||
JSnap.main(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
@ -436,7 +486,7 @@ public class SALauncher {
|
||||
}
|
||||
}
|
||||
|
||||
buildAttachArgs(newArgs, pid, exe, core, false);
|
||||
buildAttachArgs(newArgs, pid, exe, core, NO_REMOTE, false);
|
||||
if (serverid != null) {
|
||||
newArgs.add(serverid);
|
||||
}
|
||||
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 8209790
|
||||
* @summary Checks ability for connecting to debug server (jstack, jmap, jinfo, jsnap)
|
||||
* @requires vm.hasSAandCanAttach
|
||||
* @requires os.family != "windows"
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @library /test/lib
|
||||
*
|
||||
* @run main/othervm DebugdConnectTest
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import jdk.test.lib.JDKToolLauncher;
|
||||
import jdk.test.lib.apps.LingeredApp;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
|
||||
public class DebugdConnectTest {
|
||||
|
||||
private static OutputAnalyzer runJHSDB(String command, String id) throws IOException, InterruptedException {
|
||||
JDKToolLauncher jhsdbLauncher = JDKToolLauncher.createUsingTestJDK("jhsdb");
|
||||
jhsdbLauncher.addToolArg(command);
|
||||
jhsdbLauncher.addToolArg("--connect");
|
||||
if (id != null) {
|
||||
jhsdbLauncher.addToolArg(id + "@localhost");
|
||||
} else {
|
||||
jhsdbLauncher.addToolArg("localhost");
|
||||
}
|
||||
|
||||
Process jhsdb = (new ProcessBuilder(jhsdbLauncher.getCommand())).start();
|
||||
OutputAnalyzer out = new OutputAnalyzer(jhsdb);
|
||||
|
||||
jhsdb.waitFor();
|
||||
|
||||
System.out.println(out.getStdout());
|
||||
System.err.println(out.getStderr());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private static void runJSTACK(String id) throws IOException, InterruptedException {
|
||||
OutputAnalyzer out = runJHSDB("jstack", id);
|
||||
|
||||
out.shouldContain("LingeredApp");
|
||||
out.stderrShouldBeEmpty();
|
||||
out.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static void runJMAP(String id) throws IOException, InterruptedException {
|
||||
OutputAnalyzer out = runJHSDB("jmap", id);
|
||||
|
||||
out.shouldContain("JVM version is");
|
||||
out.stderrShouldBeEmpty();
|
||||
out.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static void runJINFO(String id) throws IOException, InterruptedException {
|
||||
OutputAnalyzer out = runJHSDB("jinfo", id);
|
||||
|
||||
out.shouldContain("Java System Properties:");
|
||||
out.stderrShouldBeEmpty();
|
||||
out.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static void runJSNAP(String id) throws IOException, InterruptedException {
|
||||
OutputAnalyzer out = runJHSDB("jsnap", id);
|
||||
|
||||
out.shouldContain("java.vm.name=");
|
||||
out.stderrShouldBeEmpty();
|
||||
out.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static void runTests(String id, long debuggeePid) throws IOException, InterruptedException {
|
||||
DebugdUtils debugd = new DebugdUtils(id);
|
||||
debugd.attach(debuggeePid);
|
||||
|
||||
try {
|
||||
runJSTACK(id);
|
||||
runJMAP(id);
|
||||
runJINFO(id);
|
||||
runJSNAP(id);
|
||||
} finally {
|
||||
debugd.detach();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
LingeredApp app = null;
|
||||
|
||||
try {
|
||||
app = LingeredApp.startApp();
|
||||
System.out.println("Started LingeredApp with pid " + app.getPid());
|
||||
|
||||
System.out.println("debugd connection test with server id:");
|
||||
runTests("test", app.getPid());
|
||||
|
||||
System.out.println("debugd connection test without server id:");
|
||||
runTests(null, app.getPid());
|
||||
} finally {
|
||||
LingeredApp.stopApp(app);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import jdk.test.lib.JDKToolLauncher;
|
||||
|
||||
|
||||
public class DebugdUtils {
|
||||
|
||||
private static final String GOLDEN = "Debugger attached";
|
||||
|
||||
private final String id;
|
||||
|
||||
private Process debugdProcess;
|
||||
|
||||
public DebugdUtils(String id) {
|
||||
this.id = id;
|
||||
debugdProcess = null;
|
||||
}
|
||||
|
||||
public void attach(long pid) throws IOException {
|
||||
JDKToolLauncher jhsdbLauncher = JDKToolLauncher.createUsingTestJDK("jhsdb");
|
||||
jhsdbLauncher.addToolArg("debugd");
|
||||
jhsdbLauncher.addToolArg("--pid");
|
||||
jhsdbLauncher.addToolArg(Long.toString(pid));
|
||||
if (id != null) {
|
||||
jhsdbLauncher.addToolArg("--serverid");
|
||||
jhsdbLauncher.addToolArg(id);
|
||||
}
|
||||
debugdProcess = (new ProcessBuilder(jhsdbLauncher.getCommand())).start();
|
||||
|
||||
// Wait until debug server attached
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(debugdProcess.getErrorStream()))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains(GOLDEN)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void detach() throws InterruptedException {
|
||||
if (debugdProcess != null) {
|
||||
debugdProcess.destroy();
|
||||
debugdProcess.waitFor();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user