ddb: enable the use of ^C and ^S/^Q
This lets one interrupt DDB's output, which is useful if paging is
disabled and the output device is slow.
This follows a previous implementation in svn r311952 / git
5fddef7999
which was reverted because it
broke DDB type-ahead.
Now, try this again, but with a 512-byte type-ahead buffer. While there
is buffer space, control input is handled and non-control input is
buffered. When the buffer is exhausted, the default is to print a
warning and drop further non-control input in order to continue handling
control input. sysctl debug.ddb.prioritize_control_input can be set to
0 to instead preserve all input but lose immediate handling of control
input. This could for example effect pasting of a large script into the
ddb console.
Suggested by: Anton Rang <rang@acm.org>
Reviewed by: markj
Discussed with: imp
Sponsored by: Dell EMC Isilon
Differential Revision: https://reviews.freebsd.org/D28676
This commit is contained in:
parent
588ce1a3ac
commit
3e5e9939cd
@ -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
|
||||
|
@ -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>
|
||||
@ -54,6 +55,19 @@ static char * db_lbuf_end; /* end of input line buffer */
|
||||
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.
|
||||
*/
|
||||
@ -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);
|
||||
}
|
||||
|
||||
static int
|
||||
cnmaygetc()
|
||||
/* Get a character from the console, first checking the raw input buffer. */
|
||||
int
|
||||
db_getc(void)
|
||||
{
|
||||
return (-1);
|
||||
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
|
||||
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)
|
||||
{
|
||||
|
||||
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;
|
||||
/*
|
||||
* 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_error((char *)0);
|
||||
/*NOTREACHED*/
|
||||
case CTRL('c'):
|
||||
db_do_interrupt("^C");
|
||||
/*NOTREACHED*/
|
||||
|
||||
case CTRL('s'):
|
||||
do {
|
||||
c = cnmaygetc();
|
||||
if (c == CTRL('c'))
|
||||
db_error((char *)0);
|
||||
} while (c != CTRL('q'));
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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':
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user