fix what is apparently a long standing bug in the floppy bootloader that relied on...
[newos.git] / kernel / gdb.c
blob1173474b3aa3e23857f9ebba6f43b807ce3d760e
1 /*
2 ** Copyright 2002, Manuel J. Petit. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
4 */
5 #include <string.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <kernel/vm.h>
10 #include <kernel/smp.h>
11 #include <kernel/debug.h>
12 #include <kernel/gdb.h>
13 #include <kernel/arch/dbg_console.h>
16 enum { INIT= 0, CMDREAD, CKSUM1, CKSUM2, WAITACK, QUIT, GDBSTATES };
19 static char cmd[512];
20 static int cmd_ptr;
21 static int checksum;
23 static char reply[512];
25 static char safe_mem[512];
29 * utility functions
31 static
32 int
33 htons(short value)
35 return ((value>>8)&0xff) | ((value&0xff)<<8);
38 static
39 int
40 htonl(int value)
42 return htons((value>>16)&0xffff) | (htons(value&0xffff)<<16);
45 static
46 int
47 parse_nibble(int input)
49 int nibble= 0xff;
51 if((input>= '0') && (input<= '9')) {
52 nibble= input-'0';
54 if((input>= 'A') && (input<= 'F')) {
55 nibble= 0x0a+(input-'A');
57 if((input>= 'a') && (input<= 'f')) {
58 nibble= 0x0a+(input-'a');
61 return nibble;
67 * GDB protocol ACK & NAK & Reply
70 static
71 void
72 gdb_ack(void)
74 dbg_putch('+');
77 static
78 void
79 gdb_nak(void)
81 dbg_putch('-');
84 static
85 void
86 gdb_resend_reply(void)
88 dbg_puts(reply);
91 static
92 void
93 gdb_reply(char const *fmt, ...)
95 int i;
96 int len;
97 int sum;
98 va_list args;
100 va_start(args, fmt);
101 reply[0]= '$';
102 vsprintf(reply+1, fmt, args);
103 va_end(args);
105 len= strlen(reply);
106 sum= 0;
107 for(i= 1; i< len; i++) {
108 sum+= reply[i];
110 sum%= 256;
112 sprintf(reply+len, "#%02x", sum);
114 gdb_resend_reply();
117 static
118 void
119 gdb_regreply(int const *regs, int numregs)
121 int i;
122 int len;
123 int sum;
125 reply[0]= '$';
126 for(i= 0; i< numregs; i++) {
127 sprintf(reply+1+8*i, "%08x", htonl(regs[i]));
130 len= strlen(reply);
131 sum= 0;
132 for(i= 1; i< len; i++) {
133 sum+= reply[i];
135 sum%= 256;
137 sprintf(reply+len, "#%02x", sum);
139 gdb_resend_reply();
142 static
143 void
144 gdb_memreply(char const *bytes, int numbytes)
146 int i;
147 int len;
148 int sum;
150 reply[0]= '$';
151 for(i= 0; i< numbytes; i++) {
152 sprintf(reply+1+2*i, "%02x", (unsigned char)bytes[i]);
155 len= strlen(reply);
156 sum= 0;
157 for(i= 1; i< len; i++) {
158 sum+= reply[i];
160 sum%= 256;
162 sprintf(reply+len, "#%02x", sum);
164 gdb_resend_reply();
170 * checksum verification
172 static
174 gdb_verify_checksum(void)
176 int i;
177 int len;
178 int sum;
180 len= strlen(cmd);
181 sum= 0;
182 for(i= 0; i< len; i++) {
183 sum+= cmd[i];
185 sum%= 256;
187 return (sum==checksum)?1:0;
192 * command parsing an dispatching
194 static
196 gdb_parse_command(unsigned int *regfile)
198 if(!gdb_verify_checksum()) {
199 gdb_nak();
200 return INIT;
201 } else {
202 gdb_ack();
205 switch(cmd[0]) {
207 case 'H':
210 * Command H (actually Hct) is used to select
211 * the current thread (-1 meaning all threads)
212 * We just fake we recognize the the command
213 * and send an 'OK' response.
215 gdb_reply("OK");
216 } break;
218 case 'q':
220 extern unsigned __data_start;
221 extern unsigned __bss_start;
224 * There are several q commands:
226 * qXXXX Request info about XXXX.
227 * QXXXX=yyyy Set value of XXXX to yyyy.
228 * qOffsets Get segment offsets
230 * Currently we only support the 'qOffsets'
231 * form.
233 * *Note* that we actually have to lie,
234 * At first thought looks like we should
235 * return '_start', '__data_start' &
236 * '__bss_start', however gdb gets
237 * confused because the kernel link script
238 * pre-links at 0x80000000. To keep gdb
239 * gdb happy we just substract that amount.
241 if(strcmp(cmd+1, "Offsets")== 0) {
242 gdb_reply(
243 "Text=%x;Data=%x;Bss=%x",
245 ((unsigned)(&__data_start))-0x80000000,
246 ((unsigned)(&__bss_start))-0x80000000
248 } else {
249 gdb_reply("ENS");
251 } break;
253 case '?':
256 * command '?' is used for retrieving the signal
257 * that stopped the program. Fully implemeting
258 * this command requires help from the debugger,
259 * by now we just fake a SIGKILL
261 gdb_reply("S09"); /* SIGKILL = 9 */
262 } break;
264 case 'g':
267 * command 'g' is used for reading the register
268 * file. Faked by now.
270 * For x86 the register order is:
272 * eax, ebx, ecx, edx,
273 * esp, ebp, esi, edi,
274 * eip, eflags,
275 * cs, ss, ds, es
277 * Note that even thought the segment descriptors
278 * are actually 16 bits wide, gdb requires them
279 * as 32 bit integers. Note also that for some
280 * reason (unknown to me) gdb wants the register
281 * dump in *big endian* format.
283 gdb_regreply(regfile, GDB_REGISTER_FILE_COUNT);
284 } break;
286 case 'm':
288 char *ptr;
289 unsigned address;
290 unsigned len;
293 * The 'm' command has the form mAAA,LLL
294 * where AAA is the address and LLL is the
295 * number of bytes.
297 ptr= cmd+1;
298 address= 0;
299 len= 0;
300 while(ptr && *ptr && (*ptr!= ',')) {
301 address<<= 4;
302 address+= parse_nibble(*ptr);
303 ptr+= 1;
305 if(*ptr== ',') {
306 ptr+= 1;
308 while(ptr && *ptr) {
309 len<<= 4;
310 len+= parse_nibble(*ptr);
311 ptr+= 1;
314 if(len> 128) {
315 len= 128;
319 * We cannot directly access the requested memory
320 * for gdb may be trying to access an stray pointer
321 * We copy the memory to a safe buffer using
322 * the bulletproof user_memcpy().
324 if(user_memcpy(safe_mem, (char*)address, len)< 0) {
325 gdb_reply("E02");
326 } else {
327 gdb_memreply(safe_mem, len);
329 } break;
331 case 'k':
334 * Command 'k' actual semantics is 'kill the damn thing'.
335 * However gdb sends that command when you disconnect
336 * from a debug session. I guess that 'kill' for the
337 * kernel would map to reboot... however that's a
338 * a very mean thing to do, instead we just quit
339 * the gdb state machine and fallback to the regular
340 * kernel debugger command prompt.
342 return QUIT;
343 } break;
345 default:
347 gdb_reply("E01");
348 } break;
351 return WAITACK;
357 * GDB protocol state machine
359 static
361 gdb_init_handler(int input, unsigned int *regfile)
363 (void)(regfile);
365 switch(input) {
366 case '$':
367 memset(cmd, 0, sizeof(cmd));
368 cmd_ptr= 0;
369 return CMDREAD;
370 default:
371 #if 0
372 gdb_nak();
373 #else
375 * looks to me like we should send
376 * a NAK here but it kinda works
377 * better if we just gobble all
378 * junk chars silently
380 #endif
381 return INIT;
385 static
387 gdb_cmdread_handler(int input, unsigned int *regfile)
389 (void)(regfile);
391 switch(input) {
392 case '#':
393 return CKSUM1;
394 default:
395 cmd[cmd_ptr]= input;
396 cmd_ptr+= 1;
397 return CMDREAD;
401 static
403 gdb_cksum1_handler(int input, unsigned int *regfile)
405 int nibble= parse_nibble(input);
407 (void)(regfile);
409 if(nibble== 0xff) {
410 #if 0
411 gdb_nak();
412 return INIT;
413 #else
415 * looks to me like we should send
416 * a NAK here but it kinda works
417 * better if we just gobble all
418 * junk chars silently
420 #endif
423 checksum= nibble<< 4;
425 return CKSUM2;
428 static
430 gdb_cksum2_handler(int input, unsigned int *regfile)
432 int nibble= parse_nibble(input);
434 if(nibble== 0xff) {
435 #if 0
436 gdb_nak();
437 return INIT;
438 #else
440 * looks to me like we should send
441 * a NAK here but it kinda works
442 * better if we just gobble all
443 * junk chars silently
445 #endif
448 checksum+= nibble;
450 return gdb_parse_command(regfile);
453 static
455 gdb_waitack_handler(int input, unsigned int *regfile)
457 (void)(regfile);
459 switch(input) {
460 case '+':
461 return INIT;
462 case '-':
463 gdb_resend_reply();
464 return WAITACK;
465 default:
467 * looks like gdb and us are out of synch,
468 * send a NAK and retry from INIT state.
470 gdb_nak();
471 return INIT;
475 static
477 gdb_quit_handler(int input, unsigned int *regfile)
479 (void)(input);
480 (void)(regfile);
483 * actually we should never be here
485 return QUIT;
488 static int (*dispatch_table[GDBSTATES])(int, unsigned int*)=
490 &gdb_init_handler,
491 &gdb_cmdread_handler,
492 &gdb_cksum1_handler,
493 &gdb_cksum2_handler,
494 &gdb_waitack_handler,
495 &gdb_quit_handler
498 static
500 gdb_state_dispatch(int curr, int input, unsigned int *regfile)
502 if(curr< INIT) {
503 return QUIT;
505 if(curr>= GDBSTATES) {
506 return QUIT;
509 return dispatch_table[curr](input, regfile);
512 static
514 gdb_state_machine(unsigned int *regfile)
516 int state= INIT;
517 int c;
519 while(state!= QUIT) {
520 c= arch_dbg_con_read();
521 state= gdb_state_dispatch(state, c, regfile);
524 return 0;
527 void
528 cmd_gdb(int argc, char **argv)
530 struct iframe *interrupt_frame = NULL;
531 unsigned int local_regfile[GDB_REGISTER_FILE_COUNT];
532 if (argc > 1)
534 // we want to work under a particular iframe.
535 if(strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x')
536 interrupt_frame = (struct iframe*)atoul(argv[1]);
537 else
538 dprintf("warning: iframe used is not valid, using local stack.\n");
540 if (interrupt_frame)
542 dbg_make_register_file(local_regfile, interrupt_frame);
543 } else {
544 memcpy(local_regfile, dbg_register_file, sizeof(unsigned int) * GDB_REGISTER_FILE_COUNT);
547 gdb_state_machine(local_regfile);