aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/ddb.415
-rw-r--r--sys/ddb/db_input.c126
-rw-r--r--sys/ddb/db_output.c2
-rw-r--r--sys/ddb/ddb.h1
4 files changed, 119 insertions, 25 deletions
diff --git a/share/man/man4/ddb.4 b/share/man/man4/ddb.4
index 1fe3490edd36..4f1614d8e006 100644
--- a/share/man/man4/ddb.4
+++ b/share/man/man4/ddb.4
@@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 26, 2021
+.Dd March 14, 2021
.Dt DDB 4
.Os
.Sh NAME
@@ -1571,6 +1571,19 @@ The debugger may be entered by setting the
.Xr sysctl 8
.Va debug.kdb.enter
to 1.
+.Pp
+Output may be interrupted, paused, and resumed with the control
+characters CTRL-C, CTRL-S, and CTRL-Q.
+Because these control characters are received as in-band data from the
+console, there is an input buffer, and once that buffer fills
+.Nm
+must either stop responding to control characters or drop additional
+input while continuing to search for control characters.
+This behavior is controlled by the tunable
+.Xr sysctl 8
+.Va debug.ddb.prioritize_control_input ,
+which defaults to 1.
+The input buffer size is 512 bytes.
.Sh FILES
Header files mentioned in this manual page can be found below
.Pa /usr/include
diff --git a/sys/ddb/db_input.c b/sys/ddb/db_input.c
index 41396e0a041f..a7d06e17f5c1 100644
--- a/sys/ddb/db_input.c
+++ b/sys/ddb/db_input.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cons.h>
+#include <sys/sysctl.h>
#include <ddb/ddb.h>
#include <ddb/db_output.h>
@@ -55,6 +56,19 @@ static char * db_lc; /* current character */
static char * db_le; /* one past last character */
/*
+ * Raw input buffer, processed only for certain control characters.
+ */
+#define DB_RAW_SIZE 512
+static char db_raw[DB_RAW_SIZE];
+static u_int db_raw_pos;
+static u_int db_raw_cnt;
+static int db_raw_warned;
+static int ddb_prioritize_control_input = 1;
+SYSCTL_INT(_debug_ddb, OID_AUTO, prioritize_control_input, CTLFLAG_RWTUN,
+ &ddb_prioritize_control_input, 0,
+ "Drop input when the buffer fills in order to keep servicing ^C/^S/^Q");
+
+/*
* Simple input line history support.
*/
static char db_lhistory[2048];
@@ -65,11 +79,13 @@ static int db_lhist_nlines;
#define BLANK ' '
#define BACKUP '\b'
-static int cnmaygetc(void);
static void db_delete(int n, int bwd);
static int db_inputchar(int c);
static void db_putnchars(int c, int count);
static void db_putstring(char *s, int count);
+static int db_raw_pop(void);
+static void db_raw_push(int);
+static int db_raw_space(void);
static void
db_putstring(s, count)
@@ -307,10 +323,50 @@ db_inputchar(c)
return (0);
}
+/* Get a character from the console, first checking the raw input buffer. */
+int
+db_getc(void)
+{
+ int c;
+
+ if (db_raw_cnt == 0) {
+ c = cngetc();
+ } else {
+ c = db_raw_pop();
+ if (c == '\r')
+ c = '\n';
+ }
+ return (c);
+}
+
+/* Whether the raw input buffer has space to accept another character. */
static int
-cnmaygetc()
+db_raw_space(void)
+{
+
+ return (db_raw_cnt < DB_RAW_SIZE);
+}
+
+/* Un-get a character from the console by buffering it. */
+static void
+db_raw_push(int c)
{
- return (-1);
+
+ if (!db_raw_space())
+ db_error(NULL);
+ db_raw[(db_raw_pos + db_raw_cnt++) % DB_RAW_SIZE] = c;
+}
+
+/* Drain a character from the raw input buffer. */
+static int
+db_raw_pop(void)
+{
+
+ if (db_raw_cnt == 0)
+ return (-1);
+ db_raw_cnt--;
+ db_raw_warned = 0;
+ return (db_raw[db_raw_pos++ % DB_RAW_SIZE]);
}
int
@@ -339,7 +395,7 @@ db_readline(lstart, lsize)
db_lc = lstart;
db_le = lstart;
- while (!db_inputchar(cngetc()))
+ while (!db_inputchar(db_getc()))
continue;
db_capture_write(lstart, db_le - db_lbuf_start);
@@ -361,30 +417,54 @@ db_readline(lstart, lsize)
return (db_le - db_lbuf_start);
}
+static void
+db_do_interrupt(const char *reason)
+{
+
+ /* Do a pager quit too because some commands have jmpbuf handling. */
+ db_disable_pager();
+ db_pager_quit = 1;
+ db_error(reason);
+}
+
void
db_check_interrupt(void)
{
int c;
- c = cnmaygetc();
- switch (c) {
- case -1: /* no character */
- return;
-
- case CTRL('c'):
- db_error((char *)0);
- /*NOTREACHED*/
-
- case CTRL('s'):
- do {
- c = cnmaygetc();
- if (c == CTRL('c'))
- db_error((char *)0);
- } while (c != CTRL('q'));
- break;
+ /*
+ * Check console input for control characters. Non-control input is
+ * buffered. When buffer space is exhausted, either stop responding to
+ * control input or drop further non-control input on the floor.
+ */
+ for (;;) {
+ if (!ddb_prioritize_control_input && !db_raw_space())
+ return;
+ c = cncheckc();
+ switch (c) {
+ case -1: /* no character */
+ return;
+
+ case CTRL('c'):
+ db_do_interrupt("^C");
+ /*NOTREACHED*/
+
+ case CTRL('s'):
+ do {
+ c = cncheckc();
+ if (c == CTRL('c'))
+ db_do_interrupt("^C");
+ } while (c != CTRL('q'));
+ break;
- default:
- /* drop on floor */
- break;
+ default:
+ if (db_raw_space()) {
+ db_raw_push(c);
+ } else if (!db_raw_warned) {
+ db_raw_warned = 1;
+ db_printf("\n--Exceeded input buffer--\n");
+ }
+ break;
+ }
}
}
diff --git a/sys/ddb/db_output.c b/sys/ddb/db_output.c
index 3517187f8206..41a8c7128359 100644
--- a/sys/ddb/db_output.c
+++ b/sys/ddb/db_output.c
@@ -260,7 +260,7 @@ db_pager(void)
db_printf("--More--\r");
done = 0;
while (!done) {
- c = cngetc();
+ c = db_getc();
switch (c) {
case 'e':
case 'j':
diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h
index 81448474c514..5ae48d21fda9 100644
--- a/sys/ddb/ddb.h
+++ b/sys/ddb/ddb.h
@@ -197,6 +197,7 @@ db_addr_t db_disasm(db_addr_t loc, bool altfmt);
/* instruction disassembler */
void db_error(const char *s);
int db_expression(db_expr_t *valuep);
+int db_getc(void);
int db_get_variable(db_expr_t *valuep);
void db_iprintf(const char *,...) __printflike(1, 2);
struct proc *db_lookup_proc(db_expr_t addr);