Skip to content

Commit fe6a202

Browse files
jakobcornellplummercj
authored andcommittedOct 29, 2021
8271356: Modify jdb to treat an empty command as a repeat of the previous command
Reviewed-by: cjplummer, iklam
1 parent cef9db9 commit fe6a202

File tree

10 files changed

+554
-43
lines changed

10 files changed

+554
-43
lines changed
 

‎src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java

+55-29
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,10 @@
4545
import java.io.*;
4646

4747
class Commands {
48+
/**
49+
* Number of lines to show before the target line during {@code list}.
50+
*/
51+
protected static final int LIST_LINE_LOOKBEHIND = 4;
4852

4953
abstract class AsyncExecution {
5054
abstract void action();
@@ -1472,39 +1476,46 @@ void commandUntrace(StringTokenizer t) {
14721476
}
14731477
}
14741478

1475-
void commandList(StringTokenizer t) {
1479+
/**
1480+
* @param lineHint source line number to target by default, or {@code null} to use the execution point
1481+
* @return line hint to be used in a subsequent {@code list} command, if any
1482+
*/
1483+
Integer commandList(StringTokenizer t, Integer lineHint) {
14761484
StackFrame frame = null;
14771485
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
14781486
if (threadInfo == null) {
14791487
MessageOutput.println("No thread specified.");
1480-
return;
1488+
return null;
14811489
}
14821490
try {
14831491
frame = threadInfo.getCurrentFrame();
14841492
} catch (IncompatibleThreadStateException e) {
14851493
MessageOutput.println("Current thread isnt suspended.");
1486-
return;
1494+
return null;
14871495
}
14881496

14891497
if (frame == null) {
14901498
MessageOutput.println("No frames on the current call stack");
1491-
return;
1499+
return null;
14921500
}
14931501

14941502
Location loc = frame.location();
14951503
if (loc.method().isNative()) {
14961504
MessageOutput.println("Current method is native");
1497-
return;
1505+
return null;
14981506
}
14991507

15001508
String sourceFileName = null;
15011509
try {
15021510
sourceFileName = loc.sourceName();
15031511

15041512
ReferenceType refType = loc.declaringType();
1505-
int lineno = loc.lineNumber();
15061513

1507-
if (t.hasMoreTokens()) {
1514+
int lineno;
1515+
var useDefault = !t.hasMoreTokens();
1516+
if (useDefault) {
1517+
lineno = lineHint == null ? loc.lineNumber() : lineHint;
1518+
} else {
15081519
String id = t.nextToken();
15091520

15101521
// See if token is a line number.
@@ -1515,35 +1526,48 @@ void commandList(StringTokenizer t) {
15151526
lineno = n.intValue();
15161527
} catch (java.text.ParseException jtpe) {
15171528
// It isn't -- see if it's a method name.
1518-
List<Method> meths = refType.methodsByName(id);
1519-
if (meths == null || meths.size() == 0) {
1520-
MessageOutput.println("is not a valid line number or method name for",
1521-
new Object [] {id, refType.name()});
1522-
return;
1523-
} else if (meths.size() > 1) {
1524-
MessageOutput.println("is an ambiguous method name in",
1525-
new Object [] {id, refType.name()});
1526-
return;
1527-
}
1528-
loc = meths.get(0).location();
1529-
lineno = loc.lineNumber();
1529+
List<Method> meths = refType.methodsByName(id);
1530+
if (meths == null || meths.size() == 0) {
1531+
MessageOutput.println("is not a valid line number or method name for",
1532+
new Object [] {id, refType.name()});
1533+
return null;
1534+
} else if (meths.size() > 1) {
1535+
MessageOutput.println("is an ambiguous method name in",
1536+
new Object [] {id, refType.name()});
1537+
return null;
1538+
}
1539+
loc = meths.get(0).location();
1540+
lineno = loc.lineNumber();
15301541
}
15311542
}
1532-
int startLine = Math.max(lineno - 4, 1);
1533-
int endLine = startLine + 9;
1543+
int startLine = Math.max(lineno - LIST_LINE_LOOKBEHIND, 1);
1544+
int endLine = startLine + 10;
15341545
if (lineno < 0) {
15351546
MessageOutput.println("Line number information not available for");
1536-
} else if (Env.sourceLine(loc, lineno) == null) {
1537-
MessageOutput.println("is an invalid line number for",
1538-
new Object [] {Integer.valueOf(lineno),
1539-
refType.name()});
1547+
} else if (useDefault && Env.sourceLine(loc, startLine) == null) {
1548+
/*
1549+
* If we're out of range with a default line number then we've hit EOF on auto-advance. Stay at this
1550+
* position until a different source location is requested, as in GDB.
1551+
*/
1552+
MessageOutput.println("EOF");
1553+
return lineno;
1554+
} else if (!useDefault && Env.sourceLine(loc, lineno) == null) {
1555+
MessageOutput.println(
1556+
"is an invalid line number for",
1557+
new Object[] {
1558+
Integer.valueOf(lineno),
1559+
refType.name()
1560+
}
1561+
);
1562+
return null;
15401563
} else {
1541-
for (int i = startLine; i <= endLine; i++) {
1564+
for (int i = startLine; i < endLine; i++) {
15421565
String sourceLine = Env.sourceLine(loc, i);
15431566
if (sourceLine == null) {
1544-
break;
1567+
// Next listing will start just out of range, triggering an EOF message.
1568+
return i + LIST_LINE_LOOKBEHIND;
15451569
}
1546-
if (i == lineno) {
1570+
if (i == loc.lineNumber()) {
15471571
MessageOutput.println("source line number current line and line",
15481572
new Object [] {Integer.valueOf(i),
15491573
sourceLine});
@@ -1553,6 +1577,7 @@ void commandList(StringTokenizer t) {
15531577
sourceLine});
15541578
}
15551579
}
1580+
return endLine + LIST_LINE_LOOKBEHIND; // start next listing with `endLine'
15561581
}
15571582
} catch (AbsentInformationException e) {
15581583
MessageOutput.println("No source information available for:", loc.toString());
@@ -1561,6 +1586,7 @@ void commandList(StringTokenizer t) {
15611586
} catch(IOException exc) {
15621587
MessageOutput.println("I/O exception occurred:", exc.toString());
15631588
}
1589+
return null;
15641590
}
15651591

15661592
void commandLines(StringTokenizer t) { // Undocumented command: useful for testing

‎src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java

+65-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,21 @@
4444
import java.io.*;
4545

4646
public class TTY implements EventNotifier {
47+
/**
48+
* Commands that are repeatable on empty input.
49+
*/
50+
protected static final Set<String> REPEATABLE = Set.of(
51+
"up", "down", "step", "stepi", "next", "cont", "list", "pop", "reenter"
52+
);
53+
54+
/**
55+
* Commands that reset the default source line to be displayed by {@code list}.
56+
*/
57+
protected static final Set<String> LIST_RESET = Set.of(
58+
"run", "suspend", "resume", "up", "down", "kill", "interrupt", "threadgroup", "step", "stepi", "next", "cont",
59+
"pop", "reenter"
60+
);
61+
4762
EventHandler handler = null;
4863

4964
/**
@@ -59,6 +74,16 @@ public class TTY implements EventNotifier {
5974

6075
private volatile boolean shuttingDown = false;
6176

77+
/**
78+
* The number of the next source line to target for {@code list}, if any.
79+
*/
80+
protected Integer nextListTarget = null;
81+
82+
/**
83+
* Whether to repeat when the user enters an empty command.
84+
*/
85+
protected boolean repeat = false;
86+
6287
public void setShuttingDown(boolean s) {
6388
shuttingDown = s;
6489
}
@@ -335,6 +360,7 @@ void help() {
335360
{"read", "y", "y"},
336361
{"redefine", "n", "n"},
337362
{"reenter", "n", "n"},
363+
{"repeat", "y", "y"},
338364
{"resume", "n", "n"},
339365
{"run", "y", "n"},
340366
{"save", "n", "n"},
@@ -408,12 +434,15 @@ private boolean isReadOnlyCmd(int ii) {
408434
};
409435

410436

411-
void executeCommand(StringTokenizer t) {
437+
/**
438+
* @return the name (first token) of the command processed
439+
*/
440+
String executeCommand(StringTokenizer t) {
412441
String cmd = t.nextToken().toLowerCase();
442+
413443
// Normally, prompt for the next command after this one is done
414444
boolean showPrompt = true;
415445

416-
417446
/*
418447
* Anything starting with # is discarded as a no-op or 'comment'.
419448
*/
@@ -426,15 +455,16 @@ void executeCommand(StringTokenizer t) {
426455
try {
427456
int repeat = Integer.parseInt(cmd);
428457
String subcom = t.nextToken("");
429-
while (repeat-- > 0) {
430-
executeCommand(new StringTokenizer(subcom));
458+
for (int r = 0; r < repeat; r += 1) {
459+
cmd = executeCommand(new StringTokenizer(subcom));
431460
showPrompt = false; // Bypass the printPrompt() below.
432461
}
433462
} catch (NumberFormatException exc) {
434463
MessageOutput.println("Unrecognized command. Try help...", cmd);
435464
}
436465
} else {
437466
int commandNumber = isCommand(cmd);
467+
438468
/*
439469
* Check for an unknown command
440470
*/
@@ -448,7 +478,6 @@ void executeCommand(StringTokenizer t) {
448478
MessageOutput.println("Command is not supported on a read-only VM connection",
449479
cmd);
450480
} else {
451-
452481
Commands evaluator = new Commands();
453482
try {
454483
if (cmd.equals("print")) {
@@ -550,7 +579,7 @@ void executeCommand(StringTokenizer t) {
550579
} else if (cmd.equals("unwatch")) {
551580
evaluator.commandUnwatch(t);
552581
} else if (cmd.equals("list")) {
553-
evaluator.commandList(t);
582+
nextListTarget = evaluator.commandList(t, repeat ? nextListTarget : null);
554583
} else if (cmd.equals("lines")) { // Undocumented command: useful for testing.
555584
evaluator.commandLines(t);
556585
} else if (cmd.equals("classpath")) {
@@ -596,6 +625,8 @@ void executeCommand(StringTokenizer t) {
596625
} else if (cmd.equals("version")) {
597626
evaluator.commandVersion(progname,
598627
Bootstrap.virtualMachineManager());
628+
} else if (cmd.equals("repeat")) {
629+
doRepeat(t);
599630
} else if (cmd.equals("quit") || cmd.equals("exit")) {
600631
if (handler != null) {
601632
handler.shutdown();
@@ -620,6 +651,12 @@ void executeCommand(StringTokenizer t) {
620651
if (showPrompt) {
621652
MessageOutput.printPrompt();
622653
}
654+
655+
if (LIST_RESET.contains(cmd)) {
656+
nextListTarget = null;
657+
}
658+
659+
return cmd;
623660
}
624661

625662
/*
@@ -661,7 +698,6 @@ void unmonitorCommand(StringTokenizer t) {
661698
}
662699
}
663700

664-
665701
void readCommand(StringTokenizer t) {
666702
if (t.hasMoreTokens()) {
667703
String cmdfname = t.nextToken();
@@ -673,6 +709,19 @@ void readCommand(StringTokenizer t) {
673709
}
674710
}
675711

712+
protected void doRepeat(StringTokenizer t) {
713+
if (t.hasMoreTokens()) {
714+
var choice = t.nextToken().toLowerCase();
715+
if ((choice.equals("on") || choice.equals("off")) && !t.hasMoreTokens()) {
716+
repeat = choice.equals("on");
717+
} else {
718+
MessageOutput.println("repeat usage");
719+
}
720+
} else {
721+
MessageOutput.println(repeat ? "repeat is on" : "repeat is off");
722+
}
723+
}
724+
676725
/**
677726
* Read and execute a command file. Return true if the file was read
678727
* else false;
@@ -749,8 +798,6 @@ public TTY() throws Exception {
749798
BufferedReader in =
750799
new BufferedReader(new InputStreamReader(System.in));
751800

752-
String lastLine = null;
753-
754801
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
755802

756803
/*
@@ -788,6 +835,9 @@ public TTY() throws Exception {
788835

789836
// Process interactive commands.
790837
MessageOutput.printPrompt();
838+
839+
String lastLine = null;
840+
String lastCommandName = null;
791841
while (true) {
792842
String ln = in.readLine();
793843
if (ln == null) {
@@ -809,7 +859,11 @@ public TTY() throws Exception {
809859
StringTokenizer t = new StringTokenizer(ln);
810860
if (t.hasMoreTokens()) {
811861
lastLine = ln;
812-
executeCommand(t);
862+
lastCommandName = executeCommand(t);
863+
} else if (repeat && lastLine != null && REPEATABLE.contains(lastCommandName)) {
864+
// We want list auto-advance even if the user started with a listing target.
865+
String newCommand = lastCommandName.equals("list") && nextListTarget != null ? "list" : lastLine;
866+
executeCommand(new StringTokenizer(newCommand));
813867
} else {
814868
MessageOutput.printPrompt();
815869
}

‎src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -110,6 +110,7 @@ public Object[][] getContents() {
110110
{"dbgtrace command value must be an integer:", "dbgtrace command value must be an integer: {0}"},
111111
{"Deferring.", "Deferring {0}.\nIt will be set after the class is loaded."},
112112
{"End of stack.", "End of stack."},
113+
{"EOF", "EOF"},
113114
{"Error popping frame", "Error popping frame - {0}"},
114115
{"Error reading file", "Error reading ''{0}'' - {1}"},
115116
{"Error redefining class to file", "Error redefining {0} to {1} - {2}"},
@@ -260,6 +261,9 @@ public Object[][] getContents() {
260261
" <class_id>.<method>[(argument_type,...)]"
261262
},
262263
{"Removed:", "Removed: {0}"},
264+
{"repeat is on", "Repeat is on"},
265+
{"repeat is off", "Repeat is off"},
266+
{"repeat usage", "Usage: repeat <on|off>"},
263267
{"Requested stack frame is no longer active:", "Requested stack frame is no longer active: {0,number,integer}"},
264268
{"run <args> command is valid only with launched VMs", "'run <args>' command is valid only with launched VMs"},
265269
{"run", "run {0}"},
@@ -436,6 +440,8 @@ public Object[][] getContents() {
436440
"\n" +
437441
"!! -- repeat last command\n" +
438442
"<n> <command> -- repeat command n times\n" +
443+
"repeat -- show whether GDB-style empty command repetition is enabled\n" +
444+
"repeat <on|off> -- enable/disable GDB-style repetition\n" +
439445
"# <command> -- discard (no-op)\n" +
440446
"help (or ?) -- list commands\n" +
441447
"dbgtrace [flag] -- same as dbgtrace command line option\n" +

‎src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_ja.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -110,6 +110,7 @@ public Object[][] getContents() {
110110
{"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}"},
111111
{"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"},
112112
{"End of stack.", "\u30B9\u30BF\u30C3\u30AF\u306E\u7D42\u308F\u308A\u3002"},
113+
{"EOF", "EOF"},
113114
{"Error popping frame", "\u30D5\u30EC\u30FC\u30E0\u306E\u30DD\u30C3\u30D7\u4E2D\u306E\u30A8\u30E9\u30FC - {0}"},
114115
{"Error reading file", "''{0}''\u306E\u8AAD\u53D6\u308A\u30A8\u30E9\u30FC - {1}"},
115116
{"Error redefining class to file", "{0}\u3092{1}\u306B\u518D\u5B9A\u7FA9\u4E2D\u306E\u30A8\u30E9\u30FC - {2}"},
@@ -252,6 +253,9 @@ public Object[][] getContents() {
252253
"\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,...)]"
253254
},
254255
{"Removed:", "{0}\u306F\u524A\u9664\u3055\u308C\u307E\u3057\u305F"},
256+
{"repeat is on", "Repeat is on"},
257+
{"repeat is off", "Repeat is off"},
258+
{"repeat usage", "Usage: repeat <on|off>"},
255259
{"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}"},
256260
{"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"},
257261
{"run", "{0}\u306E\u5B9F\u884C"},

‎src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_zh_CN.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -110,6 +110,7 @@ public Object[][] getContents() {
110110
{"dbgtrace command value must be an integer:", "dbgtrace \u547D\u4EE4\u503C\u5FC5\u987B\u4E3A\u6574\u6570\uFF1A{0}"},
111111
{"Deferring.", "\u6B63\u5728\u5EF6\u8FDF{0}\u3002\n\u5C06\u5728\u52A0\u8F7D\u7C7B\u540E\u8BBE\u7F6E\u3002"},
112112
{"End of stack.", "\u5806\u6808\u7ED3\u675F\u3002"},
113+
{"EOF", "EOF"},
113114
{"Error popping frame", "\u4F7F\u5E27\u51FA\u6808\u65F6\u51FA\u9519 - {0}"},
114115
{"Error reading file", "\u8BFB\u53D6 ''{0}'' \u65F6\u51FA\u9519 - {1}"},
115116
{"Error redefining class to file", "\u5C06{0}\u91CD\u65B0\u5B9A\u4E49\u4E3A{1}\u65F6\u51FA\u9519 - {2}"},
@@ -252,6 +253,9 @@ public Object[][] getContents() {
252253
"\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,...)]"
253254
},
254255
{"Removed:", "\u5DF2\u5220\u9664: {0}"},
256+
{"repeat is on", "Repeat is on"},
257+
{"repeat is off", "Repeat is off"},
258+
{"repeat usage", "Usage: repeat <on|off>"},
255259
{"Requested stack frame is no longer active:", "\u8BF7\u6C42\u7684\u5806\u6808\u5E27\u4E0D\u518D\u6709\u6548: {0,number,integer}"},
256260
{"run <args> command is valid only with launched VMs", "'run <args>' \u547D\u4EE4\u4EC5\u5BF9\u542F\u52A8\u7684 VM \u6709\u6548"},
257261
{"run", "\u8FD0\u884C{0}"},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
*
27+
* @summary
28+
* VM Testbase keywords: [jpda, jdb]
29+
* VM Testbase readme:
30+
* DECSRIPTION
31+
* This tests the GDB-style auto-advance feature of `list', which is enabled and disabled through the `repeat' command.
32+
* The test consists of two program:
33+
* list003.java - launches jdb and debuggee and executes test cases
34+
* list003a.java - the debugged application
35+
* COMMENTS
36+
*
37+
* @library /vmTestbase
38+
* /test/lib
39+
* @build nsk.jdb.list.list003.list003a
40+
* @run main/othervm
41+
* nsk.jdb.list.list003.list003
42+
* -arch=${os.family}-${os.simpleArch}
43+
* -waittime=5
44+
* -debugee.vmkind=java
45+
* -transport.address=dynamic
46+
* -jdb=${test.jdk}/bin/jdb
47+
* -jdb.option="-J-Duser.language=en -J-Duser.country=US"
48+
* -java.options="${test.vm.opts} ${test.java.opts}"
49+
* -workdir=.
50+
* -debugee.vmkeys="${test.vm.opts} ${test.java.opts}"
51+
*/
52+
53+
package nsk.jdb.list.list003;
54+
55+
import java.io.PrintStream;
56+
import java.util.ArrayList;
57+
import java.util.Arrays;
58+
import java.util.List;
59+
import static java.util.stream.Collectors.toList;
60+
61+
import nsk.share.jdb.JdbTest;
62+
import nsk.share.jdb.JdbCommand;
63+
64+
65+
public class list003 extends JdbTest {
66+
static final String PACKAGE_NAME = "nsk.jdb.list.list003";
67+
static final String TEST_CLASS = PACKAGE_NAME + ".list003";
68+
static final String DEBUGGEE_CLASS = TEST_CLASS + "a";
69+
static final String FIRST_BREAK = DEBUGGEE_CLASS + ".main";
70+
71+
/**
72+
* Represents a line output by the {@code list} command.
73+
*/
74+
protected static record ListLine(int number, boolean active) {
75+
public static ListLine parse(String line) {
76+
String[] tokens = line.split("\\s+");
77+
return new ListLine(
78+
Integer.parseInt(tokens[0]),
79+
tokens.length >= 2 && tokens[1].equals("=>")
80+
);
81+
}
82+
}
83+
84+
protected static boolean isPrompt(String line) {
85+
return line.trim().equals("main[1]");
86+
}
87+
88+
protected static List<ListLine> parseListOutput(String[] lines) {
89+
List<String> lineList = new ArrayList<>(Arrays.asList(lines));
90+
if (!isPrompt(lineList.remove(lineList.size() - 1))) {
91+
throw new AssertionError("Expected trailing prompt");
92+
} else if (lineList.size() == 1 && lineList.get(0).equals("EOF")) {
93+
return new ArrayList<>();
94+
} else {
95+
return lineList.stream().map(ListLine::parse).collect(toList());
96+
}
97+
}
98+
99+
public static void main(String[] args) {
100+
System.exit(run(args, System.out) + JCK_STATUS_BASE);
101+
}
102+
103+
public static int run(String[] args, PrintStream out) {
104+
debuggeeClass = DEBUGGEE_CLASS;
105+
firstBreak = FIRST_BREAK;
106+
return new list003().runTest(args, out);
107+
}
108+
109+
@Override
110+
protected void runCases() {
111+
try {
112+
runCasesNoCleanup();
113+
} finally {
114+
jdb.contToExit(1);
115+
}
116+
}
117+
118+
protected void runCasesNoCleanup() {
119+
if (jdb.receiveReplyFor(JdbCommand.repeat + "on").length != 1) {
120+
throw new AssertionError("Missing or unexpected output");
121+
}
122+
123+
List<ListLine> autoList = parseListOutput(jdb.receiveReplyFor(JdbCommand.list));
124+
int lineNo = autoList.stream().filter(ListLine::active).findFirst().get().number();
125+
List<ListLine> manualList = parseListOutput(jdb.receiveReplyFor(JdbCommand.list + (lineNo - 1)));
126+
if (manualList.stream().filter(ListLine::active).findFirst().get().number() != lineNo) {
127+
throw new AssertionError("Manual listing didn't mark the active source line");
128+
}
129+
130+
// Verify that we can correctly list by auto-advance all the way to EOF
131+
List<ListLine> prevList = manualList;
132+
int reps;
133+
for (reps = 0; !prevList.isEmpty(); reps += 1) {
134+
// Exercise both explicit `list' and auto-repeat
135+
var command = reps % 2 == 0 ? JdbCommand.list : "";
136+
137+
List<ListLine> currList = parseListOutput(jdb.receiveReplyFor(command));
138+
if (currList.equals(prevList)) {
139+
// This guards against infinite looping
140+
throw new AssertionError("Consecutive listings were identical");
141+
}
142+
int prevEnd = prevList.get(prevList.size() - 1).number();
143+
if (!currList.isEmpty() && currList.get(0).number() != prevEnd + 1) {
144+
throw new AssertionError("Consecutive listings weren't for consecutive source chunks");
145+
}
146+
prevList = currList;
147+
}
148+
if (reps < 2) {
149+
throw new AssertionError("Didn't get enough consecutive list reps");
150+
}
151+
152+
String[] lines = jdb.receiveReplyFor(JdbCommand.up);
153+
if (!lines[0].equals("End of stack.") || !isPrompt(lines[1])) {
154+
throw new AssertionError("Unexpected output from `up'");
155+
}
156+
List<ListLine> resetList = parseListOutput(jdb.receiveReplyFor(JdbCommand.list));
157+
if (!resetList.stream().anyMatch(ListLine::active)) {
158+
throw new AssertionError("List target didn't reset to active line");
159+
}
160+
161+
List<ListLine> listing = parseListOutput(jdb.receiveReplyFor(JdbCommand.list + "1"));
162+
if (!listing.stream().anyMatch(l -> l.number() == 1)) {
163+
throw new AssertionError("Manual listing displayed the wrong lines");
164+
}
165+
166+
List<ListLine> targetedList = parseListOutput(jdb.receiveReplyFor(JdbCommand.list + "1"));
167+
autoList = parseListOutput(jdb.receiveReplyFor(JdbCommand.list));
168+
if (autoList.get(0).number() != targetedList.get(targetedList.size() - 1).number() + 1) {
169+
throw new AssertionError("Auto-advance didn't work after targeted list");
170+
}
171+
}
172+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package nsk.jdb.list.list003;
25+
26+
import nsk.share.Log;
27+
import nsk.share.jdb.JdbArgumentHandler;
28+
29+
import java.io.PrintStream;
30+
31+
32+
/* This is debuggee application */
33+
public class list003a {
34+
static list003a _list003a = new list003a();
35+
36+
public static void main(String[] args) {
37+
System.exit(list003.JCK_STATUS_BASE + _list003a.runIt(args, System.out));
38+
}
39+
40+
public int runIt(String[] args, PrintStream out) {
41+
JdbArgumentHandler argumentHandler = new JdbArgumentHandler(args);
42+
Log log = new Log(out, argumentHandler);
43+
44+
log.display("Debuggee PASSED");
45+
return list003.PASSED;
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
*
27+
* @summary
28+
* VM Testbase keywords: [jpda, jdb]
29+
* VM Testbase readme:
30+
* DECSRIPTION
31+
* Tests the operation of the `repeat' commands, which print and change the status of GDB-style command repetition and
32+
* list auto-advance. The particular behavior of `list' when repitition is on is tested in the `list' tests.
33+
* The test consists of two program:
34+
* repeat001.java - launches jdb and debuggee and executes test cases
35+
* repeat001a.java - the debugged application
36+
* COMMENTS
37+
*
38+
* @library /vmTestbase
39+
* /test/lib
40+
* @build nsk.jdb.repeat.repeat001.repeat001a
41+
* @run main/othervm
42+
* nsk.jdb.repeat.repeat001.repeat001
43+
* -arch=${os.family}-${os.simpleArch}
44+
* -waittime=5
45+
* -debugee.vmkind=java
46+
* -transport.address=dynamic
47+
* -jdb=${test.jdk}/bin/jdb
48+
* -jdb.option="-J-Duser.language=en -J-Duser.country=US"
49+
* -java.options="${test.vm.opts} ${test.java.opts}"
50+
* -workdir=.
51+
* -debugee.vmkeys="${test.vm.opts} ${test.java.opts}"
52+
*/
53+
54+
package nsk.jdb.repeat.repeat001;
55+
56+
import java.io.PrintStream;
57+
import java.util.Arrays;
58+
59+
import nsk.share.jdb.JdbTest;
60+
import nsk.share.jdb.JdbCommand;
61+
import jdk.test.lib.Utils;
62+
63+
64+
public class repeat001 extends JdbTest {
65+
static final String PACKAGE_NAME = "nsk.jdb.repeat.repeat001";
66+
static final String TEST_CLASS = PACKAGE_NAME + ".repeat001";
67+
static final String DEBUGGEE_CLASS = TEST_CLASS + "a";
68+
static final String FIRST_BREAK = DEBUGGEE_CLASS + ".main";
69+
70+
public static void main(String[] args) {
71+
System.exit(run(args, System.out) + JCK_STATUS_BASE);
72+
}
73+
74+
public static int run(String[] args, PrintStream out) {
75+
debuggeeClass = DEBUGGEE_CLASS;
76+
firstBreak = FIRST_BREAK;
77+
return new repeat001().runTest(args, out);
78+
}
79+
80+
protected static boolean isPrompt(String line) {
81+
return line.trim().equals("main[1]");
82+
}
83+
84+
@Override
85+
protected void runCases() {
86+
try {
87+
runCasesNoCleanup();
88+
} finally {
89+
jdb.contToExit(1);
90+
}
91+
}
92+
93+
protected void runCasesNoCleanup() {
94+
// Verify that repeat is off initially
95+
String[] reply = jdb.receiveReplyFor(JdbCommand.repeat);
96+
if (reply.length != 2 || !isPrompt(reply[1])) {
97+
throw new AssertionError("Unexpected output");
98+
}
99+
if (!reply[0].equals("Repeat is off")) {
100+
throw new AssertionError("Incorrect initial repeat setting");
101+
}
102+
103+
// Verify that list auto-advance is disabled
104+
String[] firstList = jdb.receiveReplyFor(JdbCommand.list);
105+
String[] secondList = jdb.receiveReplyFor(JdbCommand.list);
106+
if (!Arrays.equals(firstList, secondList)) {
107+
throw new AssertionError("Listing inconsistent with repeat off");
108+
}
109+
110+
// Verify that command repetition doesn't happen when disabled
111+
reply = jdb.receiveReplyFor("");
112+
if (reply.length != 1 || !isPrompt(reply[0])) {
113+
throw new AssertionError("Unexpected output");
114+
}
115+
116+
reply = jdb.receiveReplyFor(JdbCommand.repeat + "on");
117+
if (reply.length != 1 || !isPrompt(reply[0])) {
118+
throw new AssertionError("Unexpected output");
119+
}
120+
121+
// Verify that repeat is reported on
122+
reply = jdb.receiveReplyFor(JdbCommand.repeat);
123+
if (reply.length != 2 || !isPrompt(reply[1])) {
124+
throw new AssertionError("Unexpected output");
125+
}
126+
if (!reply[0].equals("Repeat is on")) {
127+
throw new AssertionError("Incorrect repeat status reported");
128+
}
129+
130+
// Verify that non-repeatable commands still don't repeat
131+
if (jdb.receiveReplyFor(JdbCommand.print + "0").length != 2) {
132+
throw new AssertionError("Unexpected output");
133+
}
134+
if (jdb.receiveReplyFor("").length != 1) {
135+
throw new AssertionError("Unexpected output");
136+
}
137+
138+
// Verify that repeated commands are repeatable
139+
// (`up' just prints `End of stack.' since we're stopped in `main')
140+
reply = jdb.receiveReplyFor("2 2 " + JdbCommand.up);
141+
if (reply.length != 5 || !isPrompt(reply[4])) {
142+
throw new AssertionError("Unexpected output");
143+
}
144+
if (!Arrays.equals(reply, jdb.receiveReplyFor(""))) {
145+
throw new AssertionError("Repeated command didn't repeat correctly");
146+
}
147+
}
148+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package nsk.jdb.repeat.repeat001;
25+
26+
import nsk.share.Log;
27+
import nsk.share.jdb.JdbArgumentHandler;
28+
29+
import java.io.PrintStream;
30+
31+
32+
/* This is debuggee application */
33+
public class repeat001a {
34+
static repeat001a _repeat001a = new repeat001a();
35+
36+
public static void main(String[] args) {
37+
System.exit(repeat001.JCK_STATUS_BASE + _repeat001a.runIt(args, System.out));
38+
}
39+
40+
public int runIt(String[] args, PrintStream out) {
41+
JdbArgumentHandler argumentHandler = new JdbArgumentHandler(args);
42+
Log log = new Log(out, argumentHandler);
43+
44+
log.display("Debuggee PASSED");
45+
return repeat001.PASSED;
46+
}
47+
}

‎test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbCommand.java

+3
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@
9999
*
100100
* !! -- repeat last command
101101
* <n> <command> -- repeat command n times
102+
* repeat -- show whether GDB-style empty command repetition is enabled
103+
* repeat <on|off> -- enable/disable GDB-style repetition
102104
* help (or ?) -- list commands
103105
* version -- print version information
104106
* exit (or quit) -- exit debugger
@@ -145,6 +147,7 @@ public class JdbCommand {
145147
public static final String read = "read ";
146148
public static final String redefine = "redefine ";
147149
public static final String reenter = "reenter" + ls;
150+
public static final String repeat = "repeat ";
148151
public static final String resume = "resume ";
149152
public static final String run = "run ";
150153
public static final String set = "set ";

0 commit comments

Comments
 (0)
Please sign in to comment.