8271356: Modify jdb to treat an empty command as a repeat of the previous command
Reviewed-by: cjplummer, iklam
This commit is contained in:
parent
cef9db9a69
commit
fe6a202087
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2021, 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
|
||||
@ -45,6 +45,10 @@ import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
class Commands {
|
||||
/**
|
||||
* Number of lines to show before the target line during {@code list}.
|
||||
*/
|
||||
protected static final int LIST_LINE_LOOKBEHIND = 4;
|
||||
|
||||
abstract class AsyncExecution {
|
||||
abstract void action();
|
||||
@ -1472,29 +1476,33 @@ class Commands {
|
||||
}
|
||||
}
|
||||
|
||||
void commandList(StringTokenizer t) {
|
||||
/**
|
||||
* @param lineHint source line number to target by default, or {@code null} to use the execution point
|
||||
* @return line hint to be used in a subsequent {@code list} command, if any
|
||||
*/
|
||||
Integer commandList(StringTokenizer t, Integer lineHint) {
|
||||
StackFrame frame = null;
|
||||
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
|
||||
if (threadInfo == null) {
|
||||
MessageOutput.println("No thread specified.");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
frame = threadInfo.getCurrentFrame();
|
||||
} catch (IncompatibleThreadStateException e) {
|
||||
MessageOutput.println("Current thread isnt suspended.");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (frame == null) {
|
||||
MessageOutput.println("No frames on the current call stack");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
Location loc = frame.location();
|
||||
if (loc.method().isNative()) {
|
||||
MessageOutput.println("Current method is native");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
String sourceFileName = null;
|
||||
@ -1502,9 +1510,12 @@ class Commands {
|
||||
sourceFileName = loc.sourceName();
|
||||
|
||||
ReferenceType refType = loc.declaringType();
|
||||
int lineno = loc.lineNumber();
|
||||
|
||||
if (t.hasMoreTokens()) {
|
||||
int lineno;
|
||||
var useDefault = !t.hasMoreTokens();
|
||||
if (useDefault) {
|
||||
lineno = lineHint == null ? loc.lineNumber() : lineHint;
|
||||
} else {
|
||||
String id = t.nextToken();
|
||||
|
||||
// See if token is a line number.
|
||||
@ -1515,35 +1526,48 @@ class Commands {
|
||||
lineno = n.intValue();
|
||||
} catch (java.text.ParseException jtpe) {
|
||||
// It isn't -- see if it's a method name.
|
||||
List<Method> meths = refType.methodsByName(id);
|
||||
if (meths == null || meths.size() == 0) {
|
||||
MessageOutput.println("is not a valid line number or method name for",
|
||||
new Object [] {id, refType.name()});
|
||||
return;
|
||||
} else if (meths.size() > 1) {
|
||||
MessageOutput.println("is an ambiguous method name in",
|
||||
new Object [] {id, refType.name()});
|
||||
return;
|
||||
}
|
||||
loc = meths.get(0).location();
|
||||
lineno = loc.lineNumber();
|
||||
List<Method> meths = refType.methodsByName(id);
|
||||
if (meths == null || meths.size() == 0) {
|
||||
MessageOutput.println("is not a valid line number or method name for",
|
||||
new Object [] {id, refType.name()});
|
||||
return null;
|
||||
} else if (meths.size() > 1) {
|
||||
MessageOutput.println("is an ambiguous method name in",
|
||||
new Object [] {id, refType.name()});
|
||||
return null;
|
||||
}
|
||||
loc = meths.get(0).location();
|
||||
lineno = loc.lineNumber();
|
||||
}
|
||||
}
|
||||
int startLine = Math.max(lineno - 4, 1);
|
||||
int endLine = startLine + 9;
|
||||
int startLine = Math.max(lineno - LIST_LINE_LOOKBEHIND, 1);
|
||||
int endLine = startLine + 10;
|
||||
if (lineno < 0) {
|
||||
MessageOutput.println("Line number information not available for");
|
||||
} else if (Env.sourceLine(loc, lineno) == null) {
|
||||
MessageOutput.println("is an invalid line number for",
|
||||
new Object [] {Integer.valueOf(lineno),
|
||||
refType.name()});
|
||||
} else if (useDefault && Env.sourceLine(loc, startLine) == null) {
|
||||
/*
|
||||
* If we're out of range with a default line number then we've hit EOF on auto-advance. Stay at this
|
||||
* position until a different source location is requested, as in GDB.
|
||||
*/
|
||||
MessageOutput.println("EOF");
|
||||
return lineno;
|
||||
} else if (!useDefault && Env.sourceLine(loc, lineno) == null) {
|
||||
MessageOutput.println(
|
||||
"is an invalid line number for",
|
||||
new Object[] {
|
||||
Integer.valueOf(lineno),
|
||||
refType.name()
|
||||
}
|
||||
);
|
||||
return null;
|
||||
} else {
|
||||
for (int i = startLine; i <= endLine; i++) {
|
||||
for (int i = startLine; i < endLine; i++) {
|
||||
String sourceLine = Env.sourceLine(loc, i);
|
||||
if (sourceLine == null) {
|
||||
break;
|
||||
// Next listing will start just out of range, triggering an EOF message.
|
||||
return i + LIST_LINE_LOOKBEHIND;
|
||||
}
|
||||
if (i == lineno) {
|
||||
if (i == loc.lineNumber()) {
|
||||
MessageOutput.println("source line number current line and line",
|
||||
new Object [] {Integer.valueOf(i),
|
||||
sourceLine});
|
||||
@ -1553,6 +1577,7 @@ class Commands {
|
||||
sourceLine});
|
||||
}
|
||||
}
|
||||
return endLine + LIST_LINE_LOOKBEHIND; // start next listing with `endLine'
|
||||
}
|
||||
} catch (AbsentInformationException e) {
|
||||
MessageOutput.println("No source information available for:", loc.toString());
|
||||
@ -1561,6 +1586,7 @@ class Commands {
|
||||
} catch(IOException exc) {
|
||||
MessageOutput.println("I/O exception occurred:", exc.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void commandLines(StringTokenizer t) { // Undocumented command: useful for testing
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2021, 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
|
||||
@ -44,6 +44,21 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.io.*;
|
||||
|
||||
public class TTY implements EventNotifier {
|
||||
/**
|
||||
* Commands that are repeatable on empty input.
|
||||
*/
|
||||
protected static final Set<String> REPEATABLE = Set.of(
|
||||
"up", "down", "step", "stepi", "next", "cont", "list", "pop", "reenter"
|
||||
);
|
||||
|
||||
/**
|
||||
* Commands that reset the default source line to be displayed by {@code list}.
|
||||
*/
|
||||
protected static final Set<String> LIST_RESET = Set.of(
|
||||
"run", "suspend", "resume", "up", "down", "kill", "interrupt", "threadgroup", "step", "stepi", "next", "cont",
|
||||
"pop", "reenter"
|
||||
);
|
||||
|
||||
EventHandler handler = null;
|
||||
|
||||
/**
|
||||
@ -59,6 +74,16 @@ public class TTY implements EventNotifier {
|
||||
|
||||
private volatile boolean shuttingDown = false;
|
||||
|
||||
/**
|
||||
* The number of the next source line to target for {@code list}, if any.
|
||||
*/
|
||||
protected Integer nextListTarget = null;
|
||||
|
||||
/**
|
||||
* Whether to repeat when the user enters an empty command.
|
||||
*/
|
||||
protected boolean repeat = false;
|
||||
|
||||
public void setShuttingDown(boolean s) {
|
||||
shuttingDown = s;
|
||||
}
|
||||
@ -335,6 +360,7 @@ public class TTY implements EventNotifier {
|
||||
{"read", "y", "y"},
|
||||
{"redefine", "n", "n"},
|
||||
{"reenter", "n", "n"},
|
||||
{"repeat", "y", "y"},
|
||||
{"resume", "n", "n"},
|
||||
{"run", "y", "n"},
|
||||
{"save", "n", "n"},
|
||||
@ -408,12 +434,15 @@ public class TTY implements EventNotifier {
|
||||
};
|
||||
|
||||
|
||||
void executeCommand(StringTokenizer t) {
|
||||
/**
|
||||
* @return the name (first token) of the command processed
|
||||
*/
|
||||
String executeCommand(StringTokenizer t) {
|
||||
String cmd = t.nextToken().toLowerCase();
|
||||
|
||||
// Normally, prompt for the next command after this one is done
|
||||
boolean showPrompt = true;
|
||||
|
||||
|
||||
/*
|
||||
* Anything starting with # is discarded as a no-op or 'comment'.
|
||||
*/
|
||||
@ -426,8 +455,8 @@ public class TTY implements EventNotifier {
|
||||
try {
|
||||
int repeat = Integer.parseInt(cmd);
|
||||
String subcom = t.nextToken("");
|
||||
while (repeat-- > 0) {
|
||||
executeCommand(new StringTokenizer(subcom));
|
||||
for (int r = 0; r < repeat; r += 1) {
|
||||
cmd = executeCommand(new StringTokenizer(subcom));
|
||||
showPrompt = false; // Bypass the printPrompt() below.
|
||||
}
|
||||
} catch (NumberFormatException exc) {
|
||||
@ -435,6 +464,7 @@ public class TTY implements EventNotifier {
|
||||
}
|
||||
} else {
|
||||
int commandNumber = isCommand(cmd);
|
||||
|
||||
/*
|
||||
* Check for an unknown command
|
||||
*/
|
||||
@ -448,7 +478,6 @@ public class TTY implements EventNotifier {
|
||||
MessageOutput.println("Command is not supported on a read-only VM connection",
|
||||
cmd);
|
||||
} else {
|
||||
|
||||
Commands evaluator = new Commands();
|
||||
try {
|
||||
if (cmd.equals("print")) {
|
||||
@ -550,7 +579,7 @@ public class TTY implements EventNotifier {
|
||||
} else if (cmd.equals("unwatch")) {
|
||||
evaluator.commandUnwatch(t);
|
||||
} else if (cmd.equals("list")) {
|
||||
evaluator.commandList(t);
|
||||
nextListTarget = evaluator.commandList(t, repeat ? nextListTarget : null);
|
||||
} else if (cmd.equals("lines")) { // Undocumented command: useful for testing.
|
||||
evaluator.commandLines(t);
|
||||
} else if (cmd.equals("classpath")) {
|
||||
@ -596,6 +625,8 @@ public class TTY implements EventNotifier {
|
||||
} else if (cmd.equals("version")) {
|
||||
evaluator.commandVersion(progname,
|
||||
Bootstrap.virtualMachineManager());
|
||||
} else if (cmd.equals("repeat")) {
|
||||
doRepeat(t);
|
||||
} else if (cmd.equals("quit") || cmd.equals("exit")) {
|
||||
if (handler != null) {
|
||||
handler.shutdown();
|
||||
@ -620,6 +651,12 @@ public class TTY implements EventNotifier {
|
||||
if (showPrompt) {
|
||||
MessageOutput.printPrompt();
|
||||
}
|
||||
|
||||
if (LIST_RESET.contains(cmd)) {
|
||||
nextListTarget = null;
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -661,7 +698,6 @@ public class TTY implements EventNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void readCommand(StringTokenizer t) {
|
||||
if (t.hasMoreTokens()) {
|
||||
String cmdfname = t.nextToken();
|
||||
@ -673,6 +709,19 @@ public class TTY implements EventNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
protected void doRepeat(StringTokenizer t) {
|
||||
if (t.hasMoreTokens()) {
|
||||
var choice = t.nextToken().toLowerCase();
|
||||
if ((choice.equals("on") || choice.equals("off")) && !t.hasMoreTokens()) {
|
||||
repeat = choice.equals("on");
|
||||
} else {
|
||||
MessageOutput.println("repeat usage");
|
||||
}
|
||||
} else {
|
||||
MessageOutput.println(repeat ? "repeat is on" : "repeat is off");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and execute a command file. Return true if the file was read
|
||||
* else false;
|
||||
@ -749,8 +798,6 @@ public class TTY implements EventNotifier {
|
||||
BufferedReader in =
|
||||
new BufferedReader(new InputStreamReader(System.in));
|
||||
|
||||
String lastLine = null;
|
||||
|
||||
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
|
||||
|
||||
/*
|
||||
@ -788,6 +835,9 @@ public class TTY implements EventNotifier {
|
||||
|
||||
// Process interactive commands.
|
||||
MessageOutput.printPrompt();
|
||||
|
||||
String lastLine = null;
|
||||
String lastCommandName = null;
|
||||
while (true) {
|
||||
String ln = in.readLine();
|
||||
if (ln == null) {
|
||||
@ -809,7 +859,11 @@ public class TTY implements EventNotifier {
|
||||
StringTokenizer t = new StringTokenizer(ln);
|
||||
if (t.hasMoreTokens()) {
|
||||
lastLine = ln;
|
||||
executeCommand(t);
|
||||
lastCommandName = executeCommand(t);
|
||||
} else if (repeat && lastLine != null && REPEATABLE.contains(lastCommandName)) {
|
||||
// We want list auto-advance even if the user started with a listing target.
|
||||
String newCommand = lastCommandName.equals("list") && nextListTarget != null ? "list" : lastLine;
|
||||
executeCommand(new StringTokenizer(newCommand));
|
||||
} else {
|
||||
MessageOutput.printPrompt();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2021, 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
|
||||
@ -110,6 +110,7 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
{"dbgtrace command value must be an integer:", "dbgtrace command value must be an integer: {0}"},
|
||||
{"Deferring.", "Deferring {0}.\nIt will be set after the class is loaded."},
|
||||
{"End of stack.", "End of stack."},
|
||||
{"EOF", "EOF"},
|
||||
{"Error popping frame", "Error popping frame - {0}"},
|
||||
{"Error reading file", "Error reading ''{0}'' - {1}"},
|
||||
{"Error redefining class to file", "Error redefining {0} to {1} - {2}"},
|
||||
@ -260,6 +261,9 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
" <class_id>.<method>[(argument_type,...)]"
|
||||
},
|
||||
{"Removed:", "Removed: {0}"},
|
||||
{"repeat is on", "Repeat is on"},
|
||||
{"repeat is off", "Repeat is off"},
|
||||
{"repeat usage", "Usage: repeat <on|off>"},
|
||||
{"Requested stack frame is no longer active:", "Requested stack frame is no longer active: {0,number,integer}"},
|
||||
{"run <args> command is valid only with launched VMs", "'run <args>' command is valid only with launched VMs"},
|
||||
{"run", "run {0}"},
|
||||
@ -436,6 +440,8 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
"\n" +
|
||||
"!! -- repeat last command\n" +
|
||||
"<n> <command> -- repeat command n times\n" +
|
||||
"repeat -- show whether GDB-style empty command repetition is enabled\n" +
|
||||
"repeat <on|off> -- enable/disable GDB-style repetition\n" +
|
||||
"# <command> -- discard (no-op)\n" +
|
||||
"help (or ?) -- list commands\n" +
|
||||
"dbgtrace [flag] -- same as dbgtrace command line option\n" +
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2021, 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
|
||||
@ -110,6 +110,7 @@ public class TTYResources_ja extends java.util.ListResourceBundle {
|
||||
{"dbgtrace command value must be an integer:", "dbgtrace\u30B3\u30DE\u30F3\u30C9\u5024\u306F\u6574\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059: {0}"},
|
||||
{"Deferring.", "\u9045\u5EF6\u3057\u305F{0}\u3002\n\u30AF\u30E9\u30B9\u304C\u30ED\u30FC\u30C9\u3055\u308C\u305F\u5F8C\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002"},
|
||||
{"End of stack.", "\u30B9\u30BF\u30C3\u30AF\u306E\u7D42\u308F\u308A\u3002"},
|
||||
{"EOF", "EOF"},
|
||||
{"Error popping frame", "\u30D5\u30EC\u30FC\u30E0\u306E\u30DD\u30C3\u30D7\u4E2D\u306E\u30A8\u30E9\u30FC - {0}"},
|
||||
{"Error reading file", "''{0}''\u306E\u8AAD\u53D6\u308A\u30A8\u30E9\u30FC - {1}"},
|
||||
{"Error redefining class to file", "{0}\u3092{1}\u306B\u518D\u5B9A\u7FA9\u4E2D\u306E\u30A8\u30E9\u30FC - {2}"},
|
||||
@ -252,6 +253,9 @@ public class TTYResources_ja extends java.util.ListResourceBundle {
|
||||
"\u4F7F\u7528\u65B9\u6CD5: stop [go|thread] [<thread_id>] <at|in> <location>\n \"go\"\u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u308B\u5834\u5408\u306F\u3001\u505C\u6B62\u5F8C\u3059\u3050\u306B\u518D\u958B\u3057\u307E\u3059\n \"thread\"\u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u308B\u5834\u5408\u306F\u3001\u505C\u6B62\u3057\u305F\u30B9\u30EC\u30C3\u30C9\u306E\u307F\u4E2D\u65AD\u3057\u307E\u3059\n \"go\"\u3082\"thread\"\u3082\u6307\u5B9A\u3055\u308C\u3066\u3044\u306A\u3044\u5834\u5408\u306F\u3001\u3059\u3079\u3066\u306E\u30B9\u30EC\u30C3\u30C9\u3092\u4E2D\u65AD\u3057\u307E\u3059\n \u6574\u6570\u306E<thread_id>\u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u308B\u5834\u5408\u306F\u3001\u6307\u5B9A\u3055\u308C\u305F\u30B9\u30EC\u30C3\u30C9\u3067\u306E\u307F\u505C\u6B62\u3057\u307E\u3059\n \"at\"\u3068\"in\"\u306F\u540C\u3058\u610F\u5473\u3092\u6301\u3061\u307E\u3059\n <location>\u306F\u884C\u756A\u53F7\u307E\u305F\u306F\u30E1\u30BD\u30C3\u30C9\u306B\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059:\n <class_id>:<line_number>\n <class_id>.<method>[(argument_type,...)]"
|
||||
},
|
||||
{"Removed:", "{0}\u306F\u524A\u9664\u3055\u308C\u307E\u3057\u305F"},
|
||||
{"repeat is on", "Repeat is on"},
|
||||
{"repeat is off", "Repeat is off"},
|
||||
{"repeat usage", "Usage: repeat <on|off>"},
|
||||
{"Requested stack frame is no longer active:", "\u30EA\u30AF\u30A8\u30B9\u30C8\u3055\u308C\u305F\u30B9\u30BF\u30C3\u30AF\u30FB\u30D5\u30EC\u30FC\u30E0\u306F\u73FE\u5728\u30A2\u30AF\u30C6\u30A3\u30D6\u3067\u306F\u3042\u308A\u307E\u305B\u3093: {0,number,integer}"},
|
||||
{"run <args> command is valid only with launched VMs", "'run <args>'\u30B3\u30DE\u30F3\u30C9\u306F\u8D77\u52D5\u6E08\u306EVM\u3067\u306E\u307F\u6709\u52B9\u3067\u3059"},
|
||||
{"run", "{0}\u306E\u5B9F\u884C"},
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2021, 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
|
||||
@ -110,6 +110,7 @@ public class TTYResources_zh_CN extends java.util.ListResourceBundle {
|
||||
{"dbgtrace command value must be an integer:", "dbgtrace \u547D\u4EE4\u503C\u5FC5\u987B\u4E3A\u6574\u6570\uFF1A{0}"},
|
||||
{"Deferring.", "\u6B63\u5728\u5EF6\u8FDF{0}\u3002\n\u5C06\u5728\u52A0\u8F7D\u7C7B\u540E\u8BBE\u7F6E\u3002"},
|
||||
{"End of stack.", "\u5806\u6808\u7ED3\u675F\u3002"},
|
||||
{"EOF", "EOF"},
|
||||
{"Error popping frame", "\u4F7F\u5E27\u51FA\u6808\u65F6\u51FA\u9519 - {0}"},
|
||||
{"Error reading file", "\u8BFB\u53D6 ''{0}'' \u65F6\u51FA\u9519 - {1}"},
|
||||
{"Error redefining class to file", "\u5C06{0}\u91CD\u65B0\u5B9A\u4E49\u4E3A{1}\u65F6\u51FA\u9519 - {2}"},
|
||||
@ -252,6 +253,9 @@ public class TTYResources_zh_CN extends java.util.ListResourceBundle {
|
||||
"\u7528\u6CD5\uFF1Astop [go|thread] [<thread_id>] <at|in> <location>\n \u5982\u679C\u6307\u5B9A \"go\"\uFF0C\u5219\u5728\u505C\u6B62\u540E\u7ACB\u5373\u6062\u590D\n \u5982\u679C\u6307\u5B9A \"thread\"\uFF0C\u5219\u4EC5\u6302\u8D77\u5728\u5176\u4E2D\u505C\u6B62\u7684\u7EBF\u7A0B\n \u5982\u679C\u65E2\u672A\u6307\u5B9A \"go\" \u4E5F\u672A\u6307\u5B9A \"thread\"\uFF0C\u5219\u6302\u8D77\u6240\u6709\u7EBF\u7A0B\n \u5982\u679C\u6307\u5B9A\u4EE5\u6574\u6570\u8868\u793A\u7684 <thread_id>\uFF0C\u5219\u4EC5\u5728\u6307\u5B9A\u7684\u7EBF\u7A0B\u4E2D\u505C\u6B62\n \"at\" \u548C \"in\" \u7684\u542B\u4E49\u76F8\u540C\n <location> \u53EF\u4EE5\u662F\u884C\u53F7\u6216\u65B9\u6CD5\uFF1A\n <class_id>:<line_number>\n <class_id>.<method>[(argument_type,...)]"
|
||||
},
|
||||
{"Removed:", "\u5DF2\u5220\u9664: {0}"},
|
||||
{"repeat is on", "Repeat is on"},
|
||||
{"repeat is off", "Repeat is off"},
|
||||
{"repeat usage", "Usage: repeat <on|off>"},
|
||||
{"Requested stack frame is no longer active:", "\u8BF7\u6C42\u7684\u5806\u6808\u5E27\u4E0D\u518D\u6709\u6548: {0,number,integer}"},
|
||||
{"run <args> command is valid only with launched VMs", "'run <args>' \u547D\u4EE4\u4EC5\u5BF9\u542F\u52A8\u7684 VM \u6709\u6548"},
|
||||
{"run", "\u8FD0\u884C{0}"},
|
||||
|
172
test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java
Normal file
172
test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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
|
||||
*
|
||||
* @summary
|
||||
* VM Testbase keywords: [jpda, jdb]
|
||||
* VM Testbase readme:
|
||||
* DECSRIPTION
|
||||
* This tests the GDB-style auto-advance feature of `list', which is enabled and disabled through the `repeat' command.
|
||||
* The test consists of two program:
|
||||
* list003.java - launches jdb and debuggee and executes test cases
|
||||
* list003a.java - the debugged application
|
||||
* COMMENTS
|
||||
*
|
||||
* @library /vmTestbase
|
||||
* /test/lib
|
||||
* @build nsk.jdb.list.list003.list003a
|
||||
* @run main/othervm
|
||||
* nsk.jdb.list.list003.list003
|
||||
* -arch=${os.family}-${os.simpleArch}
|
||||
* -waittime=5
|
||||
* -debugee.vmkind=java
|
||||
* -transport.address=dynamic
|
||||
* -jdb=${test.jdk}/bin/jdb
|
||||
* -jdb.option="-J-Duser.language=en -J-Duser.country=US"
|
||||
* -java.options="${test.vm.opts} ${test.java.opts}"
|
||||
* -workdir=.
|
||||
* -debugee.vmkeys="${test.vm.opts} ${test.java.opts}"
|
||||
*/
|
||||
|
||||
package nsk.jdb.list.list003;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import nsk.share.jdb.JdbTest;
|
||||
import nsk.share.jdb.JdbCommand;
|
||||
|
||||
|
||||
public class list003 extends JdbTest {
|
||||
static final String PACKAGE_NAME = "nsk.jdb.list.list003";
|
||||
static final String TEST_CLASS = PACKAGE_NAME + ".list003";
|
||||
static final String DEBUGGEE_CLASS = TEST_CLASS + "a";
|
||||
static final String FIRST_BREAK = DEBUGGEE_CLASS + ".main";
|
||||
|
||||
/**
|
||||
* Represents a line output by the {@code list} command.
|
||||
*/
|
||||
protected static record ListLine(int number, boolean active) {
|
||||
public static ListLine parse(String line) {
|
||||
String[] tokens = line.split("\\s+");
|
||||
return new ListLine(
|
||||
Integer.parseInt(tokens[0]),
|
||||
tokens.length >= 2 && tokens[1].equals("=>")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean isPrompt(String line) {
|
||||
return line.trim().equals("main[1]");
|
||||
}
|
||||
|
||||
protected static List<ListLine> parseListOutput(String[] lines) {
|
||||
List<String> lineList = new ArrayList<>(Arrays.asList(lines));
|
||||
if (!isPrompt(lineList.remove(lineList.size() - 1))) {
|
||||
throw new AssertionError("Expected trailing prompt");
|
||||
} else if (lineList.size() == 1 && lineList.get(0).equals("EOF")) {
|
||||
return new ArrayList<>();
|
||||
} else {
|
||||
return lineList.stream().map(ListLine::parse).collect(toList());
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.exit(run(args, System.out) + JCK_STATUS_BASE);
|
||||
}
|
||||
|
||||
public static int run(String[] args, PrintStream out) {
|
||||
debuggeeClass = DEBUGGEE_CLASS;
|
||||
firstBreak = FIRST_BREAK;
|
||||
return new list003().runTest(args, out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runCases() {
|
||||
try {
|
||||
runCasesNoCleanup();
|
||||
} finally {
|
||||
jdb.contToExit(1);
|
||||
}
|
||||
}
|
||||
|
||||
protected void runCasesNoCleanup() {
|
||||
if (jdb.receiveReplyFor(JdbCommand.repeat + "on").length != 1) {
|
||||
throw new AssertionError("Missing or unexpected output");
|
||||
}
|
||||
|
||||
List<ListLine> autoList = parseListOutput(jdb.receiveReplyFor(JdbCommand.list));
|
||||
int lineNo = autoList.stream().filter(ListLine::active).findFirst().get().number();
|
||||
List<ListLine> manualList = parseListOutput(jdb.receiveReplyFor(JdbCommand.list + (lineNo - 1)));
|
||||
if (manualList.stream().filter(ListLine::active).findFirst().get().number() != lineNo) {
|
||||
throw new AssertionError("Manual listing didn't mark the active source line");
|
||||
}
|
||||
|
||||
// Verify that we can correctly list by auto-advance all the way to EOF
|
||||
List<ListLine> prevList = manualList;
|
||||
int reps;
|
||||
for (reps = 0; !prevList.isEmpty(); reps += 1) {
|
||||
// Exercise both explicit `list' and auto-repeat
|
||||
var command = reps % 2 == 0 ? JdbCommand.list : "";
|
||||
|
||||
List<ListLine> currList = parseListOutput(jdb.receiveReplyFor(command));
|
||||
if (currList.equals(prevList)) {
|
||||
// This guards against infinite looping
|
||||
throw new AssertionError("Consecutive listings were identical");
|
||||
}
|
||||
int prevEnd = prevList.get(prevList.size() - 1).number();
|
||||
if (!currList.isEmpty() && currList.get(0).number() != prevEnd + 1) {
|
||||
throw new AssertionError("Consecutive listings weren't for consecutive source chunks");
|
||||
}
|
||||
prevList = currList;
|
||||
}
|
||||
if (reps < 2) {
|
||||
throw new AssertionError("Didn't get enough consecutive list reps");
|
||||
}
|
||||
|
||||
String[] lines = jdb.receiveReplyFor(JdbCommand.up);
|
||||
if (!lines[0].equals("End of stack.") || !isPrompt(lines[1])) {
|
||||
throw new AssertionError("Unexpected output from `up'");
|
||||
}
|
||||
List<ListLine> resetList = parseListOutput(jdb.receiveReplyFor(JdbCommand.list));
|
||||
if (!resetList.stream().anyMatch(ListLine::active)) {
|
||||
throw new AssertionError("List target didn't reset to active line");
|
||||
}
|
||||
|
||||
List<ListLine> listing = parseListOutput(jdb.receiveReplyFor(JdbCommand.list + "1"));
|
||||
if (!listing.stream().anyMatch(l -> l.number() == 1)) {
|
||||
throw new AssertionError("Manual listing displayed the wrong lines");
|
||||
}
|
||||
|
||||
List<ListLine> targetedList = parseListOutput(jdb.receiveReplyFor(JdbCommand.list + "1"));
|
||||
autoList = parseListOutput(jdb.receiveReplyFor(JdbCommand.list));
|
||||
if (autoList.get(0).number() != targetedList.get(targetedList.size() - 1).number() + 1) {
|
||||
throw new AssertionError("Auto-advance didn't work after targeted list");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 nsk.jdb.list.list003;
|
||||
|
||||
import nsk.share.Log;
|
||||
import nsk.share.jdb.JdbArgumentHandler;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
|
||||
/* This is debuggee application */
|
||||
public class list003a {
|
||||
static list003a _list003a = new list003a();
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.exit(list003.JCK_STATUS_BASE + _list003a.runIt(args, System.out));
|
||||
}
|
||||
|
||||
public int runIt(String[] args, PrintStream out) {
|
||||
JdbArgumentHandler argumentHandler = new JdbArgumentHandler(args);
|
||||
Log log = new Log(out, argumentHandler);
|
||||
|
||||
log.display("Debuggee PASSED");
|
||||
return list003.PASSED;
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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
|
||||
*
|
||||
* @summary
|
||||
* VM Testbase keywords: [jpda, jdb]
|
||||
* VM Testbase readme:
|
||||
* DECSRIPTION
|
||||
* Tests the operation of the `repeat' commands, which print and change the status of GDB-style command repetition and
|
||||
* list auto-advance. The particular behavior of `list' when repitition is on is tested in the `list' tests.
|
||||
* The test consists of two program:
|
||||
* repeat001.java - launches jdb and debuggee and executes test cases
|
||||
* repeat001a.java - the debugged application
|
||||
* COMMENTS
|
||||
*
|
||||
* @library /vmTestbase
|
||||
* /test/lib
|
||||
* @build nsk.jdb.repeat.repeat001.repeat001a
|
||||
* @run main/othervm
|
||||
* nsk.jdb.repeat.repeat001.repeat001
|
||||
* -arch=${os.family}-${os.simpleArch}
|
||||
* -waittime=5
|
||||
* -debugee.vmkind=java
|
||||
* -transport.address=dynamic
|
||||
* -jdb=${test.jdk}/bin/jdb
|
||||
* -jdb.option="-J-Duser.language=en -J-Duser.country=US"
|
||||
* -java.options="${test.vm.opts} ${test.java.opts}"
|
||||
* -workdir=.
|
||||
* -debugee.vmkeys="${test.vm.opts} ${test.java.opts}"
|
||||
*/
|
||||
|
||||
package nsk.jdb.repeat.repeat001;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import nsk.share.jdb.JdbTest;
|
||||
import nsk.share.jdb.JdbCommand;
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
|
||||
public class repeat001 extends JdbTest {
|
||||
static final String PACKAGE_NAME = "nsk.jdb.repeat.repeat001";
|
||||
static final String TEST_CLASS = PACKAGE_NAME + ".repeat001";
|
||||
static final String DEBUGGEE_CLASS = TEST_CLASS + "a";
|
||||
static final String FIRST_BREAK = DEBUGGEE_CLASS + ".main";
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.exit(run(args, System.out) + JCK_STATUS_BASE);
|
||||
}
|
||||
|
||||
public static int run(String[] args, PrintStream out) {
|
||||
debuggeeClass = DEBUGGEE_CLASS;
|
||||
firstBreak = FIRST_BREAK;
|
||||
return new repeat001().runTest(args, out);
|
||||
}
|
||||
|
||||
protected static boolean isPrompt(String line) {
|
||||
return line.trim().equals("main[1]");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runCases() {
|
||||
try {
|
||||
runCasesNoCleanup();
|
||||
} finally {
|
||||
jdb.contToExit(1);
|
||||
}
|
||||
}
|
||||
|
||||
protected void runCasesNoCleanup() {
|
||||
// Verify that repeat is off initially
|
||||
String[] reply = jdb.receiveReplyFor(JdbCommand.repeat);
|
||||
if (reply.length != 2 || !isPrompt(reply[1])) {
|
||||
throw new AssertionError("Unexpected output");
|
||||
}
|
||||
if (!reply[0].equals("Repeat is off")) {
|
||||
throw new AssertionError("Incorrect initial repeat setting");
|
||||
}
|
||||
|
||||
// Verify that list auto-advance is disabled
|
||||
String[] firstList = jdb.receiveReplyFor(JdbCommand.list);
|
||||
String[] secondList = jdb.receiveReplyFor(JdbCommand.list);
|
||||
if (!Arrays.equals(firstList, secondList)) {
|
||||
throw new AssertionError("Listing inconsistent with repeat off");
|
||||
}
|
||||
|
||||
// Verify that command repetition doesn't happen when disabled
|
||||
reply = jdb.receiveReplyFor("");
|
||||
if (reply.length != 1 || !isPrompt(reply[0])) {
|
||||
throw new AssertionError("Unexpected output");
|
||||
}
|
||||
|
||||
reply = jdb.receiveReplyFor(JdbCommand.repeat + "on");
|
||||
if (reply.length != 1 || !isPrompt(reply[0])) {
|
||||
throw new AssertionError("Unexpected output");
|
||||
}
|
||||
|
||||
// Verify that repeat is reported on
|
||||
reply = jdb.receiveReplyFor(JdbCommand.repeat);
|
||||
if (reply.length != 2 || !isPrompt(reply[1])) {
|
||||
throw new AssertionError("Unexpected output");
|
||||
}
|
||||
if (!reply[0].equals("Repeat is on")) {
|
||||
throw new AssertionError("Incorrect repeat status reported");
|
||||
}
|
||||
|
||||
// Verify that non-repeatable commands still don't repeat
|
||||
if (jdb.receiveReplyFor(JdbCommand.print + "0").length != 2) {
|
||||
throw new AssertionError("Unexpected output");
|
||||
}
|
||||
if (jdb.receiveReplyFor("").length != 1) {
|
||||
throw new AssertionError("Unexpected output");
|
||||
}
|
||||
|
||||
// Verify that repeated commands are repeatable
|
||||
// (`up' just prints `End of stack.' since we're stopped in `main')
|
||||
reply = jdb.receiveReplyFor("2 2 " + JdbCommand.up);
|
||||
if (reply.length != 5 || !isPrompt(reply[4])) {
|
||||
throw new AssertionError("Unexpected output");
|
||||
}
|
||||
if (!Arrays.equals(reply, jdb.receiveReplyFor(""))) {
|
||||
throw new AssertionError("Repeated command didn't repeat correctly");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 nsk.jdb.repeat.repeat001;
|
||||
|
||||
import nsk.share.Log;
|
||||
import nsk.share.jdb.JdbArgumentHandler;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
|
||||
/* This is debuggee application */
|
||||
public class repeat001a {
|
||||
static repeat001a _repeat001a = new repeat001a();
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.exit(repeat001.JCK_STATUS_BASE + _repeat001a.runIt(args, System.out));
|
||||
}
|
||||
|
||||
public int runIt(String[] args, PrintStream out) {
|
||||
JdbArgumentHandler argumentHandler = new JdbArgumentHandler(args);
|
||||
Log log = new Log(out, argumentHandler);
|
||||
|
||||
log.display("Debuggee PASSED");
|
||||
return repeat001.PASSED;
|
||||
}
|
||||
}
|
@ -99,6 +99,8 @@ package nsk.share.jdb;
|
||||
*
|
||||
* !! -- repeat last command
|
||||
* <n> <command> -- repeat command n times
|
||||
* repeat -- show whether GDB-style empty command repetition is enabled
|
||||
* repeat <on|off> -- enable/disable GDB-style repetition
|
||||
* help (or ?) -- list commands
|
||||
* version -- print version information
|
||||
* exit (or quit) -- exit debugger
|
||||
@ -145,6 +147,7 @@ public class JdbCommand {
|
||||
public static final String read = "read ";
|
||||
public static final String redefine = "redefine ";
|
||||
public static final String reenter = "reenter" + ls;
|
||||
public static final String repeat = "repeat ";
|
||||
public static final String resume = "resume ";
|
||||
public static final String run = "run ";
|
||||
public static final String set = "set ";
|
||||
|
Loading…
x
Reference in New Issue
Block a user