Commit f679c4985bb2e7de9d39a5d40b6031361c4ad861
1 parent
3bdb65ec95
Exists in
master
and in
38 other branches
kdb,kgdb: Implement switch and pass buffer from kdb -> gdb
When switching from kdb mode to kgdb mode packets were getting lost depending on the size of the fifo queue of the serial chip. When gdb initially connects if it is in kdb mode it should entirely send any character buffer over to the gdbstub when switching connections. Previously kdb was zero'ing out the character buffer and this could lead to gdb failing to connect at all, or a lengthy pause could occur on the initial connect. Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Showing 4 changed files with 29 additions and 21 deletions Side-by-side Diff
kernel/debug/gdbstub.c
... | ... | @@ -42,6 +42,8 @@ |
42 | 42 | /* Our I/O buffers. */ |
43 | 43 | static char remcom_in_buffer[BUFMAX]; |
44 | 44 | static char remcom_out_buffer[BUFMAX]; |
45 | +static int gdbstub_use_prev_in_buf; | |
46 | +static int gdbstub_prev_in_buf_pos; | |
45 | 47 | |
46 | 48 | /* Storage for the registers, in GDB format. */ |
47 | 49 | static unsigned long gdb_regs[(NUMREGBYTES + |
... | ... | @@ -58,6 +60,13 @@ |
58 | 60 | int ret = -1; |
59 | 61 | int i; |
60 | 62 | |
63 | + if (unlikely(gdbstub_use_prev_in_buf)) { | |
64 | + if (gdbstub_prev_in_buf_pos < gdbstub_use_prev_in_buf) | |
65 | + return remcom_in_buffer[gdbstub_prev_in_buf_pos++]; | |
66 | + else | |
67 | + gdbstub_use_prev_in_buf = 0; | |
68 | + } | |
69 | + | |
61 | 70 | /* poll any additional I/O interfaces that are defined */ |
62 | 71 | while (ret < 0) |
63 | 72 | for (i = 0; kdb_poll_funcs[i] != NULL; i++) { |
... | ... | @@ -109,7 +118,6 @@ |
109 | 118 | buffer[count] = ch; |
110 | 119 | count = count + 1; |
111 | 120 | } |
112 | - buffer[count] = 0; | |
113 | 121 | |
114 | 122 | if (ch == '#') { |
115 | 123 | xmitcsum = hex_to_bin(gdbstub_read_wait()) << 4; |
... | ... | @@ -124,6 +132,7 @@ |
124 | 132 | if (dbg_io_ops->flush) |
125 | 133 | dbg_io_ops->flush(); |
126 | 134 | } |
135 | + buffer[count] = 0; | |
127 | 136 | } while (checksum != xmitcsum); |
128 | 137 | } |
129 | 138 | |
... | ... | @@ -1082,12 +1091,11 @@ |
1082 | 1091 | case 'c': |
1083 | 1092 | strcpy(remcom_in_buffer, cmd); |
1084 | 1093 | return 0; |
1085 | - case '?': | |
1086 | - gdb_cmd_status(ks); | |
1087 | - break; | |
1088 | - case '\0': | |
1089 | - strcpy(remcom_out_buffer, ""); | |
1090 | - break; | |
1094 | + case '$': | |
1095 | + strcpy(remcom_in_buffer, cmd); | |
1096 | + gdbstub_use_prev_in_buf = strlen(remcom_in_buffer); | |
1097 | + gdbstub_prev_in_buf_pos = 0; | |
1098 | + return 0; | |
1091 | 1099 | } |
1092 | 1100 | dbg_io_ops->write_char('+'); |
1093 | 1101 | put_packet(remcom_out_buffer); |
kernel/debug/kdb/kdb_debugger.c
... | ... | @@ -30,6 +30,8 @@ |
30 | 30 | int kdb_poll_idx = 1; |
31 | 31 | EXPORT_SYMBOL_GPL(kdb_poll_idx); |
32 | 32 | |
33 | +static struct kgdb_state *kdb_ks; | |
34 | + | |
33 | 35 | int kdb_stub(struct kgdb_state *ks) |
34 | 36 | { |
35 | 37 | int error = 0; |
... | ... | @@ -39,6 +41,7 @@ |
39 | 41 | kdb_dbtrap_t db_result = KDB_DB_NOBPT; |
40 | 42 | int i; |
41 | 43 | |
44 | + kdb_ks = ks; | |
42 | 45 | if (KDB_STATE(REENTRY)) { |
43 | 46 | reason = KDB_REASON_SWITCH; |
44 | 47 | KDB_STATE_CLEAR(REENTRY); |
... | ... | @@ -124,16 +127,6 @@ |
124 | 127 | kdbnearsym_cleanup(); |
125 | 128 | if (error == KDB_CMD_KGDB) { |
126 | 129 | if (KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2)) { |
127 | - /* | |
128 | - * This inteface glue which allows kdb to transition in into | |
129 | - * the gdb stub. In order to do this the '?' or '' gdb serial | |
130 | - * packet response is processed here. And then control is | |
131 | - * passed to the gdbstub. | |
132 | - */ | |
133 | - if (KDB_STATE(DOING_KGDB)) | |
134 | - gdbstub_state(ks, "?"); | |
135 | - else | |
136 | - gdbstub_state(ks, ""); | |
137 | 130 | KDB_STATE_CLEAR(DOING_KGDB); |
138 | 131 | KDB_STATE_CLEAR(DOING_KGDB2); |
139 | 132 | } |
... | ... | @@ -164,5 +157,10 @@ |
164 | 157 | return DBG_SWITCH_CPU_EVENT; |
165 | 158 | } |
166 | 159 | return kgdb_info[ks->cpu].ret_state; |
160 | +} | |
161 | + | |
162 | +void kdb_gdb_state_pass(char *buf) | |
163 | +{ | |
164 | + gdbstub_state(kdb_ks, buf); | |
167 | 165 | } |
kernel/debug/kdb/kdb_io.c
... | ... | @@ -35,8 +35,8 @@ |
35 | 35 | { |
36 | 36 | int slen = strlen(buffer); |
37 | 37 | if (strncmp(buffer, "$?#3f", slen) != 0 && |
38 | - strncmp(buffer, "$qSupported#37", slen) != 0 && | |
39 | - strncmp(buffer, "+$qSupported#37", slen) != 0) { | |
38 | + strncmp(buffer, "$qSupported", slen) != 0 && | |
39 | + strncmp(buffer, "+$qSupported", slen) != 0) { | |
40 | 40 | KDB_STATE_SET(KGDB_TRANS); |
41 | 41 | kdb_printf("%s", buffer); |
42 | 42 | } |
43 | 43 | |
... | ... | @@ -390,12 +390,14 @@ |
390 | 390 | /* Special escape to kgdb */ |
391 | 391 | if (lastchar - buffer >= 5 && |
392 | 392 | strcmp(lastchar - 5, "$?#3f") == 0) { |
393 | + kdb_gdb_state_pass(lastchar - 5); | |
393 | 394 | strcpy(buffer, "kgdb"); |
394 | 395 | KDB_STATE_SET(DOING_KGDB); |
395 | 396 | return buffer; |
396 | 397 | } |
397 | - if (lastchar - buffer >= 14 && | |
398 | - strcmp(lastchar - 14, "$qSupported#37") == 0) { | |
398 | + if (lastchar - buffer >= 11 && | |
399 | + strcmp(lastchar - 11, "$qSupported") == 0) { | |
400 | + kdb_gdb_state_pass(lastchar - 11); | |
399 | 401 | strcpy(buffer, "kgdb"); |
400 | 402 | KDB_STATE_SET(DOING_KGDB2); |
401 | 403 | return buffer; |
kernel/debug/kdb/kdb_private.h
... | ... | @@ -218,6 +218,7 @@ |
218 | 218 | extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info); |
219 | 219 | extern void kdb_meminfo_proc_show(void); |
220 | 220 | extern char *kdb_getstr(char *, size_t, char *); |
221 | +extern void kdb_gdb_state_pass(char *buf); | |
221 | 222 | |
222 | 223 | /* Defines for kdb_symbol_print */ |
223 | 224 | #define KDB_SP_SPACEB 0x0001 /* Space before string */ |