diff --git a/sys/amd64/amd64/amd64-gdbstub.c b/sys/amd64/amd64/amd64-gdbstub.c new file mode 100644 index 000000000000..41b72afaff3c --- /dev/null +++ b/sys/amd64/amd64/amd64-gdbstub.c @@ -0,0 +1,583 @@ +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for FreeBSD by Stu Grossman. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + * The external function exceptionHandler() is + * used to attach a specific handler to a specific 386 vector number. + * It should use the same privilege level it runs at. It should + * install it as an interrupt gate so that interrupts are masked + * while the handler runs. + * Also, need to assign exceptionHook and oldExceptionHook. + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************/ + +void gdb_handle_exception (db_regs_t *, int, int); + +extern jmp_buf db_jmpbuf; +extern void db_read_bytes (vm_offset_t addr, int size, char *data); +extern void db_write_bytes (vm_offset_t addr, int size, char *data); +extern void siocnputc (dev_t, int c); +extern int siocngetc (dev_t); + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 400 + +/* Create private copies of common functions used by the stub. This prevents + nasty interactions between app code and the stub (for instance if user steps + into strlen, etc..) */ + +static int +strlen (const char *s) +{ + const char *s1 = s; + + while (*s1++ != '\000'); + + return s1 - s; +} + +static char * +strcpy (char *dst, const char *src) +{ + char *retval = dst; + + while ((*dst++ = *src++) != '\000'); + + return retval; +} + +static int +putDebugChar (int c) /* write a single character */ +{ + siocnputc (NULL, c); + return 1; +} + +static int +getDebugChar (void) /* read and return a single char */ +{ + return siocngetc (NULL); +} + +static const char hexchars[]="0123456789abcdef"; + +static int +hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10); + if ((ch >= '0') && (ch <= '9')) return (ch-'0'); + if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10); + return (-1); +} + +/* scan for the sequence $# */ +static void +getpacket (char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + unsigned char ch; + + do + { + /* wait around for the start character, ignore all other characters */ + + while ((ch = (getDebugChar () & 0x7f)) != '$'); + + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + + while (count < BUFMAX) + { + ch = getDebugChar () & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') + { + xmitcsum = hex (getDebugChar () & 0x7f) << 4; + xmitcsum += hex (getDebugChar () & 0x7f); + + if (checksum != xmitcsum) + putDebugChar ('-'); /* failed checksum */ + else + { + putDebugChar ('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') + { + putDebugChar (buffer[0]); + putDebugChar (buffer[1]); + + /* remove sequence chars from buffer */ + + count = strlen (buffer); + for (i=3; i <= count; i++) + buffer[i-3] = buffer[i]; + } + } + } + } + while (checksum != xmitcsum); +} + +/* send the packet in buffer. */ + +static void +putpacket (char *buffer) +{ + unsigned char checksum; + int count; + unsigned char ch; + + /* $#. */ + do + { + putDebugChar ('$'); + checksum = 0; + count = 0; + + while (ch=buffer[count]) + { + putDebugChar (ch); + checksum += ch; + count += 1; + } + + putDebugChar ('#'); + putDebugChar (hexchars[checksum >> 4]); + putDebugChar (hexchars[checksum & 0xf]); + } + while ((getDebugChar () & 0x7f) != '+'); +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +static int +get_char (vm_offset_t addr) +{ + char data; + + if (setjmp (db_jmpbuf)) + return -1; + + db_read_bytes (addr, 1, &data); + + return data & 0xff; +} + +static int +set_char (vm_offset_t addr, int val) +{ + char data; + + if (setjmp (db_jmpbuf)) + return -1; + + data = val; + + db_write_bytes (addr, 1, &data); + return 0; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ + +static char * +mem2hex (vm_offset_t mem, char *buf, int count) +{ + int i; + int ch; + + for (i=0;i> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + return(buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +static char * +hex2mem (char *buf, vm_offset_t mem, int count) +{ + int i; + int ch; + int rv; + + for (i=0;i=0) + { + *intValue = (*intValue <<4) | hexValue; + numChars ++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +#define NUMREGBYTES (sizeof registers) +#define PC 8 +#define SP 4 +#define FP 5 +#define NUM_REGS 14 + +/* + * This function does all command procesing for interfacing to gdb. + */ +void +gdb_handle_exception (db_regs_t *raw_regs, int type, int code) +{ + int sigval; + int addr, length; + char * ptr; + struct i386regs { + unsigned int eax; + unsigned int ecx; + unsigned int edx; + unsigned int ebx; + unsigned int esp; + unsigned int ebp; + unsigned int esi; + unsigned int edi; + unsigned int eip; + unsigned int eflags; + unsigned int cs; + unsigned int ss; + unsigned int ds; + unsigned int es; + }; + struct i386regs registers; + + registers.eax = raw_regs->tf_eax; + registers.ebx = raw_regs->tf_ebx; + registers.ecx = raw_regs->tf_ecx; + registers.edx = raw_regs->tf_edx; + + registers.esp = raw_regs->tf_esp; + registers.ebp = raw_regs->tf_ebp; + registers.esi = raw_regs->tf_esi; + registers.edi = raw_regs->tf_edi; + + registers.eip = raw_regs->tf_eip; + registers.eflags = raw_regs->tf_eflags; + + registers.cs = raw_regs->tf_cs; + registers.ss = raw_regs->tf_ss; + registers.ds = raw_regs->tf_ds; + registers.es = raw_regs->tf_es; + + /* reply to host that an exception has occurred */ + sigval = computeSignal (type); + ptr = remcomOutBuffer; + + *ptr++ = 'T'; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + + *ptr++ = hexchars[PC >> 4]; + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((vm_offset_t)®isters.eip, ptr, 4); + *ptr++ = ';'; + + *ptr++ = hexchars[FP >> 4]; + *ptr++ = hexchars[FP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((vm_offset_t)®isters.ebp, ptr, 4); + *ptr++ = ';'; + + *ptr++ = hexchars[SP >> 4]; + *ptr++ = hexchars[SP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((vm_offset_t)®isters.esp, ptr, 4); + *ptr++ = ';'; + + *ptr++ = 0; + + putpacket (remcomOutBuffer); + + while (1) + { + remcomOutBuffer[0] = 0; + + getpacket (remcomInBuffer); + switch (remcomInBuffer[0]) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + + case 'g': /* return the value of the CPU registers */ + mem2hex ((vm_offset_t)®isters, remcomOutBuffer, NUMREGBYTES); + break; + + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (&remcomInBuffer[1], (vm_offset_t)®isters, NUMREGBYTES); + strcpy (remcomOutBuffer, "OK"); + break; + + case 'P': /* Set the value of one register */ + { + int regno; + + ptr = &remcomInBuffer[1]; + + if (hexToInt (&ptr, ®no) + && *ptr++ == '=' + && regno < NUM_REGS) + { + hex2mem (ptr, (vm_offset_t)®isters + regno * 4, 4); + strcpy(remcomOutBuffer,"OK"); + } + else + strcpy (remcomOutBuffer, "P01"); + break; + } + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* Try to read %x,%x. */ + + ptr = &remcomInBuffer[1]; + + if (hexToInt (&ptr, &addr) + && *(ptr++) == ',' + && hexToInt (&ptr, &length)) + { + if (mem2hex((vm_offset_t) addr, remcomOutBuffer, length) == NULL) + strcpy (remcomOutBuffer, "E03"); + break; + } + else + strcpy (remcomOutBuffer, "E01"); + break; + + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + + /* Try to read '%x,%x:'. */ + + ptr = &remcomInBuffer[1]; + + if (hexToInt(&ptr,&addr) + && *(ptr++) == ',' + && hexToInt(&ptr, &length) + && *(ptr++) == ':') + { + if (hex2mem(ptr, (vm_offset_t) addr, length) == NULL) + strcpy (remcomOutBuffer, "E03"); + else + strcpy (remcomOutBuffer, "OK"); + } + else + strcpy (remcomOutBuffer, "E02"); + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 'c' : + case 's' : + /* try to read optional parameter, pc unchanged if no parm */ + + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr,&addr)) + registers.eip = addr; + + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') + registers.eflags |= PSL_T; + else + registers.eflags &= ~PSL_T; + + raw_regs->tf_eax = registers.eax; + raw_regs->tf_ebx = registers.ebx; + raw_regs->tf_ecx = registers.ecx; + raw_regs->tf_edx = registers.edx; + + raw_regs->tf_esp = registers.esp; + raw_regs->tf_ebp = registers.ebp; + raw_regs->tf_esi = registers.esi; + raw_regs->tf_edi = registers.edi; + + raw_regs->tf_eip = registers.eip; + raw_regs->tf_eflags = registers.eflags; + + raw_regs->tf_cs = registers.cs; + raw_regs->tf_ss = registers.ss; + raw_regs->tf_ds = registers.ds; + raw_regs->tf_es = registers.es; + return; + + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} diff --git a/sys/amd64/amd64/db_interface.c b/sys/amd64/amd64/db_interface.c index db7e06031524..159400c4dbae 100644 --- a/sys/amd64/amd64/db_interface.c +++ b/sys/amd64/amd64/db_interface.c @@ -23,7 +23,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: db_interface.c,v 1.18 1996/04/07 18:34:59 bde Exp $ + * $Id: db_interface.c,v 1.19 1996/05/03 21:00:51 phk Exp $ */ /* @@ -48,6 +48,7 @@ #include static int db_active = 0; +extern void gdb_handle_exception __P((db_regs_t *, int, int)); db_regs_t ddb_regs; @@ -93,7 +94,7 @@ kdb_trap(type, code, regs) * our breakpoints by disarming our breakpoints and fixing up * %eip. */ - if (cons_unavail) { + if (cons_unavail && !(boothowto & RB_GDB)) { if (type == T_TRCTRAP) { regs->tf_eflags &= ~PSL_T; return (1); @@ -133,7 +134,10 @@ kdb_trap(type, code, regs) db_active++; cnpollc(TRUE); - db_trap(type, code); + if (boothowto & RB_GDB) + gdb_handle_exception(&ddb_regs, type, code); + else + db_trap(type, code); cnpollc(FALSE); db_active--; @@ -267,7 +271,7 @@ Debugger(msg) * OK if the call is for the debugger hotkey but not if the call * is a weak form of panicing. */ - if (cons_unavail) + if (cons_unavail & !(boothowto & RB_GDB)) return; if (!in_Debugger) { diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 9b217436cca4..090296cc41f7 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.137 1996/07/05 18:49:01 jhay Exp $ +# $Id: files.i386,v 1.138 1996/07/08 19:44:30 wollman Exp $ # aic7xxx_asm optional ahc device-driver \ dependency "$S/dev/aic7xxx/aic7xxx_asm.c" \ @@ -40,6 +40,7 @@ i386/i386/cons.c standard i386/i386/db_disasm.c optional ddb i386/i386/db_interface.c optional ddb i386/i386/db_trace.c optional ddb +i386/i386/i386-gdbstub.c optional ddb i386/i386/exception.s standard i386/i386/identcpu.c standard i386/i386/in_cksum.c optional inet diff --git a/sys/i386/boot/biosboot/boot.c b/sys/i386/boot/biosboot/boot.c index 2decc57d0ea7..fc190003bfc3 100644 --- a/sys/i386/boot/biosboot/boot.c +++ b/sys/i386/boot/biosboot/boot.c @@ -24,7 +24,7 @@ * the rights to redistribute these changes. * * from: Mach, [92/04/03 16:51:14 rvb] - * $Id: boot.c,v 1.52 1996/07/09 02:28:20 julian Exp $ + * $Id: boot.c,v 1.53 1996/07/12 05:25:45 bde Exp $ */ @@ -332,6 +332,8 @@ nextarg: if (*howto & RB_SERIAL) init_serial(); } + if (c == 'g') + *howto |= RB_GDB; if (c == 'r') *howto |= RB_DFLTROOT; if (c == 's') diff --git a/sys/i386/boot/dosboot/fbsdboot.c b/sys/i386/boot/dosboot/fbsdboot.c index fd77aae814d1..4bb18e415b68 100644 --- a/sys/i386/boot/dosboot/fbsdboot.c +++ b/sys/i386/boot/dosboot/fbsdboot.c @@ -94,6 +94,7 @@ int main(int argc, char *argv[]) case 'a': howto |= RB_ASKNAME; break; case 'c': howto |= RB_CONFIG; break; case 'd': howto |= RB_KDB; break; + case 'g': howto |= RB_GDB; break; case 'v': howto |= RB_VERBOSE; break; case 'C': howto |= RB_CDROM; break; case 'D': dos = 1; kernel = "c:\\kernel"; break; diff --git a/sys/i386/boot/dosboot/reboot.h b/sys/i386/boot/dosboot/reboot.h index 51b5f1f98f75..c21858a75cfc 100644 --- a/sys/i386/boot/dosboot/reboot.h +++ b/sys/i386/boot/dosboot/reboot.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)reboot.h 8.1 (Berkeley) 6/2/93 - * $Id: reboot.h,v 1.7 1994/11/26 09:08:40 phk Exp $ + * $Id: reboot.h,v 1.2 1995/04/27 18:22:32 phk Exp $ */ #ifndef _SYS_REBOOT_H_ @@ -56,8 +56,10 @@ #define RB_MINIROOT 0x200 /* mini-root present in memory at boot time */ #define RB_CONFIG 0x400 /* invoke user configuration routing */ #define RB_VERBOSE 0x800 /* print all potentially useful info */ -#define RB_SERIAL 0x1000 /* user serial port as console */ -#define RB_CDROM 0x2000 /* use cdrom as root */ +#define RB_SERIAL 0x1000 /* user serial port as console */ +#define RB_CDROM 0x2000 /* use cdrom as root */ +#define RB_POWEROFF 0x4000 /* if you can, turn the power off */ +#define RB_GDB 0x8000 /* use GDB remote debugger instead of DDB */ #define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */ diff --git a/sys/i386/boot/netboot/bootmenu.c b/sys/i386/boot/netboot/bootmenu.c index d8f23306379b..7e5b0157001c 100644 --- a/sys/i386/boot/netboot/bootmenu.c +++ b/sys/i386/boot/netboot/bootmenu.c @@ -299,6 +299,7 @@ cmd_flags(buf) case 'b': flags |= RB_HALT; break; case 'c': flags |= RB_CONFIG; break; case 'd': flags |= RB_KDB; break; + case 'g': flags |= RB_GDB; break; case 'h': flags ^= RB_SERIAL; break; case 's': flags |= RB_SINGLE; break; case 'v': flags |= RB_VERBOSE; break; diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 index 9b217436cca4..090296cc41f7 100644 --- a/sys/i386/conf/files.i386 +++ b/sys/i386/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.137 1996/07/05 18:49:01 jhay Exp $ +# $Id: files.i386,v 1.138 1996/07/08 19:44:30 wollman Exp $ # aic7xxx_asm optional ahc device-driver \ dependency "$S/dev/aic7xxx/aic7xxx_asm.c" \ @@ -40,6 +40,7 @@ i386/i386/cons.c standard i386/i386/db_disasm.c optional ddb i386/i386/db_interface.c optional ddb i386/i386/db_trace.c optional ddb +i386/i386/i386-gdbstub.c optional ddb i386/i386/exception.s standard i386/i386/identcpu.c standard i386/i386/in_cksum.c optional inet diff --git a/sys/i386/i386/db_interface.c b/sys/i386/i386/db_interface.c index db7e06031524..159400c4dbae 100644 --- a/sys/i386/i386/db_interface.c +++ b/sys/i386/i386/db_interface.c @@ -23,7 +23,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: db_interface.c,v 1.18 1996/04/07 18:34:59 bde Exp $ + * $Id: db_interface.c,v 1.19 1996/05/03 21:00:51 phk Exp $ */ /* @@ -48,6 +48,7 @@ #include static int db_active = 0; +extern void gdb_handle_exception __P((db_regs_t *, int, int)); db_regs_t ddb_regs; @@ -93,7 +94,7 @@ kdb_trap(type, code, regs) * our breakpoints by disarming our breakpoints and fixing up * %eip. */ - if (cons_unavail) { + if (cons_unavail && !(boothowto & RB_GDB)) { if (type == T_TRCTRAP) { regs->tf_eflags &= ~PSL_T; return (1); @@ -133,7 +134,10 @@ kdb_trap(type, code, regs) db_active++; cnpollc(TRUE); - db_trap(type, code); + if (boothowto & RB_GDB) + gdb_handle_exception(&ddb_regs, type, code); + else + db_trap(type, code); cnpollc(FALSE); db_active--; @@ -267,7 +271,7 @@ Debugger(msg) * OK if the call is for the debugger hotkey but not if the call * is a weak form of panicing. */ - if (cons_unavail) + if (cons_unavail & !(boothowto & RB_GDB)) return; if (!in_Debugger) { diff --git a/sys/i386/i386/i386-gdbstub.c b/sys/i386/i386/i386-gdbstub.c new file mode 100644 index 000000000000..41b72afaff3c --- /dev/null +++ b/sys/i386/i386/i386-gdbstub.c @@ -0,0 +1,583 @@ +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for FreeBSD by Stu Grossman. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + * The external function exceptionHandler() is + * used to attach a specific handler to a specific 386 vector number. + * It should use the same privilege level it runs at. It should + * install it as an interrupt gate so that interrupts are masked + * while the handler runs. + * Also, need to assign exceptionHook and oldExceptionHook. + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************/ + +void gdb_handle_exception (db_regs_t *, int, int); + +extern jmp_buf db_jmpbuf; +extern void db_read_bytes (vm_offset_t addr, int size, char *data); +extern void db_write_bytes (vm_offset_t addr, int size, char *data); +extern void siocnputc (dev_t, int c); +extern int siocngetc (dev_t); + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 400 + +/* Create private copies of common functions used by the stub. This prevents + nasty interactions between app code and the stub (for instance if user steps + into strlen, etc..) */ + +static int +strlen (const char *s) +{ + const char *s1 = s; + + while (*s1++ != '\000'); + + return s1 - s; +} + +static char * +strcpy (char *dst, const char *src) +{ + char *retval = dst; + + while ((*dst++ = *src++) != '\000'); + + return retval; +} + +static int +putDebugChar (int c) /* write a single character */ +{ + siocnputc (NULL, c); + return 1; +} + +static int +getDebugChar (void) /* read and return a single char */ +{ + return siocngetc (NULL); +} + +static const char hexchars[]="0123456789abcdef"; + +static int +hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10); + if ((ch >= '0') && (ch <= '9')) return (ch-'0'); + if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10); + return (-1); +} + +/* scan for the sequence $# */ +static void +getpacket (char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + unsigned char ch; + + do + { + /* wait around for the start character, ignore all other characters */ + + while ((ch = (getDebugChar () & 0x7f)) != '$'); + + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + + while (count < BUFMAX) + { + ch = getDebugChar () & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') + { + xmitcsum = hex (getDebugChar () & 0x7f) << 4; + xmitcsum += hex (getDebugChar () & 0x7f); + + if (checksum != xmitcsum) + putDebugChar ('-'); /* failed checksum */ + else + { + putDebugChar ('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') + { + putDebugChar (buffer[0]); + putDebugChar (buffer[1]); + + /* remove sequence chars from buffer */ + + count = strlen (buffer); + for (i=3; i <= count; i++) + buffer[i-3] = buffer[i]; + } + } + } + } + while (checksum != xmitcsum); +} + +/* send the packet in buffer. */ + +static void +putpacket (char *buffer) +{ + unsigned char checksum; + int count; + unsigned char ch; + + /* $#. */ + do + { + putDebugChar ('$'); + checksum = 0; + count = 0; + + while (ch=buffer[count]) + { + putDebugChar (ch); + checksum += ch; + count += 1; + } + + putDebugChar ('#'); + putDebugChar (hexchars[checksum >> 4]); + putDebugChar (hexchars[checksum & 0xf]); + } + while ((getDebugChar () & 0x7f) != '+'); +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +static int +get_char (vm_offset_t addr) +{ + char data; + + if (setjmp (db_jmpbuf)) + return -1; + + db_read_bytes (addr, 1, &data); + + return data & 0xff; +} + +static int +set_char (vm_offset_t addr, int val) +{ + char data; + + if (setjmp (db_jmpbuf)) + return -1; + + data = val; + + db_write_bytes (addr, 1, &data); + return 0; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ + +static char * +mem2hex (vm_offset_t mem, char *buf, int count) +{ + int i; + int ch; + + for (i=0;i> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + return(buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +static char * +hex2mem (char *buf, vm_offset_t mem, int count) +{ + int i; + int ch; + int rv; + + for (i=0;i=0) + { + *intValue = (*intValue <<4) | hexValue; + numChars ++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +#define NUMREGBYTES (sizeof registers) +#define PC 8 +#define SP 4 +#define FP 5 +#define NUM_REGS 14 + +/* + * This function does all command procesing for interfacing to gdb. + */ +void +gdb_handle_exception (db_regs_t *raw_regs, int type, int code) +{ + int sigval; + int addr, length; + char * ptr; + struct i386regs { + unsigned int eax; + unsigned int ecx; + unsigned int edx; + unsigned int ebx; + unsigned int esp; + unsigned int ebp; + unsigned int esi; + unsigned int edi; + unsigned int eip; + unsigned int eflags; + unsigned int cs; + unsigned int ss; + unsigned int ds; + unsigned int es; + }; + struct i386regs registers; + + registers.eax = raw_regs->tf_eax; + registers.ebx = raw_regs->tf_ebx; + registers.ecx = raw_regs->tf_ecx; + registers.edx = raw_regs->tf_edx; + + registers.esp = raw_regs->tf_esp; + registers.ebp = raw_regs->tf_ebp; + registers.esi = raw_regs->tf_esi; + registers.edi = raw_regs->tf_edi; + + registers.eip = raw_regs->tf_eip; + registers.eflags = raw_regs->tf_eflags; + + registers.cs = raw_regs->tf_cs; + registers.ss = raw_regs->tf_ss; + registers.ds = raw_regs->tf_ds; + registers.es = raw_regs->tf_es; + + /* reply to host that an exception has occurred */ + sigval = computeSignal (type); + ptr = remcomOutBuffer; + + *ptr++ = 'T'; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + + *ptr++ = hexchars[PC >> 4]; + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((vm_offset_t)®isters.eip, ptr, 4); + *ptr++ = ';'; + + *ptr++ = hexchars[FP >> 4]; + *ptr++ = hexchars[FP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((vm_offset_t)®isters.ebp, ptr, 4); + *ptr++ = ';'; + + *ptr++ = hexchars[SP >> 4]; + *ptr++ = hexchars[SP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((vm_offset_t)®isters.esp, ptr, 4); + *ptr++ = ';'; + + *ptr++ = 0; + + putpacket (remcomOutBuffer); + + while (1) + { + remcomOutBuffer[0] = 0; + + getpacket (remcomInBuffer); + switch (remcomInBuffer[0]) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + + case 'g': /* return the value of the CPU registers */ + mem2hex ((vm_offset_t)®isters, remcomOutBuffer, NUMREGBYTES); + break; + + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (&remcomInBuffer[1], (vm_offset_t)®isters, NUMREGBYTES); + strcpy (remcomOutBuffer, "OK"); + break; + + case 'P': /* Set the value of one register */ + { + int regno; + + ptr = &remcomInBuffer[1]; + + if (hexToInt (&ptr, ®no) + && *ptr++ == '=' + && regno < NUM_REGS) + { + hex2mem (ptr, (vm_offset_t)®isters + regno * 4, 4); + strcpy(remcomOutBuffer,"OK"); + } + else + strcpy (remcomOutBuffer, "P01"); + break; + } + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* Try to read %x,%x. */ + + ptr = &remcomInBuffer[1]; + + if (hexToInt (&ptr, &addr) + && *(ptr++) == ',' + && hexToInt (&ptr, &length)) + { + if (mem2hex((vm_offset_t) addr, remcomOutBuffer, length) == NULL) + strcpy (remcomOutBuffer, "E03"); + break; + } + else + strcpy (remcomOutBuffer, "E01"); + break; + + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + + /* Try to read '%x,%x:'. */ + + ptr = &remcomInBuffer[1]; + + if (hexToInt(&ptr,&addr) + && *(ptr++) == ',' + && hexToInt(&ptr, &length) + && *(ptr++) == ':') + { + if (hex2mem(ptr, (vm_offset_t) addr, length) == NULL) + strcpy (remcomOutBuffer, "E03"); + else + strcpy (remcomOutBuffer, "OK"); + } + else + strcpy (remcomOutBuffer, "E02"); + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 'c' : + case 's' : + /* try to read optional parameter, pc unchanged if no parm */ + + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr,&addr)) + registers.eip = addr; + + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') + registers.eflags |= PSL_T; + else + registers.eflags &= ~PSL_T; + + raw_regs->tf_eax = registers.eax; + raw_regs->tf_ebx = registers.ebx; + raw_regs->tf_ecx = registers.ecx; + raw_regs->tf_edx = registers.edx; + + raw_regs->tf_esp = registers.esp; + raw_regs->tf_ebp = registers.ebp; + raw_regs->tf_esi = registers.esi; + raw_regs->tf_edi = registers.edi; + + raw_regs->tf_eip = registers.eip; + raw_regs->tf_eflags = registers.eflags; + + raw_regs->tf_cs = registers.cs; + raw_regs->tf_ss = registers.ss; + raw_regs->tf_ds = registers.ds; + raw_regs->tf_es = registers.es; + return; + + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} diff --git a/sys/sys/reboot.h b/sys/sys/reboot.h index ecf6cb89bd71..d4b5ccbb0540 100644 --- a/sys/sys/reboot.h +++ b/sys/sys/reboot.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)reboot.h 8.3 (Berkeley) 12/13/94 - * $Id: reboot.h,v 1.11 1996/03/11 02:09:55 hsu Exp $ + * $Id: reboot.h,v 1.12 1996/08/22 03:50:32 julian Exp $ */ #ifndef _SYS_REBOOT_H_ @@ -58,6 +58,7 @@ #define RB_SERIAL 0x1000 /* user serial port as console */ #define RB_CDROM 0x2000 /* use cdrom as root */ #define RB_POWEROFF 0x4000 /* if you can, turn the power off */ +#define RB_GDB 0x8000 /* use GDB remote debugger instead of DDB */ #define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */