8209109: [TEST] rewrite com/sun/jdi shell tests to java version - step1
Reviewed-by: sspitsyn, jcbeyler
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jdi/ArrayLengthDumpTest.java Tue Aug 14 11:56:32 2018 -0700
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2002, 2018, 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 4422141 4695338
+ * @summary TTY: .length field for arrays in print statements in jdb not recognized
+ * TTY: dump <ArrayReference> command not implemented.
+ * @comment converted from test/jdk/com/sun/jdi/ArrayLengthDumpTest.sh
+ *
+ * @library /test/lib
+ * @build ArrayLengthDumpTest
+ * @run main/othervm ArrayLengthDumpTest
+ */
+
+import lib.jdb.JdbCommand;
+import lib.jdb.JdbTest;
+import jdk.test.lib.process.OutputAnalyzer;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+class ArrayLengthDumpTarg {
+ static final int [] i = {0,1,2,3,4,5,6};
+ String [] s = {"zero", "one", "two", "three", "four"};
+ String [][] t = {s, s, s, s, s, s, s, s, s, s, s};
+ int length = 5;
+
+ private void bar() {
+ }
+
+ private void foo() {
+ ArrayLengthDumpTarg u[] = { new ArrayLengthDumpTarg(),
+ new ArrayLengthDumpTarg(),
+ new ArrayLengthDumpTarg(),
+ new ArrayLengthDumpTarg(),
+ new ArrayLengthDumpTarg(),
+ new ArrayLengthDumpTarg() };
+ int k = u.length;
+ System.out.println(" u.length is: " + k);
+ k = this.s.length;
+ System.out.println(" this.s.length is: " + k);
+ k = this.t.length;
+ System.out.println(" this.t.length is: " + k);
+ k = this.t[1].length;
+ System.out.println("this.t[1].length is: " + k);
+ k = i.length;
+ System.out.println(" i.length is: " + k);
+ bar(); // @1 breakpoint
+ }
+
+ public static void main(String[] args) {
+ ArrayLengthDumpTarg my = new ArrayLengthDumpTarg();
+ my.foo();
+ }
+}
+
+public class ArrayLengthDumpTest extends JdbTest {
+ public static void main(String argv[]) {
+ new ArrayLengthDumpTest().run();
+ }
+
+ public ArrayLengthDumpTest() {
+ super(DEBUGGEE_CLASS);
+ }
+
+ private static final String DEBUGGEE_CLASS = ArrayLengthDumpTarg.class.getName();
+
+ @Override
+ protected void runCases() {
+ setBreakpoints(System.getProperty("test.src") + "/ArrayLengthDumpTest.java", 1);
+
+ // Run to breakpoint #1
+ jdb.command(JdbCommand.run());
+
+ List<String> reply = new LinkedList<>();
+ reply.addAll(jdb.command(JdbCommand.dump("this")));
+ reply.addAll(jdb.command(JdbCommand.dump("this.s.length")));
+ reply.addAll(jdb.command(JdbCommand.dump("this.s")));
+ reply.addAll(jdb.command(JdbCommand.dump("this.t.length")));
+ reply.addAll(jdb.command(JdbCommand.dump("this.t[1].length")));
+ reply.addAll(jdb.command(JdbCommand.dump("ArrayLengthDumpTarg.i.length")));
+ reply.addAll(jdb.command(JdbCommand.dump("this.length")));
+
+ new OutputAnalyzer(reply.stream().collect(Collectors.joining(lineSeparator)))
+ // Test the fix for 4690242:
+ .shouldNotContain("No instance field or method with the name length in")
+ .shouldNotContain("No static field or method with the name length")
+ // Test the fix for 4695338:
+ .shouldContain("\"zero\", \"one\", \"two\", \"three\", \"four\"");
+
+ jdb.contToExit(1);
+ }
+
+}
--- a/test/jdk/com/sun/jdi/ArrayLengthDumpTest.sh Tue Aug 14 13:16:26 2018 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-#!/bin/sh
-
-#
-# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# 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 4422141 4695338
-# @summary TTY: .length field for arrays in print statements in jdb not recognized
-# TTY: dump <ArrayReference> command not implemented.
-# @author Tim Bell
-#
-# @key intermittent
-# @run shell ArrayLengthDumpTest.sh
-#
-classname=ArrayLengthDumpTarg
-
-createJavaFile()
-{
- cat <<EOF > $classname.java.1
-class $classname {
- static final int [] i = {0,1,2,3,4,5,6};
- String [] s = {"zero", "one", "two", "three", "four"};
- String [][] t = {s, s, s, s, s, s, s, s, s, s, s};
- int length = 5;
-
- public void bar() {
- }
-
- public void foo() {
- ArrayLengthDumpTarg u[] = { new ArrayLengthDumpTarg(),
- new ArrayLengthDumpTarg(),
- new ArrayLengthDumpTarg(),
- new ArrayLengthDumpTarg(),
- new ArrayLengthDumpTarg(),
- new ArrayLengthDumpTarg() };
- int k = u.length;
- System.out.println(" u.length is: " + k);
- k = this.s.length;
- System.out.println(" this.s.length is: " + k);
- k = this.t.length;
- System.out.println(" this.t.length is: " + k);
- k = this.t[1].length;
- System.out.println("this.t[1].length is: " + k);
- k = i.length;
- System.out.println(" i.length is: " + k);
- bar(); // @1 breakpoint
- }
-
- public static void main(String[] args) {
- ArrayLengthDumpTarg my = new ArrayLengthDumpTarg();
- my.foo();
- }
-}
-EOF
-}
-
-# This is called to feed cmds to jdb.
-dojdbCmds()
-{
- setBkpts @1
- runToBkpt @1
- cmd dump this
- cmd dump this.s.length
- cmd dump this.s
- cmd dump this.t.length
- cmd dump this.t[1].length
- cmd dump ArrayLengthDumpTarg.i.length
- cmd dump this.length
- cmd allowExit cont
-}
-
-mysetup()
-{
- if [ -z "$TESTSRC" ] ; then
- TESTSRC=.
- fi
-
- for ii in . $TESTSRC $TESTSRC/.. ; do
- if [ -r "$ii/ShellScaffold.sh" ] ; then
- . $ii/ShellScaffold.sh
- break
- fi
- done
-}
-
-
-# You could replace this next line with the contents
-# of ShellScaffold.sh and this script will run just the same.
-mysetup
-
-runit
-#
-# Test the fix for 4690242:
-#
-jdbFailIfPresent "No instance field or method with the name length in" 50
-jdbFailIfPresent "No static field or method with the name length" 50
-#
-# Test the fix for 4695338:
-#
-jdbFailIfNotPresent "\"zero\", \"one\", \"two\", \"three\", \"four\"" 50
-pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jdi/BreakpointWithFullGC.java Tue Aug 14 11:56:32 2018 -0700
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2009, 2018, 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 6862295
+ * @summary Verify breakpoints still work after a full GC.
+ * @comment converted from test/jdk/com/sun/jdi/BreakpointWithFullGC.sh
+ *
+ * @library /test/lib
+ * @compile -g BreakpointWithFullGC.java
+ * @run main/othervm BreakpointWithFullGC
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import lib.jdb.Jdb;
+import lib.jdb.JdbCommand;
+import lib.jdb.JdbTest;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+class BreakpointWithFullGCTarg {
+ public static List<Object> objList = new ArrayList<>();
+
+ private static void init(int numObjs) {
+ for (int i = 0; i < numObjs; i++) {
+ objList.add(new Object());
+ }
+ }
+
+ public static void main(String[] args) {
+ for (int i = 0; i < 10; i++) {
+ System.out.println("top of loop"); // @1 breakpoint
+ init(500000);
+ objList.clear();
+ System.gc();
+ System.out.println("bottom of loop"); // @1 breakpoint
+ }
+ System.out.println("end of test"); // @1 breakpoint
+ }
+}
+
+public class BreakpointWithFullGC extends JdbTest {
+ public static void main(String argv[]) {
+ new BreakpointWithFullGC().run();
+ }
+
+ public BreakpointWithFullGC() {
+ super(new Jdb.LaunchOptions(DEBUGGEE_CLASS)
+ .debuggeeOptions(DEBUGGEE_OPTIONS));
+ }
+
+ private static final String DEBUGGEE_CLASS = BreakpointWithFullGCTarg.class.getName();
+ // Hijacking the mode parameter to make sure we use a small amount
+ // of memory and can see what GC is doing.
+ private static final String DEBUGGEE_OPTIONS = "-Xmx32m -verbose:gc";
+
+ @Override
+ protected void runCases() {
+ setBreakpoints(System.getProperty("test.src") + "/BreakpointWithFullGC.java", 1);
+
+ List<String> reply = new LinkedList<>();
+
+ // get to the first loop breakpoint
+ reply.addAll(jdb.command(JdbCommand.run()));
+ // 19 "cont" commands gets us through all the loop breakpoints.
+ for (int i = 1; i <= 19; i++) {
+ reply.addAll(jdb.command(JdbCommand.cont()));
+ }
+ // get to the last breakpoint
+ reply.addAll(jdb.command(JdbCommand.cont()));
+
+ new OutputAnalyzer(reply.stream().collect(Collectors.joining(lineSeparator)))
+ // make sure we hit the first breakpoint at least once
+ .stdoutShouldMatch("System\\..*top of loop")
+ // make sure we hit the second breakpoint at least once
+ .stdoutShouldMatch("System\\..*bottom of loop")
+ // make sure we hit the last breakpoint
+ .stdoutShouldMatch("System\\..*end of test")
+ // make sure we had at least one full GC
+ // Prior to JDK9-B95, the pattern was 'Full GC'
+ .stdoutShouldContain("Pause Full (System.gc())")
+ // check for error message due to thread ID change
+ .stderrShouldNotContain("Exception in thread \"event-handler\" java.lang.NullPointerException");
+
+ jdb.contToExit(1);
+ }
+}
--- a/test/jdk/com/sun/jdi/BreakpointWithFullGC.sh Tue Aug 14 13:16:26 2018 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-#!/bin/sh
-
-#
-# Copyright (c) 2009, 2013, 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 6862295
-# @summary Verify breakpoints still work after a full GC.
-# @author dcubed (based on the test program posted to the following
-# Eclipse thread https://bugs.eclipse.org/bugs/show_bug.cgi?id=279137)
-#
-# @key intermittent
-# @run shell BreakpointWithFullGC.sh
-
-compileOptions=-g
-# Hijacking the mode parameter to make sure we use a small amount
-# of memory and can see what GC is doing.
-mode="-Xmx32m -verbose:gc"
-# Force use of a GC framework collector to see the original failure.
-#mode="$mode -XX:+UseSerialGC"
-
-# Uncomment this to see the JDI trace
-#jdbOptions=-dbgtrace
-
-createJavaFile()
-{
- cat <<EOF > $1.java.1
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class $1 {
- public static List<Object> objList = new ArrayList<Object>();
-
- private static void init(int numObjs) {
- for (int i = 0; i < numObjs; i++) {
- objList.add(new Object());
- }
- }
-
- public static void main(String[] args) {
- for (int i = 0; i < 10; i++) {
- System.out.println("top of loop"); // @1 breakpoint
- init(500000);
- objList.clear();
- System.gc();
- System.out.println("bottom of loop"); // @1 breakpoint
- }
- System.out.println("end of test"); // @1 breakpoint
- }
-}
-
-EOF
-}
-
-# This is called to feed cmds to jdb.
-dojdbCmds()
-{
- setBkpts @1
-
- # get to the first loop breakpoint
- runToBkpt
- # 19 "cont" commands gets us through all the loop breakpoints.
- # Use for-loop instead of while-loop to avoid creating processes
- # for '[' and 'expr'.
- for ii in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19; do
- contToBkpt
- done
- # get to the last breakpoint
- contToBkpt
-}
-
-
-mysetup()
-{
- if [ -z "$TESTSRC" ] ; then
- TESTSRC=.
- fi
-
- for ii in . $TESTSRC $TESTSRC/.. ; do
- if [ -r "$ii/ShellScaffold.sh" ] ; then
- . $ii/ShellScaffold.sh
- break
- fi
- done
-}
-
-# You could replace this next line with the contents
-# of ShellScaffold.sh and this script will run just the same.
-mysetup
-
-runit
-
-# make sure we hit the first breakpoint at least once
-jdbFailIfNotPresent 'System\..*top of loop'
-
-# make sure we hit the second breakpoint at least once
-jdbFailIfNotPresent 'System\..*bottom of loop'
-
-# make sure we hit the last breakpoint
-jdbFailIfNotPresent 'System\..*end of test'
-
-# make sure we had at least one full GC
-# Prior to JDK9-B95, the pattern was 'Full GC'
-debuggeeMatchRegexp '^.*?\bPause Full\b\(System.gc\(\)\)\b.*?$'
-
-# check for error message due to thread ID change
-debuggeeFailIfPresent \
- 'Exception in thread "event-handler" java.lang.NullPointerException'
-
-pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jdi/lib/jdb/Jdb.java Tue Aug 14 11:56:32 2018 -0700
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+package lib.jdb;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.process.StreamPumper;
+
+public class Jdb {
+
+ public static class LaunchOptions {
+ public final String debuggeeClass;
+ public String debuggeeOptions;
+
+ public LaunchOptions(String debuggeeClass) {
+ this.debuggeeClass = debuggeeClass;
+ }
+ public LaunchOptions debuggeeOptions(String options) {
+ debuggeeOptions = options;
+ return this;
+ }
+ }
+
+ public static Jdb launchLocal(LaunchOptions options) {
+ StringBuilder connOpts = new StringBuilder("com.sun.jdi.CommandLineLaunch:");
+ if (options.debuggeeOptions != null) {
+ connOpts.append("options=")
+ .append(options.debuggeeOptions)
+ .append(",");
+ }
+ connOpts.append("main=")
+ .append(options.debuggeeClass);
+
+ return new Jdb("-connect", connOpts.toString());
+ }
+
+ public static Jdb launchLocal(String debuggeeClass) {
+ return new Jdb("-connect", "com.sun.jdi.CommandLineLaunch:main=" + debuggeeClass);
+ }
+
+ public Jdb(String... args) {
+ ProcessBuilder pb = new ProcessBuilder(JDKToolFinder.getTestJDKTool("jdb"));
+ pb.command().addAll(Arrays.asList(args));
+ System.out.println("Launching jdb:" + pb.command().stream().collect(Collectors.joining(" ")));
+ try {
+ p = pb.start();
+ } catch (IOException ex) {
+ throw new RuntimeException("failed to launch pdb", ex);
+ }
+ StreamPumper stdout = new StreamPumper(p.getInputStream());
+ StreamPumper stderr = new StreamPumper(p.getErrorStream());
+
+ stdout.addPump(new StreamPumper.StreamPump(outputHandler));
+ stderr.addPump(new StreamPumper.StreamPump(outputHandler));
+
+ stdout.process();
+ stderr.process();
+
+ inputWriter = new PrintWriter(p.getOutputStream(), true);
+ }
+
+ private final Process p;
+ private final OutputHandler outputHandler = new OutputHandler();
+ private final PrintWriter inputWriter;
+
+ private static final String lineSeparator = System.getProperty("line.separator");
+ // wait time before check jdb output (in ms)
+ private static long sleepTime = 1000;
+ // max time to wait for jdb output (in ms)
+ private static long timeout = 60000;
+
+ // jdb prompt when debuggee is not started nor suspended after breakpoint
+ public static final String SIMPLE_PROMPT = "> ";
+ // pattern for message of a breakpoint hit
+ public static final String BREAKPOINT_HIT = "Breakpoint hit:";
+ // pattern for message of an application exit
+ public static final String APPLICATION_EXIT = "The application exited";
+ // pattern for message of an application disconnect
+ public static final String APPLICATION_DISCONNECTED = "The application has been disconnected";
+
+
+ // Check whether the process has been terminated
+ public boolean terminated() {
+ try {
+ p.exitValue();
+ return true;
+ } catch (IllegalThreadStateException e) {
+ return false;
+ }
+ }
+
+ // waits until the process shutdown or crash
+ public boolean waitFor (long timeout, TimeUnit unit) {
+ try {
+ return p.waitFor(timeout, unit);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
+ // ugly cleanup
+ public void terminate() {
+ p.destroy();
+ }
+
+
+ // waits until string {@pattern} appears in the jdb output, within the last {@code lines} lines.
+ /* Comment from original /test/jdk/com/sun/jdi/ShellScaffold.sh
+ # Now we have to wait for the next jdb prompt. We wait for a pattern
+ # to appear in the last line of jdb output. Normally, the prompt is
+ #
+ # 1) ^main[89] @
+ #
+ # where ^ means start of line, and @ means end of file with no end of line
+ # and 89 is the current command counter. But we have complications e.g.,
+ # the following jdb output can appear:
+ #
+ # 2) a[89] = 10
+ #
+ # The above form is an array assignment and not a prompt.
+ #
+ # 3) ^main[89] main[89] ...
+ #
+ # This occurs if the next cmd is one that causes no jdb output, e.g.,
+ # 'trace methods'.
+ #
+ # 4) ^main[89] [main[89]] .... > @
+ #
+ # jdb prints a > as a prompt after something like a cont.
+ # Thus, even though the above is the last 'line' in the file, it
+ # isn't the next prompt we are waiting for after the cont completes.
+ # HOWEVER, sometimes we see this for a cont command:
+ #
+ # ^main[89] $
+ # <lines output for hitting a bkpt>
+ #
+ # 5) ^main[89] > @
+ #
+ # i.e., the > prompt comes out AFTER the prompt we we need to wait for.
+ */
+ public List<String> waitForMsg(String pattern, boolean allowSimplePrompt, int lines, boolean allowExit) {
+ long startTime = System.currentTimeMillis();
+ while (System.currentTimeMillis() - startTime < timeout) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ synchronized (outputHandler) {
+ if (!outputHandler.updated()) {
+ try {
+ outputHandler.wait(sleepTime);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ } else {
+ // if something appeared in the jdb output, reset the timeout
+ startTime = System.currentTimeMillis();
+ }
+ }
+ List<String> reply = outputHandler.get();
+ for (String line: reply.subList(Math.max(0, reply.size() - lines), reply.size())) {
+ if (line.matches(pattern) || (allowSimplePrompt && line.contains(SIMPLE_PROMPT))) {
+ logJdb(reply);
+ return outputHandler.reset();
+ }
+ }
+ if (terminated()) {
+ logJdb(outputHandler.get());
+ if (!allowExit) {
+ throw new RuntimeException("waitForMsg timed out after " + (timeout/1000)
+ + " seconds, looking for '" + pattern + "', in " + lines + " lines");
+ }
+ return new ArrayList<>(reply);
+ }
+ }
+ // timeout
+ logJdb(outputHandler.get());
+ throw new RuntimeException("waitForMsg timed out after " + (timeout/1000)
+ + " seconds, looking for '" + pattern + "', in " + lines + " lines");
+ }
+
+ //
+ public List<String> waitForSimplePrompt() {
+ return waitForMsg(SIMPLE_PROMPT, true, 1, false);
+ }
+
+ public List<String> command(JdbCommand cmd) {
+ if (terminated()) {
+ if (cmd.allowExit) {
+ // return remaining output
+ return outputHandler.reset();
+ }
+ throw new RuntimeException("Attempt to send command '" + cmd.cmd + "' to terminated jdb");
+ }
+
+ System.out.println("> " + cmd.cmd);
+
+ inputWriter.println(cmd.cmd);
+
+ if (inputWriter.checkError()) {
+ throw new RuntimeException("Unexpected IO error while writing command '" + cmd.cmd + "' to jdb stdin stream");
+ }
+
+ return waitForMsg("[a-zA-Z0-9_-][a-zA-Z0-9_-]*\\[[1-9][0-9]*\\] [ >]*$", cmd.allowSimplePrompt, 1, cmd.allowExit);
+ }
+
+ public List<String> command(String cmd) {
+ return command(new JdbCommand(cmd));
+ }
+
+ // sends "cont" command up to maxTimes until debuggee exit
+ public void contToExit(int maxTimes) {
+ boolean exited = false;
+ JdbCommand cont = JdbCommand.cont().allowExit();
+ for (int i = 0; i < maxTimes && !terminated(); i++) {
+ String reply = command(cont).stream().collect(Collectors.joining(lineSeparator));
+ if (reply.contains(APPLICATION_EXIT)) {
+ exited = true;
+ break;
+ }
+ }
+ if (!exited && !terminated()) {
+ throw new RuntimeException("Debuggee did not exit after " + maxTimes + " <cont> commands");
+ }
+ }
+
+ // quits jdb by using "quit" command
+ public void quit() {
+ command(JdbCommand.quit());
+ }
+
+ private void log(String s) {
+ System.out.println(s);
+ }
+
+ private void logJdb(List<String> reply) {
+ reply.forEach(s -> System.out.println("[jdb] " + s));
+ }
+
+ // handler for out/err of the pdb process
+ private class OutputHandler extends OutputStream {
+ // there are 2 buffers:
+ // outStream - data from the process stdout/stderr after last get() call
+ // cachedData - data collected at get(), cleared by reset()
+
+ private final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ // if the last line in the reply had EOL, the list's last element is empty
+ private final List<String> cachedData = new ArrayList<>();
+
+ @Override
+ public synchronized void write(int b) throws IOException {
+ outStream.write((byte)(b & 0xFF));
+ notifyAll();
+ }
+ @Override
+ public synchronized void write(byte b[], int off, int len) throws IOException {
+ outStream.write(b, off, len);
+ notifyAll();
+ }
+
+ // gets output after the last {@ reset}.
+ // returned data becomes invalid after {@reset}.
+ public synchronized List<String> get() {
+ if (updated()) {
+ String[] newLines = outStream.toString().split(lineSeparator);
+ if (!cachedData.isEmpty()) {
+ // concat the last line if previous data had no EOL
+ newLines[0] = cachedData.remove(cachedData.size()-1) + newLines[0];
+ }
+ cachedData.addAll(Arrays.asList(newLines));
+ outStream.reset();
+ }
+ return Collections.unmodifiableList(cachedData);
+ }
+
+ // clears last replay (does not touch replyStream)
+ // returns list as the last get()
+ public synchronized List<String> reset() {
+ List<String> result = new ArrayList<>(cachedData);
+ cachedData.clear();
+ return result;
+ }
+
+ // tests if there are some new data after the last lastReply() call
+ public synchronized boolean updated() {
+ return outStream.size() > 0;
+ }
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jdi/lib/jdb/JdbCommand.java Tue Aug 14 11:56:32 2018 -0700
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2002, 2018, 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.
+ */
+
+package lib.jdb;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+/**
+ * Represents list of commands of <code>jdb</code> from JDK1.4:
+ *
+ * run [class [args]] -- start execution of application's main class
+ *
+ * threads [threadgroup] -- list threads
+ * thread <thread id> -- set default thread
+ * suspend [thread id(s)] -- suspend threads (default: all)
+ * resume [thread id(s)] -- resume threads (default: all)
+ * where [thread id] | all -- dump a thread's stack
+ * wherei [thread id] | all -- dump a thread's stack, with pc info
+ * up [n frames] -- move up a thread's stack
+ * down [n frames] -- move down a thread's stack
+ * kill <thread> <expr> -- kill a thread with the given exception object
+ * interrupt <thread> -- interrupt a thread
+ *
+ * print <expr> -- print value of expression
+ * dump <expr> -- print all object information
+ * eval <expr> -- evaluate expression (same as print)
+ * set <lvalue> = <expr> -- assign new value to field/variable/array element
+ * locals -- print all local variables in current stack frame
+ *
+ * classes -- list currently known classes
+ * class <class id> -- show details of named class
+ * methods <class id> -- list a class's methods
+ * fields <class id> -- list a class's fields
+ *
+ * threadgroups -- list threadgroups
+ * threadgroup <name> -- set current threadgroup
+ *
+ * stop in <class id>.<method>[(argument_type,...)]
+ * -- set a breakpoint in a method
+ * stop at <class id>:<line> -- set a breakpoint at a line
+ * clear <class id>.<method>[(argument_type,...)]
+ * -- clear a breakpoint in a method
+ * clear <class id>:<line> -- clear a breakpoint at a line
+ * clear -- list breakpoints
+ * catch <class id> -- break when specified exception thrown
+ * ignore <class id> -- cancel 'catch' for the specified exception
+ * watch [access|all] <class id>.<field name>
+ * -- watch access/modifications to a field
+ * unwatch [access|all] <class id>.<field name>
+ * -- discontinue watching access/modifications to a field
+ * trace methods [thread] -- trace method entry and exit
+ * untrace methods [thread] -- stop tracing method entry and exit
+ * step -- execute current line
+ * step up -- execute until the current method returns to its caller
+ * stepi -- execute current instruction
+ * next -- step one line (step OVER calls)
+ * cont -- continue execution from breakpoint
+ *
+ * list [line number|method] -- print source code
+ * use (or sourcepath) [source file path]
+ * -- display or change the source path
+ * exclude [class id ... | "none"]
+ * -- do not report step or method events for specified classes
+ * classpath -- print classpath info from target VM
+ *
+ * monitor <command> -- execute command each time the program stops
+ * monitor -- list monitors
+ * unmonitor <monitor#> -- delete a monitor
+ * read <filename> -- read and execute a command file
+ *
+ * lock <expr> -- print lock info for an object
+ * threadlocks [thread id] -- print lock info for a thread
+ *
+ * pop -- pop the stack through and including the current frame
+ * reenter -- same as pop, but current frame is reentered
+ * redefine <class id> <class file name>
+ * -- redefine the code for a class
+ *
+ * disablegc <expr> -- prevent garbage collection of an object
+ * enablegc <expr> -- permit garbage collection of an object
+ *
+ * !! -- repeat last command
+ * <n> <command> -- repeat command n times
+ * help (or ?) -- list commands
+ * version -- print version information
+ * exit (or quit) -- exit debugger
+ *
+ * <class id>: full class name with package qualifiers or a
+ * pattern with a leading or trailing wildcard ('*').
+ * <thread id>: thread number as reported in the 'threads' command
+ * <expr>: a Java(tm) Programming Language expression.
+ * Most common syntax is supported.
+ *
+ * Startup commands can be placed in either "jdb.ini" or ".jdbrc"
+ * in user.home or user.dir
+ */
+public class JdbCommand {
+ final String cmd;
+ boolean allowSimplePrompt = false;
+ boolean allowExit = false;
+
+ public JdbCommand(String cmd) {
+ this.cmd = cmd.endsWith(ls) ? cmd.substring(0, cmd.length() - 1) : cmd;
+ }
+
+ public JdbCommand allowSimplePrompt() {
+ allowSimplePrompt = true;
+ return this;
+ }
+
+ public JdbCommand allowExit() {
+ allowExit = true;
+ return this;
+ }
+
+
+ private static final String ls = System.getProperty("line.separator");
+
+ public static JdbCommand run(String ... params) {
+ return new JdbCommand("run " + Arrays.stream(params).collect(Collectors.joining(" ")));
+ }
+ public static JdbCommand cont() {
+ return new JdbCommand("cont");
+ }
+ public static JdbCommand dump(String what) {
+ return new JdbCommand("dump " + what);
+ }
+ public static JdbCommand quit() {
+ // the command suppose jdb terminates
+ return new JdbCommand("quit").allowExit();
+ }
+ public static JdbCommand stopAt(String targetClass, int lineNum) {
+ return new JdbCommand("stop at " + targetClass + ":" + lineNum);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jdi/lib/jdb/JdbTest.java Tue Aug 14 11:56:32 2018 -0700
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+package lib.jdb;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+public abstract class JdbTest {
+
+ public JdbTest(Jdb.LaunchOptions jdbOptions) {
+ this.jdbOptions= jdbOptions;
+ debuggeeClass = jdbOptions.debuggeeClass;
+ }
+ public JdbTest(String debuggeeClass) {
+ this(new Jdb.LaunchOptions(debuggeeClass));
+ }
+
+ private final Jdb.LaunchOptions jdbOptions;
+ protected Jdb jdb;
+ protected final String debuggeeClass; // shortland for jdbOptions.debuggeeClass
+
+ public void run() {
+ try {
+ setup();
+ runCases();
+ } finally {
+ shutdown();
+ }
+ }
+
+ protected void setup() {
+ jdb = Jdb.launchLocal(jdbOptions);
+ // wait while jdb is initialized
+ jdb.waitForSimplePrompt();
+
+ }
+
+ protected abstract void runCases();
+
+ protected void shutdown() {
+ try {
+ if (!jdb.terminated()) {
+ jdb.quit();
+ // wait some time after the command for the process termination
+ jdb.waitFor(10, TimeUnit.SECONDS);
+ }
+ } finally {
+ if (!jdb.terminated()) {
+ jdb.terminate();
+ }
+ }
+ }
+
+ protected static final String lineSeparator = System.getProperty("line.separator");
+
+
+ // Parses the specified source file for "@{id} breakpoint" tags and returns
+ // list of the line numbers containing the tag.
+ // Example:
+ // System.out.println("BP is here"); // @1 breakpoint
+ public static List<Integer> parseBreakpoints(String filePath, int id) {
+ final String pattern = "@" + id + " breakpoint";
+ int lineNum = 1;
+ List<Integer> result = new LinkedList<>();
+ try {
+ for (String line: Files.readAllLines(Paths.get(filePath))) {
+ if (line.contains(pattern)) {
+ result.add(lineNum);
+ }
+ lineNum++;
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException("failed to parse " + filePath, ex);
+ }
+ return result;
+ }
+
+ // sets breakpoints to the lines parsed by {@code parseBreakpoints}
+ // returns number of the breakpoints set.
+ public static int setBreakpoints(Jdb jdb, String debuggeeClass, String sourcePath, int id) {
+ List<Integer> bps = parseBreakpoints(sourcePath, id);
+ for (int bp : bps) {
+ // usually we set breakpoints before the debuggee is run, so we allow simple prompt
+ String reply = jdb.command(JdbCommand.stopAt(debuggeeClass, bp).allowSimplePrompt()).stream()
+ .collect(Collectors.joining("\n"));
+ if (reply.contains("Unable to set")) {
+ throw new RuntimeException("jdb failed to set breakpoint at " + debuggeeClass + ":" + bp);
+ }
+
+ }
+ return bps.size();
+ }
+
+ protected int setBreakpoints(String debuggeeSourcePath, int id) {
+ return setBreakpoints(jdb, debuggeeClass, debuggeeSourcePath, id);
+ }
+
+}