1ae2e6c43SIngo Weinhold /*
2ae2e6c43SIngo Weinhold * Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de.
3ae2e6c43SIngo Weinhold * Distributed under the terms of the MIT License.
4ae2e6c43SIngo Weinhold *
5ae2e6c43SIngo Weinhold * Copyright 2002, Manuel J. Petit. All rights reserved.
6ae2e6c43SIngo Weinhold * Distributed under the terms of the NewOS License.
7ae2e6c43SIngo Weinhold */
8ae2e6c43SIngo Weinhold
9ae2e6c43SIngo Weinhold /** Contains the code to interface with a remote GDB */
10ae2e6c43SIngo Weinhold
11ae2e6c43SIngo Weinhold #include "gdb.h"
12ae2e6c43SIngo Weinhold
13ae2e6c43SIngo Weinhold #include <string.h>
14ae2e6c43SIngo Weinhold #include <stdarg.h>
15ae2e6c43SIngo Weinhold #include <stdio.h>
16ae2e6c43SIngo Weinhold
17ae2e6c43SIngo Weinhold #include <ByteOrder.h>
18ae2e6c43SIngo Weinhold
199536ec02SIngo Weinhold #include <arch/debug.h>
20ae2e6c43SIngo Weinhold #include <arch/debug_console.h>
21ae2e6c43SIngo Weinhold #include <debug.h>
2290d46a5cSIngo Weinhold #include <elf.h>
2390d46a5cSIngo Weinhold #include <elf_priv.h>
24ae2e6c43SIngo Weinhold #include <smp.h>
25e50cf876SIngo Weinhold #include <vm/vm.h>
26ae2e6c43SIngo Weinhold
27ae2e6c43SIngo Weinhold
28ae2e6c43SIngo Weinhold enum { INIT = 0, CMDREAD, CKSUM1, CKSUM2, WAITACK, QUIT, GDBSTATES };
29ae2e6c43SIngo Weinhold
30ae2e6c43SIngo Weinhold
31ae2e6c43SIngo Weinhold static char sCommand[512];
32ae2e6c43SIngo Weinhold static int sCommandIndex;
33ae2e6c43SIngo Weinhold static int sCheckSum;
34ae2e6c43SIngo Weinhold
35ae2e6c43SIngo Weinhold static char sReply[512];
36ae2e6c43SIngo Weinhold static char sSafeMemory[512];
37ae2e6c43SIngo Weinhold
38ae2e6c43SIngo Weinhold
39ae2e6c43SIngo Weinhold // utility functions
40ae2e6c43SIngo Weinhold
41ae2e6c43SIngo Weinhold
42ae2e6c43SIngo Weinhold static int
parse_nibble(int input)43ae2e6c43SIngo Weinhold parse_nibble(int input)
44ae2e6c43SIngo Weinhold {
45ae2e6c43SIngo Weinhold int nibble = 0xff;
46ae2e6c43SIngo Weinhold
47ae2e6c43SIngo Weinhold if (input >= '0' && input <= '9')
48ae2e6c43SIngo Weinhold nibble = input - '0';
49ae2e6c43SIngo Weinhold
50ae2e6c43SIngo Weinhold if (input >= 'A' && input <= 'F')
51ae2e6c43SIngo Weinhold nibble = 0x0a + input - 'A';
52ae2e6c43SIngo Weinhold
53ae2e6c43SIngo Weinhold if (input >= 'a' && input <= 'f')
54ae2e6c43SIngo Weinhold nibble = 0x0a + input - 'a';
55ae2e6c43SIngo Weinhold
56ae2e6c43SIngo Weinhold return nibble;
57ae2e6c43SIngo Weinhold }
58ae2e6c43SIngo Weinhold
59ae2e6c43SIngo Weinhold
60ae2e6c43SIngo Weinhold // #pragma mark - GDB protocol
61ae2e6c43SIngo Weinhold
62ae2e6c43SIngo Weinhold
63ae2e6c43SIngo Weinhold static void
gdb_ack(void)64ae2e6c43SIngo Weinhold gdb_ack(void)
65ae2e6c43SIngo Weinhold {
66ae2e6c43SIngo Weinhold arch_debug_serial_putchar('+');
67ae2e6c43SIngo Weinhold }
68ae2e6c43SIngo Weinhold
69ae2e6c43SIngo Weinhold
70ae2e6c43SIngo Weinhold static void
gdb_nak(void)71ae2e6c43SIngo Weinhold gdb_nak(void)
72ae2e6c43SIngo Weinhold {
73ae2e6c43SIngo Weinhold arch_debug_serial_putchar('-');
74ae2e6c43SIngo Weinhold }
75ae2e6c43SIngo Weinhold
76ae2e6c43SIngo Weinhold
77ae2e6c43SIngo Weinhold static void
gdb_resend_reply(void)78ae2e6c43SIngo Weinhold gdb_resend_reply(void)
79ae2e6c43SIngo Weinhold {
80ae2e6c43SIngo Weinhold arch_debug_serial_puts(sReply);
81ae2e6c43SIngo Weinhold }
82ae2e6c43SIngo Weinhold
83ae2e6c43SIngo Weinhold
84ae2e6c43SIngo Weinhold static void
gdb_reply(char const * format,...)85ae2e6c43SIngo Weinhold gdb_reply(char const* format, ...)
86ae2e6c43SIngo Weinhold {
87ae2e6c43SIngo Weinhold int i;
88ae2e6c43SIngo Weinhold int len;
89ae2e6c43SIngo Weinhold int sum;
90ae2e6c43SIngo Weinhold va_list args;
91ae2e6c43SIngo Weinhold
92ae2e6c43SIngo Weinhold va_start(args, format);
93ae2e6c43SIngo Weinhold sReply[0] = '$';
94ae2e6c43SIngo Weinhold vsprintf(sReply + 1, format, args);
95ae2e6c43SIngo Weinhold va_end(args);
96ae2e6c43SIngo Weinhold
97ae2e6c43SIngo Weinhold len = strlen(sReply);
98ae2e6c43SIngo Weinhold sum = 0;
99ae2e6c43SIngo Weinhold for (i = 1; i < len; i++) {
100ae2e6c43SIngo Weinhold sum += sReply[i];
101ae2e6c43SIngo Weinhold }
102ae2e6c43SIngo Weinhold sum %= 256;
103ae2e6c43SIngo Weinhold
104ae2e6c43SIngo Weinhold sprintf(sReply + len, "#%02x", sum);
105ae2e6c43SIngo Weinhold
106ae2e6c43SIngo Weinhold gdb_resend_reply();
107ae2e6c43SIngo Weinhold }
108ae2e6c43SIngo Weinhold
109ae2e6c43SIngo Weinhold
110ae2e6c43SIngo Weinhold static void
gdb_regreply()1119536ec02SIngo Weinhold gdb_regreply()
112ae2e6c43SIngo Weinhold {
113ae2e6c43SIngo Weinhold sReply[0] = '$';
114ae2e6c43SIngo Weinhold
1159536ec02SIngo Weinhold // get registers (architecture specific)
1169536ec02SIngo Weinhold ssize_t bytesWritten = arch_debug_gdb_get_registers(sReply + 1,
1179536ec02SIngo Weinhold sizeof(sReply) - 1);
1189536ec02SIngo Weinhold if (bytesWritten < 0) {
1199536ec02SIngo Weinhold gdb_reply("E01");
1209536ec02SIngo Weinhold return;
1219536ec02SIngo Weinhold }
1229536ec02SIngo Weinhold
1239536ec02SIngo Weinhold // add 1 for the leading '$'
1249536ec02SIngo Weinhold bytesWritten++;
1259536ec02SIngo Weinhold
1269536ec02SIngo Weinhold // compute check sum
1279536ec02SIngo Weinhold int sum = 0;
1289536ec02SIngo Weinhold for (int32 i = 1; i < bytesWritten; i++)
129ae2e6c43SIngo Weinhold sum += sReply[i];
130ae2e6c43SIngo Weinhold sum %= 256;
131ae2e6c43SIngo Weinhold
1329536ec02SIngo Weinhold // print check sum
1339536ec02SIngo Weinhold int result = snprintf(sReply + bytesWritten, sizeof(sReply) - bytesWritten,
1349536ec02SIngo Weinhold "#%02x", sum);
1359536ec02SIngo Weinhold if (result >= (ssize_t)sizeof(sReply) - bytesWritten) {
1369536ec02SIngo Weinhold gdb_reply("E01");
1379536ec02SIngo Weinhold return;
1389536ec02SIngo Weinhold }
139ae2e6c43SIngo Weinhold
140ae2e6c43SIngo Weinhold gdb_resend_reply();
141ae2e6c43SIngo Weinhold }
142ae2e6c43SIngo Weinhold
143ae2e6c43SIngo Weinhold
144ae2e6c43SIngo Weinhold static void
gdb_memreply(char const * bytes,int numbytes)145ae2e6c43SIngo Weinhold gdb_memreply(char const* bytes, int numbytes)
146ae2e6c43SIngo Weinhold {
147ae2e6c43SIngo Weinhold int i;
148ae2e6c43SIngo Weinhold int len;
149ae2e6c43SIngo Weinhold int sum;
150ae2e6c43SIngo Weinhold
151ae2e6c43SIngo Weinhold sReply[0] = '$';
152ae2e6c43SIngo Weinhold for (i = 0; i < numbytes; i++)
153ae2e6c43SIngo Weinhold sprintf(sReply + 1 + 2 * i, "%02x", (uint8)bytes[i]);
154ae2e6c43SIngo Weinhold
155ae2e6c43SIngo Weinhold len = strlen(sReply);
156ae2e6c43SIngo Weinhold sum = 0;
157ae2e6c43SIngo Weinhold for (i = 1; i < len; i++)
158ae2e6c43SIngo Weinhold sum += sReply[i];
159ae2e6c43SIngo Weinhold sum %= 256;
160ae2e6c43SIngo Weinhold
161ae2e6c43SIngo Weinhold sprintf(sReply + len, "#%02x", sum);
162ae2e6c43SIngo Weinhold
163ae2e6c43SIngo Weinhold gdb_resend_reply();
164ae2e6c43SIngo Weinhold }
165ae2e6c43SIngo Weinhold
166ae2e6c43SIngo Weinhold
167ae2e6c43SIngo Weinhold // #pragma mark - checksum verification
168ae2e6c43SIngo Weinhold
169ae2e6c43SIngo Weinhold
170ae2e6c43SIngo Weinhold static int
gdb_verify_checksum(void)171ae2e6c43SIngo Weinhold gdb_verify_checksum(void)
172ae2e6c43SIngo Weinhold {
173ae2e6c43SIngo Weinhold int i;
174ae2e6c43SIngo Weinhold int len;
175ae2e6c43SIngo Weinhold int sum;
176ae2e6c43SIngo Weinhold
177ae2e6c43SIngo Weinhold len = strlen(sCommand);
178ae2e6c43SIngo Weinhold sum = 0;
179ae2e6c43SIngo Weinhold for (i = 0; i < len; i++)
180ae2e6c43SIngo Weinhold sum += sCommand[i];
181ae2e6c43SIngo Weinhold sum %= 256;
182ae2e6c43SIngo Weinhold
183ae2e6c43SIngo Weinhold return (sum == sCheckSum) ? 1 : 0;
184ae2e6c43SIngo Weinhold }
185ae2e6c43SIngo Weinhold
186ae2e6c43SIngo Weinhold
187ae2e6c43SIngo Weinhold // #pragma mark - command parsing
188ae2e6c43SIngo Weinhold
189ae2e6c43SIngo Weinhold
190ae2e6c43SIngo Weinhold static int
gdb_parse_command(void)191ae2e6c43SIngo Weinhold gdb_parse_command(void)
192ae2e6c43SIngo Weinhold {
193ae2e6c43SIngo Weinhold if (!gdb_verify_checksum()) {
194ae2e6c43SIngo Weinhold gdb_nak();
195ae2e6c43SIngo Weinhold return INIT;
196ae2e6c43SIngo Weinhold } else
197ae2e6c43SIngo Weinhold gdb_ack();
198ae2e6c43SIngo Weinhold
199ae2e6c43SIngo Weinhold switch (sCommand[0]) {
20090d46a5cSIngo Weinhold case '?':
20190d46a5cSIngo Weinhold // command '?' is used for retrieving the signal
20290d46a5cSIngo Weinhold // that stopped the program. Fully implemeting
20390d46a5cSIngo Weinhold // this command requires help from the debugger,
20490d46a5cSIngo Weinhold // by now we just fake a SIGKILL
20590d46a5cSIngo Weinhold gdb_reply("S09"); /* SIGKILL = 9 */
20690d46a5cSIngo Weinhold break;
20790d46a5cSIngo Weinhold
208ae2e6c43SIngo Weinhold case 'H':
209c970c6e8SIngo Weinhold // Command H (actually Hct) is used to select
210c970c6e8SIngo Weinhold // the current thread (-1 meaning all threads)
211c970c6e8SIngo Weinhold // We just fake we recognize the the command
212c970c6e8SIngo Weinhold // and send an 'OK' response.
213ae2e6c43SIngo Weinhold gdb_reply("OK");
214ae2e6c43SIngo Weinhold break;
215ae2e6c43SIngo Weinhold
216ae2e6c43SIngo Weinhold case 'q':
217ae2e6c43SIngo Weinhold {
21890d46a5cSIngo Weinhold // query commands
219ae2e6c43SIngo Weinhold
22090d46a5cSIngo Weinhold if (strcmp(sCommand + 1, "Supported") == 0) {
22190d46a5cSIngo Weinhold // get the supported features
22290d46a5cSIngo Weinhold gdb_reply("");
22390d46a5cSIngo Weinhold } else if (strcmp(sCommand + 1, "Offsets") == 0) {
22490d46a5cSIngo Weinhold // get the segment offsets
22590d46a5cSIngo Weinhold elf_image_info* kernelImage = elf_get_kernel_image();
22690d46a5cSIngo Weinhold gdb_reply("Text=%lx;Data=%lx;Bss=%lx",
22790d46a5cSIngo Weinhold kernelImage->text_region.delta,
22890d46a5cSIngo Weinhold kernelImage->data_region.delta,
22990d46a5cSIngo Weinhold kernelImage->data_region.delta);
230ae2e6c43SIngo Weinhold } else
23190d46a5cSIngo Weinhold gdb_reply("");
232777ae2fbSIngo Weinhold
233ae2e6c43SIngo Weinhold break;
234777ae2fbSIngo Weinhold }
235ae2e6c43SIngo Weinhold
23690d46a5cSIngo Weinhold case 'c':
23790d46a5cSIngo Weinhold // continue at address
23890d46a5cSIngo Weinhold // TODO: Parse the address and resume there!
23990d46a5cSIngo Weinhold return QUIT;
240ae2e6c43SIngo Weinhold
241ae2e6c43SIngo Weinhold case 'g':
2429536ec02SIngo Weinhold gdb_regreply();
243ae2e6c43SIngo Weinhold break;
244ae2e6c43SIngo Weinhold
24590d46a5cSIngo Weinhold case 'G':
24690d46a5cSIngo Weinhold // write registers
24790d46a5cSIngo Weinhold // TODO: Implement!
24890d46a5cSIngo Weinhold gdb_reply("E01");
24990d46a5cSIngo Weinhold break;
25090d46a5cSIngo Weinhold
25190d46a5cSIngo Weinhold
252ae2e6c43SIngo Weinhold case 'm':
253ae2e6c43SIngo Weinhold {
254ae2e6c43SIngo Weinhold char* ptr;
255*4be4fc6bSAlex Smith addr_t address;
256*4be4fc6bSAlex Smith size_t len;
257ae2e6c43SIngo Weinhold
258c970c6e8SIngo Weinhold // The 'm' command has the form mAAA,LLL
259c970c6e8SIngo Weinhold // where AAA is the address and LLL is the
260c970c6e8SIngo Weinhold // number of bytes.
261ae2e6c43SIngo Weinhold ptr = sCommand + 1;
262ae2e6c43SIngo Weinhold address = 0;
263ae2e6c43SIngo Weinhold len = 0;
264ae2e6c43SIngo Weinhold while (ptr && *ptr && (*ptr != ',')) {
265ae2e6c43SIngo Weinhold address <<= 4;
266ae2e6c43SIngo Weinhold address += parse_nibble(*ptr);
267ae2e6c43SIngo Weinhold ptr += 1;
268ae2e6c43SIngo Weinhold }
269ae2e6c43SIngo Weinhold if (*ptr == ',')
270ae2e6c43SIngo Weinhold ptr += 1;
271ae2e6c43SIngo Weinhold
272ae2e6c43SIngo Weinhold while (ptr && *ptr) {
273ae2e6c43SIngo Weinhold len <<= 4;
274ae2e6c43SIngo Weinhold len += parse_nibble(*ptr);
275ae2e6c43SIngo Weinhold ptr += 1;
276ae2e6c43SIngo Weinhold }
277ae2e6c43SIngo Weinhold
278ae2e6c43SIngo Weinhold if (len > 128)
279ae2e6c43SIngo Weinhold len = 128;
280ae2e6c43SIngo Weinhold
281c970c6e8SIngo Weinhold // We cannot directly access the requested memory
282c970c6e8SIngo Weinhold // for gdb may be trying to access an stray pointer
283c970c6e8SIngo Weinhold // We copy the memory to a safe buffer using
284ea2abd11SIngo Weinhold // the bulletproof debug_memcpy().
285c3676b54SIngo Weinhold if (debug_memcpy(B_CURRENT_TEAM, sSafeMemory, (char*)address, len)
286c3676b54SIngo Weinhold < 0) {
287ae2e6c43SIngo Weinhold gdb_reply("E02");
288c3676b54SIngo Weinhold } else
289ae2e6c43SIngo Weinhold gdb_memreply(sSafeMemory, len);
290777ae2fbSIngo Weinhold
291ae2e6c43SIngo Weinhold break;
292777ae2fbSIngo Weinhold }
293ae2e6c43SIngo Weinhold
29490d46a5cSIngo Weinhold case 'D':
29590d46a5cSIngo Weinhold // detach
29690d46a5cSIngo Weinhold return QUIT;
29790d46a5cSIngo Weinhold
298ae2e6c43SIngo Weinhold case 'k':
299c970c6e8SIngo Weinhold // Command 'k' actual semantics is 'kill the damn thing'.
300c970c6e8SIngo Weinhold // However gdb sends that command when you disconnect
301c970c6e8SIngo Weinhold // from a debug session. I guess that 'kill' for the
302c970c6e8SIngo Weinhold // kernel would map to reboot... however that's a
303c970c6e8SIngo Weinhold // a very mean thing to do, instead we just quit
304c970c6e8SIngo Weinhold // the gdb state machine and fallback to the regular
305c970c6e8SIngo Weinhold // kernel debugger command prompt.
306ae2e6c43SIngo Weinhold return QUIT;
307ae2e6c43SIngo Weinhold
30890d46a5cSIngo Weinhold case 's':
30990d46a5cSIngo Weinhold // "step" -- resume (?) at address
31090d46a5cSIngo Weinhold // TODO: Implement!
311ae2e6c43SIngo Weinhold gdb_reply("E01");
312ae2e6c43SIngo Weinhold break;
31390d46a5cSIngo Weinhold
31490d46a5cSIngo Weinhold default:
31590d46a5cSIngo Weinhold gdb_reply("");
31690d46a5cSIngo Weinhold break;
317ae2e6c43SIngo Weinhold }
318ae2e6c43SIngo Weinhold
319ae2e6c43SIngo Weinhold return WAITACK;
320ae2e6c43SIngo Weinhold }
321ae2e6c43SIngo Weinhold
322ae2e6c43SIngo Weinhold
323ae2e6c43SIngo Weinhold // #pragma mark - protocol state machine
324ae2e6c43SIngo Weinhold
325ae2e6c43SIngo Weinhold
326ae2e6c43SIngo Weinhold static int
gdb_init_handler(int input)327ae2e6c43SIngo Weinhold gdb_init_handler(int input)
328ae2e6c43SIngo Weinhold {
329ae2e6c43SIngo Weinhold switch (input) {
330ae2e6c43SIngo Weinhold case '$':
331ae2e6c43SIngo Weinhold memset(sCommand, 0, sizeof(sCommand));
332ae2e6c43SIngo Weinhold sCommandIndex = 0;
333ae2e6c43SIngo Weinhold return CMDREAD;
334ae2e6c43SIngo Weinhold
335ae2e6c43SIngo Weinhold default:
336ae2e6c43SIngo Weinhold #if 0
337ae2e6c43SIngo Weinhold gdb_nak();
338ae2e6c43SIngo Weinhold #else
339c970c6e8SIngo Weinhold // looks to me like we should send
340c970c6e8SIngo Weinhold // a NAK here but it kinda works
341c970c6e8SIngo Weinhold // better if we just gobble all
342c970c6e8SIngo Weinhold // junk chars silently
343ae2e6c43SIngo Weinhold #endif
344ae2e6c43SIngo Weinhold return INIT;
345ae2e6c43SIngo Weinhold }
346ae2e6c43SIngo Weinhold }
347ae2e6c43SIngo Weinhold
348ae2e6c43SIngo Weinhold
349ae2e6c43SIngo Weinhold static int
gdb_cmdread_handler(int input)350ae2e6c43SIngo Weinhold gdb_cmdread_handler(int input)
351ae2e6c43SIngo Weinhold {
352ae2e6c43SIngo Weinhold switch (input) {
353ae2e6c43SIngo Weinhold case '#':
354ae2e6c43SIngo Weinhold return CKSUM1;
355ae2e6c43SIngo Weinhold
356ae2e6c43SIngo Weinhold default:
357ae2e6c43SIngo Weinhold sCommand[sCommandIndex] = input;
358ae2e6c43SIngo Weinhold sCommandIndex += 1;
359ae2e6c43SIngo Weinhold return CMDREAD;
360ae2e6c43SIngo Weinhold }
361ae2e6c43SIngo Weinhold }
362ae2e6c43SIngo Weinhold
363ae2e6c43SIngo Weinhold
364ae2e6c43SIngo Weinhold static int
gdb_cksum1_handler(int input)365ae2e6c43SIngo Weinhold gdb_cksum1_handler(int input)
366ae2e6c43SIngo Weinhold {
367ae2e6c43SIngo Weinhold int nibble = parse_nibble(input);
368ae2e6c43SIngo Weinhold
369ae2e6c43SIngo Weinhold if (nibble == 0xff) {
370ae2e6c43SIngo Weinhold #if 0
371ae2e6c43SIngo Weinhold gdb_nak();
372ae2e6c43SIngo Weinhold return INIT;
373ae2e6c43SIngo Weinhold #else
374c970c6e8SIngo Weinhold // looks to me like we should send
375c970c6e8SIngo Weinhold // a NAK here but it kinda works
376c970c6e8SIngo Weinhold // better if we just gobble all
377c970c6e8SIngo Weinhold // junk chars silently
378ae2e6c43SIngo Weinhold #endif
379ae2e6c43SIngo Weinhold }
380ae2e6c43SIngo Weinhold
381ae2e6c43SIngo Weinhold sCheckSum = nibble << 4;
382ae2e6c43SIngo Weinhold
383ae2e6c43SIngo Weinhold return CKSUM2;
384ae2e6c43SIngo Weinhold }
385ae2e6c43SIngo Weinhold
386ae2e6c43SIngo Weinhold
387ae2e6c43SIngo Weinhold static int
gdb_cksum2_handler(int input)388ae2e6c43SIngo Weinhold gdb_cksum2_handler(int input)
389ae2e6c43SIngo Weinhold {
390ae2e6c43SIngo Weinhold int nibble = parse_nibble(input);
391ae2e6c43SIngo Weinhold
392ae2e6c43SIngo Weinhold if (nibble == 0xff) {
393ae2e6c43SIngo Weinhold #if 0
394ae2e6c43SIngo Weinhold gdb_nak();
395ae2e6c43SIngo Weinhold return INIT;
396ae2e6c43SIngo Weinhold #else
397c970c6e8SIngo Weinhold // looks to me like we should send
398c970c6e8SIngo Weinhold // a NAK here but it kinda works
399c970c6e8SIngo Weinhold // better if we just gobble all
400c970c6e8SIngo Weinhold // junk chars silently
401ae2e6c43SIngo Weinhold #endif
402ae2e6c43SIngo Weinhold }
403ae2e6c43SIngo Weinhold
404ae2e6c43SIngo Weinhold sCheckSum += nibble;
405ae2e6c43SIngo Weinhold
406ae2e6c43SIngo Weinhold return gdb_parse_command();
407ae2e6c43SIngo Weinhold }
408ae2e6c43SIngo Weinhold
409ae2e6c43SIngo Weinhold
410ae2e6c43SIngo Weinhold static int
gdb_waitack_handler(int input)411ae2e6c43SIngo Weinhold gdb_waitack_handler(int input)
412ae2e6c43SIngo Weinhold {
413ae2e6c43SIngo Weinhold switch (input) {
414ae2e6c43SIngo Weinhold case '+':
415ae2e6c43SIngo Weinhold return INIT;
416ae2e6c43SIngo Weinhold case '-':
417ae2e6c43SIngo Weinhold gdb_resend_reply();
418ae2e6c43SIngo Weinhold return WAITACK;
419ae2e6c43SIngo Weinhold
420ae2e6c43SIngo Weinhold default:
421c970c6e8SIngo Weinhold // looks like gdb and us are out of sync,
422c970c6e8SIngo Weinhold // send a NAK and retry from INIT state.
423ae2e6c43SIngo Weinhold gdb_nak();
424ae2e6c43SIngo Weinhold return INIT;
425ae2e6c43SIngo Weinhold }
426ae2e6c43SIngo Weinhold }
427ae2e6c43SIngo Weinhold
428ae2e6c43SIngo Weinhold
429ae2e6c43SIngo Weinhold static int
gdb_quit_handler(int input)430ae2e6c43SIngo Weinhold gdb_quit_handler(int input)
431ae2e6c43SIngo Weinhold {
432ae2e6c43SIngo Weinhold (void)(input);
433ae2e6c43SIngo Weinhold
434c970c6e8SIngo Weinhold // actually we should never be here
435ae2e6c43SIngo Weinhold return QUIT;
436ae2e6c43SIngo Weinhold }
437ae2e6c43SIngo Weinhold
438ae2e6c43SIngo Weinhold
439ae2e6c43SIngo Weinhold static int (*dispatch_table[GDBSTATES])(int) = {
440ae2e6c43SIngo Weinhold &gdb_init_handler,
441ae2e6c43SIngo Weinhold &gdb_cmdread_handler,
442ae2e6c43SIngo Weinhold &gdb_cksum1_handler,
443ae2e6c43SIngo Weinhold &gdb_cksum2_handler,
444ae2e6c43SIngo Weinhold &gdb_waitack_handler,
445ae2e6c43SIngo Weinhold &gdb_quit_handler
446ae2e6c43SIngo Weinhold };
447ae2e6c43SIngo Weinhold
448ae2e6c43SIngo Weinhold
449ae2e6c43SIngo Weinhold static int
gdb_state_dispatch(int curr,int input)450ae2e6c43SIngo Weinhold gdb_state_dispatch(int curr, int input)
451ae2e6c43SIngo Weinhold {
452ae2e6c43SIngo Weinhold if (curr < INIT || curr >= GDBSTATES)
453ae2e6c43SIngo Weinhold return QUIT;
454ae2e6c43SIngo Weinhold
455ae2e6c43SIngo Weinhold return dispatch_table[curr](input);
456ae2e6c43SIngo Weinhold }
457ae2e6c43SIngo Weinhold
458ae2e6c43SIngo Weinhold
459ae2e6c43SIngo Weinhold static int
gdb_state_machine(void)460ae2e6c43SIngo Weinhold gdb_state_machine(void)
461ae2e6c43SIngo Weinhold {
462ae2e6c43SIngo Weinhold int state = INIT;
463ae2e6c43SIngo Weinhold int c;
464ae2e6c43SIngo Weinhold
465ae2e6c43SIngo Weinhold while (state != QUIT) {
466ae2e6c43SIngo Weinhold c = arch_debug_serial_getchar();
467ae2e6c43SIngo Weinhold state = gdb_state_dispatch(state, c);
468ae2e6c43SIngo Weinhold }
469ae2e6c43SIngo Weinhold
470ae2e6c43SIngo Weinhold return 0;
471ae2e6c43SIngo Weinhold }
472ae2e6c43SIngo Weinhold
473ae2e6c43SIngo Weinhold
474ae2e6c43SIngo Weinhold // #pragma mark -
475ae2e6c43SIngo Weinhold
476ae2e6c43SIngo Weinhold
477ae2e6c43SIngo Weinhold int
cmd_gdb(int argc,char ** argv)478ae2e6c43SIngo Weinhold cmd_gdb(int argc, char** argv)
479ae2e6c43SIngo Weinhold {
480ae2e6c43SIngo Weinhold (void)(argc);
481ae2e6c43SIngo Weinhold (void)(argv);
482ae2e6c43SIngo Weinhold
483ae2e6c43SIngo Weinhold return gdb_state_machine();
484ae2e6c43SIngo Weinhold }
485