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