Skip to content

Commit 4f27e82

Browse files
author
Daniel Thompson
committed
kdb: Remove special case logic from kdb_read()
kdb_read() contains special case logic to force it exit after reading a single character. We can remove all the special case logic by directly calling the function to read a single character instead. This also allows us to tidy up the function prototype which, because it now matches getchar(), we can also rename in order to make its role clearer. This does involve some extra code to handle btaprompt properly but we don't mind the new lines of code here because the old code had some interesting problems (bad newline handling, treating unexpected characters like <cr>). Signed-off-by: Daniel Thompson <[email protected]> Reviewed-by: Douglas Anderson <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent d04213a commit 4f27e82

File tree

3 files changed

+42
-42
lines changed

3 files changed

+42
-42
lines changed

kernel/debug/kdb/kdb_bt.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,22 +75,28 @@ static void kdb_show_stack(struct task_struct *p, void *addr)
7575
static int
7676
kdb_bt1(struct task_struct *p, unsigned long mask, bool btaprompt)
7777
{
78-
char buffer[2];
79-
if (kdb_getarea(buffer[0], (unsigned long)p) ||
80-
kdb_getarea(buffer[0], (unsigned long)(p+1)-1))
78+
char ch;
79+
80+
if (kdb_getarea(ch, (unsigned long)p) ||
81+
kdb_getarea(ch, (unsigned long)(p+1)-1))
8182
return KDB_BADADDR;
8283
if (!kdb_task_state(p, mask))
8384
return 0;
8485
kdb_printf("Stack traceback for pid %d\n", p->pid);
8586
kdb_ps1(p);
8687
kdb_show_stack(p, NULL);
8788
if (btaprompt) {
88-
kdb_getstr(buffer, sizeof(buffer),
89-
"Enter <q> to end, <cr> to continue:");
90-
if (buffer[0] == 'q') {
91-
kdb_printf("\n");
89+
kdb_printf("Enter <q> to end, <cr> or <space> to continue:");
90+
do {
91+
ch = kdb_getchar();
92+
} while (!strchr("\r\n q", ch));
93+
kdb_printf("\n");
94+
95+
/* reset the pager */
96+
kdb_nextline = 1;
97+
98+
if (ch == 'q')
9299
return 1;
93-
}
94100
}
95101
touch_nmi_watchdog();
96102
return 0;

kernel/debug/kdb/kdb_io.c

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,22 @@ static int kdb_handle_escape(char *buf, size_t sz)
108108
return -1;
109109
}
110110

111-
static int kdb_read_get_key(char *buffer, size_t bufsize)
111+
/**
112+
* kdb_getchar() - Read a single character from a kdb console (or consoles).
113+
*
114+
* Other than polling the various consoles that are currently enabled,
115+
* most of the work done in this function is dealing with escape sequences.
116+
*
117+
* An escape key could be the start of a vt100 control sequence such as \e[D
118+
* (left arrow) or it could be a character in its own right. The standard
119+
* method for detecting the difference is to wait for 2 seconds to see if there
120+
* are any other characters. kdb is complicated by the lack of a timer service
121+
* (interrupts are off), by multiple input sources. Escape sequence processing
122+
* has to be done as states in the polling loop.
123+
*
124+
* Return: The key pressed or a control code derived from an escape sequence.
125+
*/
126+
char kdb_getchar(void)
112127
{
113128
#define ESCAPE_UDELAY 1000
114129
#define ESCAPE_DELAY (2*1000000/ESCAPE_UDELAY) /* 2 seconds worth of udelays */
@@ -126,7 +141,6 @@ static int kdb_read_get_key(char *buffer, size_t bufsize)
126141
}
127142

