xref: /haiku/src/system/kernel/debug/gdb.cpp (revision 25a7b01d15612846f332751841da3579db313082)
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