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