128143
key = (*f)();
129-
130144
if (key == -1) {
131145
if (escape_delay) {
132146
udelay(ESCAPE_UDELAY);
@@ -136,14 +150,6 @@ static int kdb_read_get_key(char *buffer, size_t bufsize)
136150
continue;
137151
}
138152

139-
if (bufsize <= 2) {
140-
if (key == '\r')
141-
key = '\n';
142-
*buffer++ = key;
143-
*buffer = '\0';
144-
return -1;
145-
}
146-
147153
if (escape_delay == 0 && key == '\e') {
148154
escape_delay = ESCAPE_DELAY;
149155
ped = escape_data;
@@ -184,17 +190,7 @@ static int kdb_read_get_key(char *buffer, size_t bufsize)
184190
* function. It is not reentrant - it relies on the fact
185191
* that while kdb is running on only one "master debug" cpu.
186192
* Remarks:
187-
*
188-
* The buffer size must be >= 2. A buffer size of 2 means that the caller only
189-
* wants a single key.
190-
*
191-
* An escape key could be the start of a vt100 control sequence such as \e[D
192-
* (left arrow) or it could be a character in its own right. The standard
193-
* method for detecting the difference is to wait for 2 seconds to see if there
194-
* are any other characters. kdb is complicated by the lack of a timer service
195-
* (interrupts are off), by multiple input sources and by the need to sometimes
196-
* return after just one key. Escape sequence processing has to be done as
197-
* states in the polling loop.
193+
* The buffer size must be >= 2.
198194
*/
199195

200196
static char *kdb_read(char *buffer, size_t bufsize)
@@ -229,9 +225,7 @@ static char *kdb_read(char *buffer, size_t bufsize)
229225
*cp = '\0';
230226
kdb_printf("%s", buffer);
231227
poll_again:
232-
key = kdb_read_get_key(buffer, bufsize);
233-
if (key == -1)
234-
return buffer;
228+
key = kdb_getchar();
235229
if (key != 9)
236230
tab = 0;
237231
switch (key) {
@@ -742,7 +736,7 @@ int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap)
742736

743737
/* check for having reached the LINES number of printed lines */
744738
if (kdb_nextline >= linecount) {
745-
char buf1[16] = "";
739+
char ch;
746740

747741
/* Watch out for recursion here. Any routine that calls
748742
* kdb_printf will come back through here. And kdb_read
@@ -777,39 +771,38 @@ int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap)
777771
if (logging)
778772
printk("%s", moreprompt);
779773

780-
kdb_read(buf1, 2); /* '2' indicates to return
781-
* immediately after getting one key. */
774+
ch = kdb_getchar();
782775
kdb_nextline = 1; /* Really set output line 1 */
783776

784777
/* empty and reset the buffer: */
785778
kdb_buffer[0] = '\0';
786779
next_avail = kdb_buffer;
787780
size_avail = sizeof(kdb_buffer);
788-
if ((buf1[0] == 'q') || (buf1[0] == 'Q')) {
781+
if ((ch == 'q') || (ch == 'Q')) {
789782
/* user hit q or Q */
790783
KDB_FLAG_SET(CMD_INTERRUPT); /* command interrupted */
791784
KDB_STATE_CLEAR(PAGER);
792785
/* end of command output; back to normal mode */
793786
kdb_grepping_flag = 0;
794787
kdb_printf("\n");
795-
} else if (buf1[0] == ' ') {
788+
} else if (ch == ' ') {
796789
kdb_printf("\r");
797790
suspend_grep = 1; /* for this recursion */
798-
} else if (buf1[0] == '\n') {
791+
} else if (ch == '\n' || ch == '\r') {
799792
kdb_nextline = linecount - 1;
800793
kdb_printf("\r");
801794
suspend_grep = 1; /* for this recursion */
802-
} else if (buf1[0] == '/' && !kdb_grepping_flag) {
795+
} else if (ch == '/' && !kdb_grepping_flag) {
803796
kdb_printf("\r");
804797
kdb_getstr(kdb_grep_string, KDB_GREP_STRLEN,
805798
kdbgetenv("SEARCHPROMPT") ?: "search> ");
806799
*strchrnul(kdb_grep_string, '\n') = '\0';
807800
kdb_grepping_flag += KDB_GREPPING_FLAG_SEARCH;
808801
suspend_grep = 1; /* for this recursion */
809-
} else if (buf1[0] && buf1[0] != '\n') {
810-
/* user hit something other than enter */
802+
} else if (ch) {
803+
/* user hit something unexpected */
811804
suspend_grep = 1; /* for this recursion */
812-
if (buf1[0] != '/')
805+
if (ch != '/')
813806
kdb_printf(
814807
"\nOnly 'q', 'Q' or '/' are processed at "
815808
"more prompt, input ignored\n");

kernel/debug/kdb/kdb_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ extern void kdb_ps1(const struct task_struct *p);
210210
extern void kdb_print_nameval(const char *name, unsigned long val);
211211
extern void kdb_send_sig(struct task_struct *p, int sig);
212212
extern void kdb_meminfo_proc_show(void);
213+
extern char kdb_getchar(void);
213214
extern char *kdb_getstr(char *, size_t, const char *);
214215
extern void kdb_gdb_state_pass(char *buf);
215216

0 commit comments

Comments
 (0)