xref: /haiku/src/system/kernel/debug/gdb.cpp (revision 777ae2fbb51bbc1b6d0950bd17d9d104e4bcc4cc)
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 
19ae2e6c43SIngo Weinhold #include <arch/debug_console.h>
20ae2e6c43SIngo Weinhold #include <debug.h>
21ae2e6c43SIngo Weinhold #include <smp.h>
22ae2e6c43SIngo Weinhold #include <vm.h>
23ae2e6c43SIngo Weinhold 
24ae2e6c43SIngo Weinhold 
25ae2e6c43SIngo Weinhold enum { INIT = 0, CMDREAD, CKSUM1, CKSUM2, WAITACK, QUIT, GDBSTATES };
26ae2e6c43SIngo Weinhold 
27ae2e6c43SIngo Weinhold 
28ae2e6c43SIngo Weinhold static char sCommand[512];
29ae2e6c43SIngo Weinhold static int sCommandIndex;
30ae2e6c43SIngo Weinhold static int sCheckSum;
31ae2e6c43SIngo Weinhold 
32ae2e6c43SIngo Weinhold static char sReply[512];
33ae2e6c43SIngo Weinhold static char sSafeMemory[512];
34ae2e6c43SIngo Weinhold 
35ae2e6c43SIngo Weinhold 
36ae2e6c43SIngo Weinhold // utility functions
37ae2e6c43SIngo Weinhold 
38ae2e6c43SIngo Weinhold 
39ae2e6c43SIngo Weinhold static int
40ae2e6c43SIngo Weinhold parse_nibble(int input)
41ae2e6c43SIngo Weinhold {
42ae2e6c43SIngo Weinhold 	int nibble = 0xff;
43ae2e6c43SIngo Weinhold 
44ae2e6c43SIngo Weinhold 	if (input >= '0' && input <= '9')
45ae2e6c43SIngo Weinhold 		nibble = input - '0';
46ae2e6c43SIngo Weinhold 
47ae2e6c43SIngo Weinhold 	if (input >= 'A' && input <= 'F')
48ae2e6c43SIngo Weinhold 		nibble = 0x0a + input - 'A';
49ae2e6c43SIngo Weinhold 
50ae2e6c43SIngo Weinhold 	if (input >= 'a' && input <= 'f')
51ae2e6c43SIngo Weinhold 		nibble = 0x0a + input - 'a';
52ae2e6c43SIngo Weinhold 
53ae2e6c43SIngo Weinhold 	return nibble;
54ae2e6c43SIngo Weinhold }
55ae2e6c43SIngo Weinhold 
56ae2e6c43SIngo Weinhold 
57ae2e6c43SIngo Weinhold //	#pragma mark - GDB protocol
58ae2e6c43SIngo Weinhold 
59ae2e6c43SIngo Weinhold 
60ae2e6c43SIngo Weinhold static void
61ae2e6c43SIngo Weinhold gdb_ack(void)
62ae2e6c43SIngo Weinhold {
63ae2e6c43SIngo Weinhold 	arch_debug_serial_putchar('+');
64ae2e6c43SIngo Weinhold }
65ae2e6c43SIngo Weinhold 
66ae2e6c43SIngo Weinhold 
67ae2e6c43SIngo Weinhold static void
68ae2e6c43SIngo Weinhold gdb_nak(void)
69ae2e6c43SIngo Weinhold {
70ae2e6c43SIngo Weinhold 	arch_debug_serial_putchar('-');
71ae2e6c43SIngo Weinhold }
72ae2e6c43SIngo Weinhold 
73ae2e6c43SIngo Weinhold 
74ae2e6c43SIngo Weinhold static void
75ae2e6c43SIngo Weinhold gdb_resend_reply(void)
76ae2e6c43SIngo Weinhold {
77ae2e6c43SIngo Weinhold 	arch_debug_serial_puts(sReply);
78ae2e6c43SIngo Weinhold }
79ae2e6c43SIngo Weinhold 
80ae2e6c43SIngo Weinhold 
81ae2e6c43SIngo Weinhold static void
82ae2e6c43SIngo Weinhold gdb_reply(char const* format, ...)
83ae2e6c43SIngo Weinhold {
84ae2e6c43SIngo Weinhold 	int i;
85ae2e6c43SIngo Weinhold 	int len;
86ae2e6c43SIngo Weinhold 	int sum;
87ae2e6c43SIngo Weinhold 	va_list args;
88ae2e6c43SIngo Weinhold 
89ae2e6c43SIngo Weinhold 	va_start(args, format);
90ae2e6c43SIngo Weinhold 	sReply[0] = '$';
91ae2e6c43SIngo Weinhold 	vsprintf(sReply + 1, format, args);
92ae2e6c43SIngo Weinhold 	va_end(args);
93ae2e6c43SIngo Weinhold 
94ae2e6c43SIngo Weinhold 	len = strlen(sReply);
95ae2e6c43SIngo Weinhold 	sum = 0;
96ae2e6c43SIngo Weinhold 	for (i = 1; i < len; i++) {
97ae2e6c43SIngo Weinhold 		sum += sReply[i];
98ae2e6c43SIngo Weinhold 	}
99ae2e6c43SIngo Weinhold 	sum %= 256;
100ae2e6c43SIngo Weinhold 
101ae2e6c43SIngo Weinhold 	sprintf(sReply + len, "#%02x", sum);
102ae2e6c43SIngo Weinhold 
103ae2e6c43SIngo Weinhold 	gdb_resend_reply();
104ae2e6c43SIngo Weinhold }
105ae2e6c43SIngo Weinhold 
106ae2e6c43SIngo Weinhold 
107ae2e6c43SIngo Weinhold static void
108ae2e6c43SIngo Weinhold gdb_regreply(int const* regs, int numregs)
109ae2e6c43SIngo Weinhold {
110ae2e6c43SIngo Weinhold 	int i;
111ae2e6c43SIngo Weinhold 	int len;
112ae2e6c43SIngo Weinhold 	int sum;
113ae2e6c43SIngo Weinhold 
114ae2e6c43SIngo Weinhold 	sReply[0] = '$';
115ae2e6c43SIngo Weinhold 	for (i = 0; i < numregs; i++)
116ae2e6c43SIngo Weinhold 		sprintf(sReply + 1 + 8 * i, "%08lx", B_HOST_TO_BENDIAN_INT32(regs[i]));
117ae2e6c43SIngo Weinhold 
118ae2e6c43SIngo Weinhold 	len = strlen(sReply);
119ae2e6c43SIngo Weinhold 	sum = 0;
120ae2e6c43SIngo Weinhold 	for (i = 1; i < len; i++)
121ae2e6c43SIngo Weinhold 		sum += sReply[i];
122ae2e6c43SIngo Weinhold 	sum %= 256;
123ae2e6c43SIngo Weinhold 
124ae2e6c43SIngo Weinhold 	sprintf(sReply + len, "#%02x", sum);
125ae2e6c43SIngo Weinhold 
126ae2e6c43SIngo Weinhold 	gdb_resend_reply();
127ae2e6c43SIngo Weinhold }
128ae2e6c43SIngo Weinhold 
129ae2e6c43SIngo Weinhold 
130ae2e6c43SIngo Weinhold static void
131ae2e6c43SIngo Weinhold gdb_memreply(char const* bytes, int numbytes)
132ae2e6c43SIngo Weinhold {
133ae2e6c43SIngo Weinhold 	int i;
134ae2e6c43SIngo Weinhold 	int len;
135ae2e6c43SIngo Weinhold 	int sum;
136ae2e6c43SIngo Weinhold 
137ae2e6c43SIngo Weinhold 	sReply[0] = '$';
138ae2e6c43SIngo Weinhold 	for (i = 0; i < numbytes; i++)
139ae2e6c43SIngo Weinhold 		sprintf(sReply + 1 + 2 * i, "%02x", (uint8)bytes[i]);
140ae2e6c43SIngo Weinhold 
141ae2e6c43SIngo Weinhold 	len = strlen(sReply);
142ae2e6c43SIngo Weinhold 	sum = 0;
143ae2e6c43SIngo Weinhold 	for (i = 1; i < len; i++)
144ae2e6c43SIngo Weinhold 		sum += sReply[i];
145ae2e6c43SIngo Weinhold 	sum %= 256;
146ae2e6c43SIngo Weinhold 
147ae2e6c43SIngo Weinhold 	sprintf(sReply + len, "#%02x", sum);
148ae2e6c43SIngo Weinhold 
149ae2e6c43SIngo Weinhold 	gdb_resend_reply();
150ae2e6c43SIngo Weinhold }
151ae2e6c43SIngo Weinhold 
152ae2e6c43SIngo Weinhold 
153ae2e6c43SIngo Weinhold //	#pragma mark - checksum verification
154ae2e6c43SIngo Weinhold 
155ae2e6c43SIngo Weinhold 
156ae2e6c43SIngo Weinhold static int
157ae2e6c43SIngo Weinhold gdb_verify_checksum(void)
158ae2e6c43SIngo Weinhold {
159ae2e6c43SIngo Weinhold 	int i;
160ae2e6c43SIngo Weinhold 	int len;
161ae2e6c43SIngo Weinhold 	int sum;
162ae2e6c43SIngo Weinhold 
163ae2e6c43SIngo Weinhold 	len = strlen(sCommand);
164ae2e6c43SIngo Weinhold 	sum = 0;
165ae2e6c43SIngo Weinhold 	for (i = 0; i < len; i++)
166ae2e6c43SIngo Weinhold 		sum += sCommand[i];
167ae2e6c43SIngo Weinhold 	sum %= 256;
168ae2e6c43SIngo Weinhold 
169ae2e6c43SIngo Weinhold 	return (sum == sCheckSum) ? 1 : 0;
170ae2e6c43SIngo Weinhold }
171ae2e6c43SIngo Weinhold 
172ae2e6c43SIngo Weinhold 
173ae2e6c43SIngo Weinhold //	#pragma mark - command parsing
174ae2e6c43SIngo Weinhold 
175ae2e6c43SIngo Weinhold 
176ae2e6c43SIngo Weinhold static int
177ae2e6c43SIngo Weinhold gdb_parse_command(void)
178ae2e6c43SIngo Weinhold {
179ae2e6c43SIngo Weinhold 	if (!gdb_verify_checksum()) {
180ae2e6c43SIngo Weinhold 		gdb_nak();
181ae2e6c43SIngo Weinhold 		return INIT;
182ae2e6c43SIngo Weinhold 	} else
183ae2e6c43SIngo Weinhold 		gdb_ack();
184ae2e6c43SIngo Weinhold 
185ae2e6c43SIngo Weinhold 	switch (sCommand[0]) {
186ae2e6c43SIngo Weinhold 		case 'H':
187c970c6e8SIngo Weinhold 			// Command H (actually Hct) is used to select
188c970c6e8SIngo Weinhold 			// the current thread (-1 meaning all threads)
189c970c6e8SIngo Weinhold 			// We just fake we recognize the the command
190c970c6e8SIngo Weinhold 			// and send an 'OK' response.
191ae2e6c43SIngo Weinhold 			gdb_reply("OK");
192ae2e6c43SIngo Weinhold 			break;
193ae2e6c43SIngo Weinhold 
194ae2e6c43SIngo Weinhold 		case 'q':
195ae2e6c43SIngo Weinhold 		{
196ae2e6c43SIngo Weinhold 			extern unsigned __data_start;
197ae2e6c43SIngo Weinhold 			extern unsigned __bss_start;
198ae2e6c43SIngo Weinhold 
199c970c6e8SIngo Weinhold 			// There are several q commands:
200c970c6e8SIngo Weinhold 			//
201c970c6e8SIngo Weinhold 			//     qXXXX        Request info about XXXX.
202c970c6e8SIngo Weinhold 			//     QXXXX=yyyy   Set value of XXXX to yyyy.
203c970c6e8SIngo Weinhold 			//     qOffsets     Get segment offsets
204c970c6e8SIngo Weinhold 			//
205c970c6e8SIngo Weinhold 			// Currently we only support the 'qOffsets'
206c970c6e8SIngo Weinhold 			// form.
207c970c6e8SIngo Weinhold 			//
208c970c6e8SIngo Weinhold 			// *Note* that we actually have to lie,
209c970c6e8SIngo Weinhold 			// At first thought looks like we should
210c970c6e8SIngo Weinhold 			// return '_start', '__data_start' &
211c970c6e8SIngo Weinhold 			// '__bss_start', however gdb gets
212c970c6e8SIngo Weinhold 			// confused because the kernel link script
213c970c6e8SIngo Weinhold 			// pre-links at 0x80000000. To keep gdb
214c970c6e8SIngo Weinhold 			// gdb happy we just substract that amount.
215ae2e6c43SIngo Weinhold 			if (strcmp(sCommand + 1, "Offsets") == 0) {
216ae2e6c43SIngo Weinhold 				gdb_reply("Text=%x;Data=%x;Bss=%x", 0,
217ae2e6c43SIngo Weinhold 					((unsigned)(&__data_start)) - 0x80000000,
218ae2e6c43SIngo Weinhold 					((unsigned)(&__bss_start)) - 0x80000000);
219ae2e6c43SIngo Weinhold 			} else
220ae2e6c43SIngo Weinhold 				gdb_reply("ENS");
221*777ae2fbSIngo Weinhold 
222ae2e6c43SIngo Weinhold 			break;
223*777ae2fbSIngo Weinhold 		}
224ae2e6c43SIngo Weinhold 
225ae2e6c43SIngo Weinhold 		case '?':
226c970c6e8SIngo Weinhold 			// command '?' is used for retrieving the signal
227c970c6e8SIngo Weinhold 			// that stopped the program. Fully implemeting
228c970c6e8SIngo Weinhold 			// this command requires help from the debugger,
229c970c6e8SIngo Weinhold 			// by now we just fake a SIGKILL
230ae2e6c43SIngo Weinhold 			gdb_reply("S09");	/* SIGKILL = 9 */
231ae2e6c43SIngo Weinhold 			break;
232ae2e6c43SIngo Weinhold 
233ae2e6c43SIngo Weinhold 		case 'g':
234ae2e6c43SIngo Weinhold 		{
235ae2e6c43SIngo Weinhold 			int cpu;
236ae2e6c43SIngo Weinhold 
237c970c6e8SIngo Weinhold 			// command 'g' is used for reading the register
238c970c6e8SIngo Weinhold 			// file. Faked by now.
239c970c6e8SIngo Weinhold 			//
240c970c6e8SIngo Weinhold 			// For x86 the register order is:
241c970c6e8SIngo Weinhold 			//
242c970c6e8SIngo Weinhold 			//    eax, ebx, ecx, edx,
243c970c6e8SIngo Weinhold 			//    esp, ebp, esi, edi,
244c970c6e8SIngo Weinhold 			//    eip, eflags,
245c970c6e8SIngo Weinhold 			//    cs, ss, ds, es
246c970c6e8SIngo Weinhold 			//
247c970c6e8SIngo Weinhold 			// Note that even thought the segment descriptors
248c970c6e8SIngo Weinhold 			// are actually 16 bits wide, gdb requires them
249c970c6e8SIngo Weinhold 			// as 32 bit integers. Note also that for some
250c970c6e8SIngo Weinhold 			// reason (unknown to me) gdb wants the register
251c970c6e8SIngo Weinhold 			// dump in *big endian* format.
252ae2e6c43SIngo Weinhold 			cpu = smp_get_current_cpu();
253ae2e6c43SIngo Weinhold 			gdb_regreply(dbg_register_file[cpu], 14);
254*777ae2fbSIngo Weinhold 
255ae2e6c43SIngo Weinhold 			break;
256*777ae2fbSIngo Weinhold 		}
257ae2e6c43SIngo Weinhold 
258ae2e6c43SIngo Weinhold 		case 'm':
259ae2e6c43SIngo Weinhold 		{
260ae2e6c43SIngo Weinhold 			char* ptr;
261ae2e6c43SIngo Weinhold 			unsigned address;
262ae2e6c43SIngo Weinhold 			unsigned len;
263ae2e6c43SIngo Weinhold 
264c970c6e8SIngo Weinhold 			// The 'm' command has the form mAAA,LLL
265c970c6e8SIngo Weinhold 			// where AAA is the address and LLL is the
266c970c6e8SIngo Weinhold 			// number of bytes.
267ae2e6c43SIngo Weinhold 			ptr = sCommand + 1;
268ae2e6c43SIngo Weinhold 			address = 0;
269ae2e6c43SIngo Weinhold 			len = 0;
270ae2e6c43SIngo Weinhold 			while (ptr && *ptr && (*ptr != ',')) {
271ae2e6c43SIngo Weinhold 				address <<= 4;
272ae2e6c43SIngo Weinhold 				address += parse_nibble(*ptr);
273ae2e6c43SIngo Weinhold 				ptr += 1;
274ae2e6c43SIngo Weinhold 			}
275ae2e6c43SIngo Weinhold 			if (*ptr == ',')
276ae2e6c43SIngo Weinhold 				ptr += 1;
277ae2e6c43SIngo Weinhold 
278ae2e6c43SIngo Weinhold 			while (ptr && *ptr) {
279ae2e6c43SIngo Weinhold 				len <<= 4;
280ae2e6c43SIngo Weinhold 				len += parse_nibble(*ptr);
281ae2e6c43SIngo Weinhold 				ptr += 1;
282ae2e6c43SIngo Weinhold 			}
283ae2e6c43SIngo Weinhold 
284ae2e6c43SIngo Weinhold 			if (len > 128)
285ae2e6c43SIngo Weinhold 				len = 128;
286ae2e6c43SIngo Weinhold 
287c970c6e8SIngo Weinhold 			// We cannot directly access the requested memory
288c970c6e8SIngo Weinhold 			// for gdb may be trying to access an stray pointer
289c970c6e8SIngo Weinhold 			// We copy the memory to a safe buffer using
290c970c6e8SIngo Weinhold 			// the bulletproof user_memcpy().
291ae2e6c43SIngo Weinhold 			if (user_memcpy(sSafeMemory, (char*)address, len) < 0)
292ae2e6c43SIngo Weinhold 				gdb_reply("E02");
293ae2e6c43SIngo Weinhold 			else
294ae2e6c43SIngo Weinhold 				gdb_memreply(sSafeMemory, len);
295*777ae2fbSIngo Weinhold 
296ae2e6c43SIngo Weinhold 			break;
297*777ae2fbSIngo Weinhold 		}
298ae2e6c43SIngo Weinhold 
299ae2e6c43SIngo Weinhold 		case 'k':
300c970c6e8SIngo Weinhold 			// Command 'k' actual semantics is 'kill the damn thing'.
301c970c6e8SIngo Weinhold 			// However gdb sends that command when you disconnect
302c970c6e8SIngo Weinhold 			// from a debug session. I guess that 'kill' for the
303c970c6e8SIngo Weinhold 			// kernel would map to reboot... however that's a
304c970c6e8SIngo Weinhold 			// a very mean thing to do, instead we just quit
305c970c6e8SIngo Weinhold 			// the gdb state machine and fallback to the regular
306c970c6e8SIngo Weinhold 			// kernel debugger command prompt.
307ae2e6c43SIngo Weinhold 			return QUIT;
308ae2e6c43SIngo Weinhold 
309ae2e6c43SIngo Weinhold 		default:
310ae2e6c43SIngo Weinhold 			gdb_reply("E01");
311ae2e6c43SIngo Weinhold 			break;
312ae2e6c43SIngo Weinhold 	}
313ae2e6c43SIngo Weinhold 
314ae2e6c43SIngo Weinhold 	return WAITACK;
315ae2e6c43SIngo Weinhold }
316ae2e6c43SIngo Weinhold 
317ae2e6c43SIngo Weinhold 
318ae2e6c43SIngo Weinhold //	#pragma mark - protocol state machine
319ae2e6c43SIngo Weinhold 
320ae2e6c43SIngo Weinhold 
321ae2e6c43SIngo Weinhold static int
322ae2e6c43SIngo Weinhold gdb_init_handler(int input)
323ae2e6c43SIngo Weinhold {
324ae2e6c43SIngo Weinhold 	switch (input) {
325ae2e6c43SIngo Weinhold 		case '$':
326ae2e6c43SIngo Weinhold 			memset(sCommand, 0, sizeof(sCommand));
327ae2e6c43SIngo Weinhold 			sCommandIndex = 0;
328ae2e6c43SIngo Weinhold 			return CMDREAD;
329ae2e6c43SIngo Weinhold 
330ae2e6c43SIngo Weinhold 		default:
331ae2e6c43SIngo Weinhold #if 0
332ae2e6c43SIngo Weinhold 			gdb_nak();
333ae2e6c43SIngo Weinhold #else
334c970c6e8SIngo Weinhold 			// looks to me like we should send
335c970c6e8SIngo Weinhold 			// a NAK here but it kinda works
336c970c6e8SIngo Weinhold 			// better if we just gobble all
337c970c6e8SIngo Weinhold 			// junk chars silently
338ae2e6c43SIngo Weinhold #endif
339ae2e6c43SIngo Weinhold 			return INIT;
340ae2e6c43SIngo Weinhold 	}
341ae2e6c43SIngo Weinhold }
342ae2e6c43SIngo Weinhold 
343ae2e6c43SIngo Weinhold 
344ae2e6c43SIngo Weinhold static int
345ae2e6c43SIngo Weinhold gdb_cmdread_handler(int input)
346ae2e6c43SIngo Weinhold {
347ae2e6c43SIngo Weinhold 	switch (input) {
348ae2e6c43SIngo Weinhold 		case '#':
349ae2e6c43SIngo Weinhold 			return CKSUM1;
350ae2e6c43SIngo Weinhold 
351ae2e6c43SIngo Weinhold 		default:
352ae2e6c43SIngo Weinhold 			sCommand[sCommandIndex] = input;
353ae2e6c43SIngo Weinhold 			sCommandIndex += 1;
354ae2e6c43SIngo Weinhold 			return CMDREAD;
355ae2e6c43SIngo Weinhold 	}
356ae2e6c43SIngo Weinhold }
357ae2e6c43SIngo Weinhold 
358ae2e6c43SIngo Weinhold 
359ae2e6c43SIngo Weinhold static int
360ae2e6c43SIngo Weinhold gdb_cksum1_handler(int input)
361ae2e6c43SIngo Weinhold {
362ae2e6c43SIngo Weinhold 	int nibble = parse_nibble(input);
363ae2e6c43SIngo Weinhold 
364ae2e6c43SIngo Weinhold 	if (nibble == 0xff) {
365ae2e6c43SIngo Weinhold #if 0
366ae2e6c43SIngo Weinhold 		gdb_nak();
367ae2e6c43SIngo Weinhold 		return INIT;
368ae2e6c43SIngo Weinhold #else
369c970c6e8SIngo Weinhold 		// looks to me like we should send
370c970c6e8SIngo Weinhold 		// a NAK here but it kinda works
371c970c6e8SIngo Weinhold 		// better if we just gobble all
372c970c6e8SIngo Weinhold 		// junk chars silently
373ae2e6c43SIngo Weinhold #endif
374ae2e6c43SIngo Weinhold 	}
375ae2e6c43SIngo Weinhold 
376ae2e6c43SIngo Weinhold 	sCheckSum = nibble << 4;
377ae2e6c43SIngo Weinhold 
378ae2e6c43SIngo Weinhold 	return CKSUM2;
379ae2e6c43SIngo Weinhold }
380ae2e6c43SIngo Weinhold 
381ae2e6c43SIngo Weinhold 
382ae2e6c43SIngo Weinhold static int
383ae2e6c43SIngo Weinhold gdb_cksum2_handler(int input)
384ae2e6c43SIngo Weinhold {
385ae2e6c43SIngo Weinhold 	int nibble = parse_nibble(input);
386ae2e6c43SIngo Weinhold 
387ae2e6c43SIngo Weinhold 	if (nibble == 0xff) {
388ae2e6c43SIngo Weinhold #if 0
389ae2e6c43SIngo Weinhold 		gdb_nak();
390ae2e6c43SIngo Weinhold 		return INIT;
391ae2e6c43SIngo Weinhold #else
392c970c6e8SIngo Weinhold 		// looks to me like we should send
393c970c6e8SIngo Weinhold 		// a NAK here but it kinda works
394c970c6e8SIngo Weinhold 		// better if we just gobble all
395c970c6e8SIngo Weinhold 		// junk chars silently
396ae2e6c43SIngo Weinhold #endif
397ae2e6c43SIngo Weinhold 	}
398ae2e6c43SIngo Weinhold 
399ae2e6c43SIngo Weinhold 	sCheckSum += nibble;
400ae2e6c43SIngo Weinhold 
401ae2e6c43SIngo Weinhold 	return gdb_parse_command();
402ae2e6c43SIngo Weinhold }
403ae2e6c43SIngo Weinhold 
404ae2e6c43SIngo Weinhold 
405ae2e6c43SIngo Weinhold static int
406ae2e6c43SIngo Weinhold gdb_waitack_handler(int input)
407ae2e6c43SIngo Weinhold {
408ae2e6c43SIngo Weinhold 	switch (input) {
409ae2e6c43SIngo Weinhold 		case '+':
410ae2e6c43SIngo Weinhold 			return INIT;
411ae2e6c43SIngo Weinhold 		case '-':
412ae2e6c43SIngo Weinhold 			gdb_resend_reply();
413ae2e6c43SIngo Weinhold 			return WAITACK;
414ae2e6c43SIngo Weinhold 
415ae2e6c43SIngo Weinhold 		default:
416c970c6e8SIngo Weinhold 			// looks like gdb and us are out of sync,
417c970c6e8SIngo Weinhold 			// send a NAK and retry from INIT state.
418ae2e6c43SIngo Weinhold 			gdb_nak();
419ae2e6c43SIngo Weinhold 			return INIT;
420ae2e6c43SIngo Weinhold 	}
421ae2e6c43SIngo Weinhold }
422ae2e6c43SIngo Weinhold 
423ae2e6c43SIngo Weinhold 
424ae2e6c43SIngo Weinhold static int
425ae2e6c43SIngo Weinhold gdb_quit_handler(int input)
426ae2e6c43SIngo Weinhold {
427ae2e6c43SIngo Weinhold 	(void)(input);
428ae2e6c43SIngo Weinhold 
429c970c6e8SIngo Weinhold 	// actually we should never be here
430ae2e6c43SIngo Weinhold 	return QUIT;
431ae2e6c43SIngo Weinhold }
432ae2e6c43SIngo Weinhold 
433ae2e6c43SIngo Weinhold 
434ae2e6c43SIngo Weinhold static int (*dispatch_table[GDBSTATES])(int) = {
435ae2e6c43SIngo Weinhold 	&gdb_init_handler,
436ae2e6c43SIngo Weinhold 	&gdb_cmdread_handler,
437ae2e6c43SIngo Weinhold 	&gdb_cksum1_handler,
438ae2e6c43SIngo Weinhold 	&gdb_cksum2_handler,
439ae2e6c43SIngo Weinhold 	&gdb_waitack_handler,
440ae2e6c43SIngo Weinhold 	&gdb_quit_handler
441ae2e6c43SIngo Weinhold };
442ae2e6c43SIngo Weinhold 
443ae2e6c43SIngo Weinhold 
444ae2e6c43SIngo Weinhold static int
445ae2e6c43SIngo Weinhold gdb_state_dispatch(int curr, int input)
446ae2e6c43SIngo Weinhold {
447ae2e6c43SIngo Weinhold 	if (curr < INIT || curr >= GDBSTATES)
448ae2e6c43SIngo Weinhold 		return QUIT;
449ae2e6c43SIngo Weinhold 
450ae2e6c43SIngo Weinhold 	return dispatch_table[curr](input);
451ae2e6c43SIngo Weinhold }
452ae2e6c43SIngo Weinhold 
453ae2e6c43SIngo Weinhold 
454ae2e6c43SIngo Weinhold static int
455ae2e6c43SIngo Weinhold gdb_state_machine(void)
456ae2e6c43SIngo Weinhold {
457ae2e6c43SIngo Weinhold 	int state = INIT;
458ae2e6c43SIngo Weinhold 	int c;
459ae2e6c43SIngo Weinhold 
460ae2e6c43SIngo Weinhold 	while (state != QUIT) {
461ae2e6c43SIngo Weinhold 		c = arch_debug_serial_getchar();
462ae2e6c43SIngo Weinhold 		state = gdb_state_dispatch(state, c);
463ae2e6c43SIngo Weinhold 	}
464ae2e6c43SIngo Weinhold 
465ae2e6c43SIngo Weinhold 	return 0;
466ae2e6c43SIngo Weinhold }
467ae2e6c43SIngo Weinhold 
468ae2e6c43SIngo Weinhold 
469ae2e6c43SIngo Weinhold //	#pragma mark -
470ae2e6c43SIngo Weinhold 
471ae2e6c43SIngo Weinhold 
472ae2e6c43SIngo Weinhold int
473ae2e6c43SIngo Weinhold cmd_gdb(int argc, char** argv)
474ae2e6c43SIngo Weinhold {
475ae2e6c43SIngo Weinhold 	(void)(argc);
476ae2e6c43SIngo Weinhold 	(void)(argv);
477ae2e6c43SIngo Weinhold 
478ae2e6c43SIngo Weinhold 	return gdb_state_machine();
479ae2e6c43SIngo Weinhold }
480