2 ** Copyright 2002, Manuel J. Petit. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
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
};
23 static char reply
[512];
25 static char safe_mem
[512];
35 return ((value
>>8)&0xff) | ((value
&0xff)<<8);
42 return htons((value
>>16)&0xffff) | (htons(value
&0xffff)<<16);
47 parse_nibble(int input
)
51 if((input
>= '0') && (input
<= '9')) {
54 if((input
>= 'A') && (input
<= 'F')) {
55 nibble
= 0x0a+(input
-'A');
57 if((input
>= 'a') && (input
<= 'f')) {
58 nibble
= 0x0a+(input
-'a');
67 * GDB protocol ACK & NAK & Reply
86 gdb_resend_reply(void)
93 gdb_reply(char const *fmt
, ...)
102 vsprintf(reply
+1, fmt
, args
);
107 for(i
= 1; i
< len
; i
++) {
112 sprintf(reply
+len
, "#%02x", sum
);
119 gdb_regreply(int const *regs
, int numregs
)
126 for(i
= 0; i
< numregs
; i
++) {
127 sprintf(reply
+1+8*i
, "%08x", htonl(regs
[i
]));
132 for(i
= 1; i
< len
; i
++) {
137 sprintf(reply
+len
, "#%02x", sum
);
144 gdb_memreply(char const *bytes
, int numbytes
)
151 for(i
= 0; i
< numbytes
; i
++) {
152 sprintf(reply
+1+2*i
, "%02x", (unsigned char)bytes
[i
]);
157 for(i
= 1; i
< len
; i
++) {
162 sprintf(reply
+len
, "#%02x", sum
);
170 * checksum verification
174 gdb_verify_checksum(void)
182 for(i
= 0; i
< len
; i
++) {
187 return (sum
==checksum
)?1:0;
192 * command parsing an dispatching
196 gdb_parse_command(unsigned int *regfile
)
198 if(!gdb_verify_checksum()) {
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.
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'
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) {
243 "Text=%x;Data=%x;Bss=%x",
245 ((unsigned)(&__data_start
))-0x80000000,
246 ((unsigned)(&__bss_start
))-0x80000000
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 */
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,
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
);
293 * The 'm' command has the form mAAA,LLL
294 * where AAA is the address and LLL is the
300 while(ptr
&& *ptr
&& (*ptr
!= ',')) {
302 address
+= parse_nibble(*ptr
);
310 len
+= parse_nibble(*ptr
);
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) {
327 gdb_memreply(safe_mem
, len
);
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.
357 * GDB protocol state machine
361 gdb_init_handler(int input
, unsigned int *regfile
)
367 memset(cmd
, 0, sizeof(cmd
));
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
387 gdb_cmdread_handler(int input
, unsigned int *regfile
)
403 gdb_cksum1_handler(int input
, unsigned int *regfile
)
405 int nibble
= parse_nibble(input
);
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
423 checksum
= nibble
<< 4;
430 gdb_cksum2_handler(int input
, unsigned int *regfile
)
432 int nibble
= parse_nibble(input
);
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
450 return gdb_parse_command(regfile
);
455 gdb_waitack_handler(int input
, unsigned int *regfile
)
467 * looks like gdb and us are out of synch,
468 * send a NAK and retry from INIT state.
477 gdb_quit_handler(int input
, unsigned int *regfile
)
483 * actually we should never be here
488 static int (*dispatch_table
[GDBSTATES
])(int, unsigned int*)=
491 &gdb_cmdread_handler
,
494 &gdb_waitack_handler
,
500 gdb_state_dispatch(int curr
, int input
, unsigned int *regfile
)
505 if(curr
>= GDBSTATES
) {
509 return dispatch_table
[curr
](input
, regfile
);
514 gdb_state_machine(unsigned int *regfile
)
519 while(state
!= QUIT
) {
520 c
= arch_dbg_con_read();
521 state
= gdb_state_dispatch(state
, c
, regfile
);
528 cmd_gdb(int argc
, char **argv
)
530 struct iframe
*interrupt_frame
= NULL
;
531 unsigned int local_regfile
[GDB_REGISTER_FILE_COUNT
];
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]);
538 dprintf("warning: iframe used is not valid, using local stack.\n");
542 dbg_make_register_file(local_regfile
, interrupt_frame
);
544 memcpy(local_regfile
, dbg_register_file
, sizeof(unsigned int) * GDB_REGISTER_FILE_COUNT
);
547 gdb_state_machine(local_regfile
);