libroot/posix/stdio: Remove unused portions.
[haiku.git] / src / system / kernel / debug / gdb.cpp
blob3711683027359cf09af347e402acc5e4fc35ba7c
1 /*
2 * Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
5 * Copyright 2002, Manuel J. Petit. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7 */
9 /** Contains the code to interface with a remote GDB */
11 #include "gdb.h"
13 #include <string.h>
14 #include <stdarg.h>
15 #include <stdio.h>
17 #include <ByteOrder.h>
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>
28 enum { INIT = 0, CMDREAD, CKSUM1, CKSUM2, WAITACK, QUIT, GDBSTATES };
31 static char sCommand[512];
32 static int sCommandIndex;
33 static int sCheckSum;
35 static char sReply[512];
36 static char sSafeMemory[512];
39 // utility functions
42 static int
43 parse_nibble(int input)
45 int nibble = 0xff;
47 if (input >= '0' && input <= '9')
48 nibble = input - '0';
50 if (input >= 'A' && input <= 'F')
51 nibble = 0x0a + input - 'A';
53 if (input >= 'a' && input <= 'f')
54 nibble = 0x0a + input - 'a';
56 return nibble;
60 // #pragma mark - GDB protocol
63 static void
64 gdb_ack(void)
66 arch_debug_serial_putchar('+');
70 static void
71 gdb_nak(void)
73 arch_debug_serial_putchar('-');
77 static void
78 gdb_resend_reply(void)
80 arch_debug_serial_puts(sReply);
84 static void
85 gdb_reply(char const* format, ...)
87 int i;
88 int len;
89 int sum;
90 va_list args;
92 va_start(args, format);
93 sReply[0] = '$';
94 vsprintf(sReply + 1, format, args);
95 va_end(args);
97 len = strlen(sReply);
98 sum = 0;
99 for (i = 1; i < len; i++) {
100 sum += sReply[i];
102 sum %= 256;
104 sprintf(sReply + len, "#%02x", sum);
106 gdb_resend_reply();
110 static void
111 gdb_regreply()
113 sReply[0] = '$';
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;
123 // add 1 for the leading '$'
124 bytesWritten++;
126 // compute check sum
127 int sum = 0;
128 for (int32 i = 1; i < bytesWritten; i++)
129 sum += sReply[i];
130 sum %= 256;
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;
140 gdb_resend_reply();
144 static void
145 gdb_memreply(char const* bytes, int numbytes)
147 int i;
148 int len;
149 int sum;
151 sReply[0] = '$';
152 for (i = 0; i < numbytes; i++)
153 sprintf(sReply + 1 + 2 * i, "%02x", (uint8)bytes[i]);
155 len = strlen(sReply);
156 sum = 0;
157 for (i = 1; i < len; i++)
158 sum += sReply[i];
159 sum %= 256;
161 sprintf(sReply + len, "#%02x", sum);
163 gdb_resend_reply();
167 // #pragma mark - checksum verification
170 static int
171 gdb_verify_checksum(void)
173 int i;
174 int len;
175 int sum;
177 len = strlen(sCommand);
178 sum = 0;
179 for (i = 0; i < len; i++)
180 sum += sCommand[i];
181 sum %= 256;
183 return (sum == sCheckSum) ? 1 : 0;
187 // #pragma mark - command parsing
190 static int
191 gdb_parse_command(void)
193 if (!gdb_verify_checksum()) {
194 gdb_nak();
195 return INIT;
196 } else
197 gdb_ack();
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;
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;
216 case 'q':
218 // query commands
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("");
233 break;
236 case 'c':
237 // continue at address
238 // TODO: Parse the address and resume there!
239 return QUIT;
241 case 'g':
242 gdb_regreply();
243 break;
245 case 'G':
246 // write registers
247 // TODO: Implement!
248 gdb_reply("E01");
249 break;
252 case 'm':
254 char* ptr;
255 addr_t address;
256 size_t len;
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;
269 if (*ptr == ',')
270 ptr += 1;
272 while (ptr && *ptr) {
273 len <<= 4;
274 len += parse_nibble(*ptr);
275 ptr += 1;
278 if (len > 128)
279 len = 128;
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);
291 break;
294 case 'D':
295 // detach
296 return QUIT;
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;
308 case 's':
309 // "step" -- resume (?) at address
310 // TODO: Implement!
311 gdb_reply("E01");
312 break;
314 default:
315 gdb_reply("");
316 break;
319 return WAITACK;
323 // #pragma mark - protocol state machine
326 static int
327 gdb_init_handler(int input)
329 switch (input) {
330 case '$':
331 memset(sCommand, 0, sizeof(sCommand));
332 sCommandIndex = 0;
333 return CMDREAD;
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;
349 static int
350 gdb_cmdread_handler(int input)
352 switch (input) {
353 case '#':
354 return CKSUM1;
356 default:
357 sCommand[sCommandIndex] = input;
358 sCommandIndex += 1;
359 return CMDREAD;
364 static int
365 gdb_cksum1_handler(int input)
367 int nibble = parse_nibble(input);
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
381 sCheckSum = nibble << 4;
383 return CKSUM2;
387 static int
388 gdb_cksum2_handler(int input)
390 int nibble = parse_nibble(input);
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
404 sCheckSum += nibble;
406 return gdb_parse_command();
410 static int
411 gdb_waitack_handler(int input)
413 switch (input) {
414 case '+':
415 return INIT;
416 case '-':
417 gdb_resend_reply();
418 return WAITACK;
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;
429 static int
430 gdb_quit_handler(int input)
432 (void)(input);
434 // actually we should never be here
435 return QUIT;
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
449 static int
450 gdb_state_dispatch(int curr, int input)
452 if (curr < INIT || curr >= GDBSTATES)
453 return QUIT;
455 return dispatch_table[curr](input);
459 static int
460 gdb_state_machine(void)
462 int state = INIT;
463 int c;
465 while (state != QUIT) {
466 c = arch_debug_serial_getchar();
467 state = gdb_state_dispatch(state, c);
470 return 0;
474 // #pragma mark -
478 cmd_gdb(int argc, char** argv)
480 (void)(argc);
481 (void)(argv);
483 return gdb_state_machine();