kgdb patches for 5.5-rc1
The major change here is the work from Douglas Anderson that reworks the way kdb stack traces are handled on SMP systems. The effect is to allow all CPUs to issue their stack trace which reduced the need for architecture specific code to support stack tracing. Also included are general of clean ups from Doug and myself: * Remove some unused variables or arguments. * Tidy up the kdb escape handling code and fix a couple of odd corner cases. - Better ignore escape characters that do not form part of an escape sequence. This mostly benefits vi users since they are most likely to press escape as a nervous habit but it won't harm anyone else. Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEELzVBU1D3lWq6cKzwfOMlXTn3iKEFAl3dPzwACgkQfOMlXTn3 iKG2sxAAkGTTmKKlu8cAEILD7ONXM3kB0lfsTxJ2aBdrFhkZxOmVIO5fAaTxLRh5 bmznv1bzA6FulSxS2d0aGa8Oh3QE8z7fV2fngsW409ikUf3uu43K13R2yQGnOdZY n+dMR+C/H8LWvmUDK1rZtNf91uhmD+DNxpoI6U7H4mIVMC1RRP8XtMyf3m9qRbJE Bud0JAdOHB5eSH9a/97elRIhIUCWUSkeFG950RIMT08kdsyIAaobg+4NmlmTZsl2 zVmXaIftBjiDAkEDtk/7p9N+3U42e0aWA2YSxq4lYgNfgsbJTGP8GskNTOG+egOJ N03xHqHR7NhzkCKjneocEba95uKct7t50+epC6nAT8GF4COV6aLNUcm+vNhcVmLI kbJO0ZcWp+iBr0O5GO53ZaGEoD3GAT7l3tDGqXkcJN1OGc6gjiEih8FRFoMa6cIJ GdqziWsooOlHgGgu9lsRL1a0pvrFJFkd9ha7XEKWIq8CEiHmKSbhPJF3SyaX2XJA NTrthitANWGWC4EIapV+jhSZ/8tOKfT5ehCvFEtnouKJ0pHFyynDJaveUJ3561Bl qr7noViXcIidDgceagGSZz7fQxBZeG3MNL1D5YIcpE3lfEHKSl5FivQ5kBmq79at 1svw1OmocrvFuUhxhkj1Yo2R7Q6k97IYeX8v1q7DBkFaXS7Lv6E= =CZKd -----END PGP SIGNATURE----- Merge tag 'kgdb-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux Pull kgdb updates from Daniel Thompson: "The major change here is the work from Douglas Anderson that reworks the way kdb stack traces are handled on SMP systems. The effect is to allow all CPUs to issue their stack trace which reduced the need for architecture specific code to support stack tracing. Also included are general of clean ups from Doug and myself: - Remove some unused variables or arguments. - Tidy up the kdb escape handling code and fix a couple of odd corner cases. - Better ignore escape characters that do not form part of an escape sequence. This mostly benefits vi users since they are most likely to press escape as a nervous habit but it won't harm anyone else" * tag 'kgdb-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux: kdb: Tweak escape handling for vi users kdb: Improve handling of characters from different input sources kdb: Remove special case logic from kdb_read() kdb: Simplify code to fetch characters from console kdb: Tidy up code to handle escape sequences kdb: Avoid array subscript warnings on non-SMP builds kdb: Fix stack crawling on 'running' CPUs that aren't the master kdb: Fix "btc <cpu>" crash if the CPU didn't round up kdb: Remove unused "argcount" param from kdb_bt1(); make btaprompt bool kgdb: Remove unused DCPU_SSTEP definition
This commit is contained in:
commit
8a99117f6e
|
@ -441,6 +441,37 @@ setundefined:
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KGDB_KDB
|
||||
void kdb_dump_stack_on_cpu(int cpu)
|
||||
{
|
||||
if (cpu == raw_smp_processor_id() || !IS_ENABLED(CONFIG_SMP)) {
|
||||
dump_stack();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(kgdb_info[cpu].exception_state & DCPU_IS_SLAVE)) {
|
||||
kdb_printf("ERROR: Task on cpu %d didn't stop in the debugger\n",
|
||||
cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* In general, architectures don't support dumping the stack of a
|
||||
* "running" process that's not the current one. From the point of
|
||||
* view of the Linux, kernel processes that are looping in the kgdb
|
||||
* slave loop are still "running". There's also no API (that actually
|
||||
* works across all architectures) that can do a stack crawl based
|
||||
* on registers passed as a parameter.
|
||||
*
|
||||
* Solve this conundrum by asking slave CPUs to do the backtrace
|
||||
* themselves.
|
||||
*/
|
||||
kgdb_info[cpu].exception_state |= DCPU_WANT_BT;
|
||||
while (kgdb_info[cpu].exception_state & DCPU_WANT_BT)
|
||||
cpu_relax();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return true if there is a valid kgdb I/O module. Also if no
|
||||
* debugger is attached a message can be printed to the console about
|
||||
|
@ -580,6 +611,9 @@ cpu_loop:
|
|||
atomic_xchg(&kgdb_active, cpu);
|
||||
break;
|
||||
}
|
||||
} else if (kgdb_info[cpu].exception_state & DCPU_WANT_BT) {
|
||||
dump_stack();
|
||||
kgdb_info[cpu].exception_state &= ~DCPU_WANT_BT;
|
||||
} else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) {
|
||||
if (!raw_spin_is_locked(&dbg_slave_lock))
|
||||
goto return_normal;
|
||||
|
|
|
@ -33,7 +33,7 @@ struct kgdb_state {
|
|||
#define DCPU_WANT_MASTER 0x1 /* Waiting to become a master kgdb cpu */
|
||||
#define DCPU_NEXT_MASTER 0x2 /* Transition from one master cpu to another */
|
||||
#define DCPU_IS_SLAVE 0x4 /* Slave cpu enter exception */
|
||||
#define DCPU_SSTEP 0x8 /* CPU is single stepping */
|
||||
#define DCPU_WANT_BT 0x8 /* Slave cpu should backtrace then clear flag */
|
||||
|
||||
struct debuggerinfo_struct {
|
||||
void *debuggerinfo;
|
||||
|
@ -76,6 +76,7 @@ extern int kdb_stub(struct kgdb_state *ks);
|
|||
extern int kdb_parse(const char *cmdstr);
|
||||
extern int kdb_common_init_state(struct kgdb_state *ks);
|
||||
extern int kdb_common_deinit_state(void);
|
||||
extern void kdb_dump_stack_on_cpu(int cpu);
|
||||
#else /* ! CONFIG_KGDB_KDB */
|
||||
static inline int kdb_stub(struct kgdb_state *ks)
|
||||
{
|
||||
|
|
|
@ -22,20 +22,15 @@
|
|||
static void kdb_show_stack(struct task_struct *p, void *addr)
|
||||
{
|
||||
int old_lvl = console_loglevel;
|
||||
|
||||
console_loglevel = CONSOLE_LOGLEVEL_MOTORMOUTH;
|
||||
kdb_trap_printk++;
|
||||
kdb_set_current_task(p);
|
||||
if (addr) {
|
||||
show_stack((struct task_struct *)p, addr);
|
||||
} else if (kdb_current_regs) {
|
||||
#ifdef CONFIG_X86
|
||||
show_stack(p, &kdb_current_regs->sp);
|
||||
#else
|
||||
show_stack(p, NULL);
|
||||
#endif
|
||||
} else {
|
||||
show_stack(p, NULL);
|
||||
}
|
||||
|
||||
if (!addr && kdb_task_has_cpu(p))
|
||||
kdb_dump_stack_on_cpu(kdb_process_cpu(p));
|
||||
else
|
||||
show_stack(p, addr);
|
||||
|
||||
console_loglevel = old_lvl;
|
||||
kdb_trap_printk--;
|
||||
}
|
||||
|
@ -78,12 +73,12 @@ static void kdb_show_stack(struct task_struct *p, void *addr)
|
|||
*/
|
||||
|
||||
static int
|
||||
kdb_bt1(struct task_struct *p, unsigned long mask,
|
||||
int argcount, int btaprompt)
|
||||
kdb_bt1(struct task_struct *p, unsigned long mask, bool btaprompt)
|
||||
{
|
||||
char buffer[2];
|
||||
if (kdb_getarea(buffer[0], (unsigned long)p) ||
|
||||
kdb_getarea(buffer[0], (unsigned long)(p+1)-1))
|
||||
char ch;
|
||||
|
||||
if (kdb_getarea(ch, (unsigned long)p) ||
|
||||
kdb_getarea(ch, (unsigned long)(p+1)-1))
|
||||
return KDB_BADADDR;
|
||||
if (!kdb_task_state(p, mask))
|
||||
return 0;
|
||||
|
@ -91,22 +86,47 @@ kdb_bt1(struct task_struct *p, unsigned long mask,
|
|||
kdb_ps1(p);
|
||||
kdb_show_stack(p, NULL);
|
||||
if (btaprompt) {
|
||||
kdb_getstr(buffer, sizeof(buffer),
|
||||
"Enter <q> to end, <cr> to continue:");
|
||||
if (buffer[0] == 'q') {
|
||||
kdb_printf("\n");
|
||||
kdb_printf("Enter <q> to end, <cr> or <space> to continue:");
|
||||
do {
|
||||
ch = kdb_getchar();
|
||||
} while (!strchr("\r\n q", ch));
|
||||
kdb_printf("\n");
|
||||
|
||||
/* reset the pager */
|
||||
kdb_nextline = 1;
|
||||
|
||||
if (ch == 'q')
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
touch_nmi_watchdog();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
kdb_bt_cpu(unsigned long cpu)
|
||||
{
|
||||
struct task_struct *kdb_tsk;
|
||||
|
||||
if (cpu >= num_possible_cpus() || !cpu_online(cpu)) {
|
||||
kdb_printf("WARNING: no process for cpu %ld\n", cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If a CPU failed to round up we could be here */
|
||||
kdb_tsk = KDB_TSK(cpu);
|
||||
if (!kdb_tsk) {
|
||||
kdb_printf("WARNING: no task for cpu %ld\n", cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
kdb_set_current_task(kdb_tsk);
|
||||
kdb_bt1(kdb_tsk, ~0UL, false);
|
||||
}
|
||||
|
||||
int
|
||||
kdb_bt(int argc, const char **argv)
|
||||
{
|
||||
int diag;
|
||||
int argcount = 5;
|
||||
int btaprompt = 1;
|
||||
int nextarg;
|
||||
unsigned long addr;
|
||||
|
@ -125,7 +145,7 @@ kdb_bt(int argc, const char **argv)
|
|||
/* Run the active tasks first */
|
||||
for_each_online_cpu(cpu) {
|
||||
p = kdb_curr_task(cpu);
|
||||
if (kdb_bt1(p, mask, argcount, btaprompt))
|
||||
if (kdb_bt1(p, mask, btaprompt))
|
||||
return 0;
|
||||
}
|
||||
/* Now the inactive tasks */
|
||||
|
@ -134,7 +154,7 @@ kdb_bt(int argc, const char **argv)
|
|||
return 0;
|
||||
if (task_curr(p))
|
||||
continue;
|
||||
if (kdb_bt1(p, mask, argcount, btaprompt))
|
||||
if (kdb_bt1(p, mask, btaprompt))
|
||||
return 0;
|
||||
} kdb_while_each_thread(g, p);
|
||||
} else if (strcmp(argv[0], "btp") == 0) {
|
||||
|
@ -148,7 +168,7 @@ kdb_bt(int argc, const char **argv)
|
|||
p = find_task_by_pid_ns(pid, &init_pid_ns);
|
||||
if (p) {
|
||||
kdb_set_current_task(p);
|
||||
return kdb_bt1(p, ~0UL, argcount, 0);
|
||||
return kdb_bt1(p, ~0UL, false);
|
||||
}
|
||||
kdb_printf("No process with pid == %ld found\n", pid);
|
||||
return 0;
|
||||
|
@ -159,11 +179,10 @@ kdb_bt(int argc, const char **argv)
|
|||
if (diag)
|
||||
return diag;
|
||||
kdb_set_current_task((struct task_struct *)addr);
|
||||
return kdb_bt1((struct task_struct *)addr, ~0UL, argcount, 0);
|
||||
return kdb_bt1((struct task_struct *)addr, ~0UL, false);
|
||||
} else if (strcmp(argv[0], "btc") == 0) {
|
||||
unsigned long cpu = ~0;
|
||||
struct task_struct *save_current_task = kdb_current_task;
|
||||
char buf[80];
|
||||
if (argc > 1)
|
||||
return KDB_ARGCOUNT;
|
||||
if (argc == 1) {
|
||||
|
@ -171,35 +190,22 @@ kdb_bt(int argc, const char **argv)
|
|||
if (diag)
|
||||
return diag;
|
||||
}
|
||||
/* Recursive use of kdb_parse, do not use argv after
|
||||
* this point */
|
||||
argv = NULL;
|
||||
if (cpu != ~0) {
|
||||
if (cpu >= num_possible_cpus() || !cpu_online(cpu)) {
|
||||
kdb_printf("no process for cpu %ld\n", cpu);
|
||||
return 0;
|
||||
kdb_bt_cpu(cpu);
|
||||
} else {
|
||||
/*
|
||||
* Recursive use of kdb_parse, do not use argv after
|
||||
* this point.
|
||||
*/
|
||||
argv = NULL;
|
||||
kdb_printf("btc: cpu status: ");
|
||||
kdb_parse("cpu\n");
|
||||
for_each_online_cpu(cpu) {
|
||||
kdb_bt_cpu(cpu);
|
||||
touch_nmi_watchdog();
|
||||
}
|
||||
sprintf(buf, "btt 0x%px\n", KDB_TSK(cpu));
|
||||
kdb_parse(buf);
|
||||
return 0;
|
||||
kdb_set_current_task(save_current_task);
|
||||
}
|
||||
kdb_printf("btc: cpu status: ");
|
||||
kdb_parse("cpu\n");
|
||||
for_each_online_cpu(cpu) {
|
||||
void *kdb_tsk = KDB_TSK(cpu);
|
||||
|
||||
/* If a CPU failed to round up we could be here */
|
||||
if (!kdb_tsk) {
|
||||
kdb_printf("WARNING: no task for cpu %ld\n",
|
||||
cpu);
|
||||
continue;
|
||||
}
|
||||
|
||||
sprintf(buf, "btt 0x%px\n", kdb_tsk);
|
||||
kdb_parse(buf);
|
||||
touch_nmi_watchdog();
|
||||
}
|
||||
kdb_set_current_task(save_current_task);
|
||||
return 0;
|
||||
} else {
|
||||
if (argc) {
|
||||
|
@ -211,7 +217,7 @@ kdb_bt(int argc, const char **argv)
|
|||
kdb_show_stack(kdb_current_task, (void *)addr);
|
||||
return 0;
|
||||
} else {
|
||||
return kdb_bt1(kdb_current_task, ~0UL, argcount, 0);
|
||||
return kdb_bt1(kdb_current_task, ~0UL, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,14 +49,88 @@ static int kgdb_transition_check(char *buffer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int kdb_read_get_key(char *buffer, size_t bufsize)
|
||||
/**
|
||||
* kdb_handle_escape() - validity check on an accumulated escape sequence.
|
||||
* @buf: Accumulated escape characters to be examined. Note that buf
|
||||
* is not a string, it is an array of characters and need not be
|
||||
* nil terminated.
|
||||
* @sz: Number of accumulated escape characters.
|
||||
*
|
||||
* Return: -1 if the escape sequence is unwanted, 0 if it is incomplete,
|
||||
* otherwise it returns a mapped key value to pass to the upper layers.
|
||||
*/
|
||||
static int kdb_handle_escape(char *buf, size_t sz)
|
||||
{
|
||||
char *lastkey = buf + sz - 1;
|
||||
|
||||
switch (sz) {
|
||||
case 1:
|
||||
if (*lastkey == '\e')
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 2: /* \e<something> */
|
||||
if (*lastkey == '[')
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
switch (*lastkey) {
|
||||
case 'A': /* \e[A, up arrow */
|
||||
return 16;
|
||||
case 'B': /* \e[B, down arrow */
|
||||
return 14;
|
||||
case 'C': /* \e[C, right arrow */
|
||||
return 6;
|
||||
case 'D': /* \e[D, left arrow */
|
||||
return 2;
|
||||
case '1': /* \e[<1,3,4>], may be home, del, end */
|
||||
case '3':
|
||||
case '4':
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (*lastkey == '~') {
|
||||
switch (buf[2]) {
|
||||
case '1': /* \e[1~, home */
|
||||
return 1;
|
||||
case '3': /* \e[3~, del */
|
||||
return 4;
|
||||
case '4': /* \e[4~, end */
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* kdb_getchar() - Read a single character from a kdb console (or consoles).
|
||||
*
|
||||
* Other than polling the various consoles that are currently enabled,
|
||||
* most of the work done in this function is dealing with escape sequences.
|
||||
*
|
||||
* An escape key could be the start of a vt100 control sequence such as \e[D
|
||||
* (left arrow) or it could be a character in its own right. The standard
|
||||
* method for detecting the difference is to wait for 2 seconds to see if there
|
||||
* are any other characters. kdb is complicated by the lack of a timer service
|
||||
* (interrupts are off), by multiple input sources. Escape sequence processing
|
||||
* has to be done as states in the polling loop.
|
||||
*
|
||||
* Return: The key pressed or a control code derived from an escape sequence.
|
||||
*/
|
||||
char kdb_getchar(void)
|
||||
{
|
||||
#define ESCAPE_UDELAY 1000
|
||||
#define ESCAPE_DELAY (2*1000000/ESCAPE_UDELAY) /* 2 seconds worth of udelays */
|
||||
char escape_data[5]; /* longest vt100 escape sequence is 4 bytes */
|
||||
char *ped = escape_data;
|
||||
char buf[4]; /* longest vt100 escape sequence is 4 bytes */
|
||||
char *pbuf = buf;
|
||||
int escape_delay = 0;
|
||||
get_char_func *f, *f_escape = NULL;
|
||||
get_char_func *f, *f_prev = NULL;
|
||||
int key;
|
||||
|
||||
for (f = &kdb_poll_funcs[0]; ; ++f) {
|
||||
|
@ -65,109 +139,37 @@ static int kdb_read_get_key(char *buffer, size_t bufsize)
|
|||
touch_nmi_watchdog();
|
||||
f = &kdb_poll_funcs[0];
|
||||
}
|
||||
if (escape_delay == 2) {
|
||||
*ped = '\0';
|
||||
ped = escape_data;
|
||||
--escape_delay;
|
||||
}
|
||||
if (escape_delay == 1) {
|
||||
key = *ped++;
|
||||
if (!*ped)
|
||||
--escape_delay;
|
||||
break;
|
||||
}
|
||||
|
||||
key = (*f)();
|
||||
if (key == -1) {
|
||||
if (escape_delay) {
|
||||
udelay(ESCAPE_UDELAY);
|
||||
--escape_delay;
|
||||
if (--escape_delay == 0)
|
||||
return '\e';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (bufsize <= 2) {
|
||||
if (key == '\r')
|
||||
key = '\n';
|
||||
*buffer++ = key;
|
||||
*buffer = '\0';
|
||||
return -1;
|
||||
}
|
||||
if (escape_delay == 0 && key == '\e') {
|
||||
|
||||
/*
|
||||
* When the first character is received (or we get a change
|
||||
* input source) we set ourselves up to handle an escape
|
||||
* sequences (just in case).
|
||||
*/
|
||||
if (f_prev != f) {
|
||||
f_prev = f;
|
||||
pbuf = buf;
|
||||
escape_delay = ESCAPE_DELAY;
|
||||
ped = escape_data;
|
||||
f_escape = f;
|
||||
}
|
||||
if (escape_delay) {
|
||||
*ped++ = key;
|
||||
if (f_escape != f) {
|
||||
escape_delay = 2;
|
||||
continue;
|
||||
}
|
||||
if (ped - escape_data == 1) {
|
||||
/* \e */
|
||||
continue;
|
||||
} else if (ped - escape_data == 2) {
|
||||
/* \e<something> */
|
||||
if (key != '[')
|
||||
escape_delay = 2;
|
||||
continue;
|
||||
} else if (ped - escape_data == 3) {
|
||||
/* \e[<something> */
|
||||
int mapkey = 0;
|
||||
switch (key) {
|
||||
case 'A': /* \e[A, up arrow */
|
||||
mapkey = 16;
|
||||
break;
|
||||
case 'B': /* \e[B, down arrow */
|
||||
mapkey = 14;
|
||||
break;
|
||||
case 'C': /* \e[C, right arrow */
|
||||
mapkey = 6;
|
||||
break;
|
||||
case 'D': /* \e[D, left arrow */
|
||||
mapkey = 2;
|
||||
break;
|
||||
case '1': /* dropthrough */
|
||||
case '3': /* dropthrough */
|
||||
/* \e[<1,3,4>], may be home, del, end */
|
||||
case '4':
|
||||
mapkey = -1;
|
||||
break;
|
||||
}
|
||||
if (mapkey != -1) {
|
||||
if (mapkey > 0) {
|
||||
escape_data[0] = mapkey;
|
||||
escape_data[1] = '\0';
|
||||
}
|
||||
escape_delay = 2;
|
||||
}
|
||||
continue;
|
||||
} else if (ped - escape_data == 4) {
|
||||
/* \e[<1,3,4><something> */
|
||||
int mapkey = 0;
|
||||
if (key == '~') {
|
||||
switch (escape_data[2]) {
|
||||
case '1': /* \e[1~, home */
|
||||
mapkey = 1;
|
||||
break;
|
||||
case '3': /* \e[3~, del */
|
||||
mapkey = 4;
|
||||
break;
|
||||
case '4': /* \e[4~, end */
|
||||
mapkey = 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mapkey > 0) {
|
||||
escape_data[0] = mapkey;
|
||||
escape_data[1] = '\0';
|
||||
}
|
||||
escape_delay = 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break; /* A key to process */
|
||||
|
||||
*pbuf++ = key;
|
||||
key = kdb_handle_escape(buf, pbuf - buf);
|
||||
if (key < 0) /* no escape sequence; return best character */
|
||||
return buf[pbuf - buf == 2 ? 1 : 0];
|
||||
if (key > 0)
|
||||
return key;
|
||||
}
|
||||
return key;
|
||||
|
||||
unreachable();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -188,17 +190,7 @@ static int kdb_read_get_key(char *buffer, size_t bufsize)
|
|||
* function. It is not reentrant - it relies on the fact
|
||||
* that while kdb is running on only one "master debug" cpu.
|
||||
* Remarks:
|
||||
*
|
||||
* The buffer size must be >= 2. A buffer size of 2 means that the caller only
|
||||
* wants a single key.
|
||||
*
|
||||
* An escape key could be the start of a vt100 control sequence such as \e[D
|
||||
* (left arrow) or it could be a character in its own right. The standard
|
||||
* method for detecting the difference is to wait for 2 seconds to see if there
|
||||
* are any other characters. kdb is complicated by the lack of a timer service
|
||||
* (interrupts are off), by multiple input sources and by the need to sometimes
|
||||
* return after just one key. Escape sequence processing has to be done as
|
||||
* states in the polling loop.
|
||||
* The buffer size must be >= 2.
|
||||
*/
|
||||
|
||||
static char *kdb_read(char *buffer, size_t bufsize)
|
||||
|
@ -233,9 +225,7 @@ static char *kdb_read(char *buffer, size_t bufsize)
|
|||
*cp = '\0';
|
||||
kdb_printf("%s", buffer);
|
||||
poll_again:
|
||||
key = kdb_read_get_key(buffer, bufsize);
|
||||
if (key == -1)
|
||||
return buffer;
|
||||
key = kdb_getchar();
|
||||
if (key != 9)
|
||||
tab = 0;
|
||||
switch (key) {
|
||||
|
@ -746,7 +736,7 @@ kdb_printit:
|
|||
|
||||
/* check for having reached the LINES number of printed lines */
|
||||
if (kdb_nextline >= linecount) {
|
||||
char buf1[16] = "";
|
||||
char ch;
|
||||
|
||||
/* Watch out for recursion here. Any routine that calls
|
||||
* kdb_printf will come back through here. And kdb_read
|
||||
|
@ -781,39 +771,38 @@ kdb_printit:
|
|||
if (logging)
|
||||
printk("%s", moreprompt);
|
||||
|
||||
kdb_read(buf1, 2); /* '2' indicates to return
|
||||
* immediately after getting one key. */
|
||||
ch = kdb_getchar();
|
||||
kdb_nextline = 1; /* Really set output line 1 */
|
||||
|
||||
/* empty and reset the buffer: */
|
||||
kdb_buffer[0] = '\0';
|
||||
next_avail = kdb_buffer;
|
||||
size_avail = sizeof(kdb_buffer);
|
||||
if ((buf1[0] == 'q') || (buf1[0] == 'Q')) {
|
||||
if ((ch == 'q') || (ch == 'Q')) {
|
||||
/* user hit q or Q */
|
||||
KDB_FLAG_SET(CMD_INTERRUPT); /* command interrupted */
|
||||
KDB_STATE_CLEAR(PAGER);
|
||||
/* end of command output; back to normal mode */
|
||||
kdb_grepping_flag = 0;
|
||||
kdb_printf("\n");
|
||||
} else if (buf1[0] == ' ') {
|
||||
} else if (ch == ' ') {
|
||||
kdb_printf("\r");
|
||||
suspend_grep = 1; /* for this recursion */
|
||||
} else if (buf1[0] == '\n') {
|
||||
} else if (ch == '\n' || ch == '\r') {
|
||||
kdb_nextline = linecount - 1;
|
||||
kdb_printf("\r");
|
||||
suspend_grep = 1; /* for this recursion */
|
||||
} else if (buf1[0] == '/' && !kdb_grepping_flag) {
|
||||
} else if (ch == '/' && !kdb_grepping_flag) {
|
||||
kdb_printf("\r");
|
||||
kdb_getstr(kdb_grep_string, KDB_GREP_STRLEN,
|
||||
kdbgetenv("SEARCHPROMPT") ?: "search> ");
|
||||
*strchrnul(kdb_grep_string, '\n') = '\0';
|
||||
kdb_grepping_flag += KDB_GREPPING_FLAG_SEARCH;
|
||||
suspend_grep = 1; /* for this recursion */
|
||||
} else if (buf1[0] && buf1[0] != '\n') {
|
||||
/* user hit something other than enter */
|
||||
} else if (ch) {
|
||||
/* user hit something unexpected */
|
||||
suspend_grep = 1; /* for this recursion */
|
||||
if (buf1[0] != '/')
|
||||
if (ch != '/')
|
||||
kdb_printf(
|
||||
"\nOnly 'q', 'Q' or '/' are processed at "
|
||||
"more prompt, input ignored\n");
|
||||
|
|
|
@ -210,6 +210,7 @@ extern void kdb_ps1(const struct task_struct *p);
|
|||
extern void kdb_print_nameval(const char *name, unsigned long val);
|
||||
extern void kdb_send_sig(struct task_struct *p, int sig);
|
||||
extern void kdb_meminfo_proc_show(void);
|
||||
extern char kdb_getchar(void);
|
||||
extern char *kdb_getstr(char *, size_t, const char *);
|
||||
extern void kdb_gdb_state_pass(char *buf);
|
||||
|
||||
|
|
Loading…
Reference in a new issue