summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authordfr <dfr@FreeBSD.org>1998-07-05 12:24:18 +0000
committerdfr <dfr@FreeBSD.org>1998-07-05 12:24:18 +0000
commit78bd2b16752c288c894293c92497c3d3fcb856c8 (patch)
treee2b4e85001f2d3f404df0052764d4fab47db3ce0 /sys
parent49590d8c5a39306eaccde9fcb31a5b39751410da (diff)
downloadFreeBSD-src-78bd2b16752c288c894293c92497c3d3fcb856c8.zip
FreeBSD-src-78bd2b16752c288c894293c92497c3d3fcb856c8.tar.gz
Add support for kernel gdb.
Diffstat (limited to 'sys')
-rw-r--r--sys/alpha/alpha/alpha-gdbstub.c746
-rw-r--r--sys/alpha/alpha/db_interface.c51
-rw-r--r--sys/alpha/alpha/machdep.c51
-rw-r--r--sys/alpha/alpha/trap.c19
-rw-r--r--sys/alpha/include/db_machdep.h2
5 files changed, 829 insertions, 40 deletions
diff --git a/sys/alpha/alpha/alpha-gdbstub.c b/sys/alpha/alpha/alpha-gdbstub.c
new file mode 100644
index 0000000..f632e8a
--- /dev/null
+++ b/sys/alpha/alpha/alpha-gdbstub.c
@@ -0,0 +1,746 @@
+/****************************************************************************
+
+ 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 its 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 its 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)
+ *
+ * D detach OK
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * 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 <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/systm.h>
+#include <sys/signal.h>
+
+#include <machine/reg.h>
+#include <machine/cons.h>
+
+#include <ddb/ddb.h>
+
+#include <setjmp.h>
+
+/* #include "sio.h" */
+#include "opt_ddb.h"
+
+#define NSIO 1
+
+#if NSIO == 0
+void
+gdb_handle_exception (db_regs_t *raw_regs, int type, int code)
+{
+}
+#else
+/************************************************************************/
+
+void gdb_handle_exception (db_regs_t *, int, int);
+
+extern jmp_buf db_jmpbuf;
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+#define BUFMAX 1500
+
+/* 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..) */
+/* XXX this is fairly bogus. strlen() and strcpy() should be reentrant,
+ and are reentrant under FreeBSD. In any case, our versions should not
+ be named the same as the standard versions, so that the address `strlen'
+ is unambiguous... */
+
+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;
+}
+
+/* XXX sio always uses its major with minor 0 no matter what we specify. */
+#define REMOTE_DEV 0
+
+static int
+putDebugChar (int c) /* write a single character */
+{
+ siocnputc (REMOTE_DEV, c);
+ return 1;
+}
+
+static int
+getDebugChar (void) /* read and return a single char */
+{
+ return siocngetc (REMOTE_DEV);
+}
+
+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 $<data>#<checksum> */
+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);
+
+ if (strlen(buffer) >= BUFMAX)
+ panic("kgdb: buffer overflow");
+}
+
+/* send the packet in buffer. */
+
+static void
+putpacket (char *buffer)
+{
+ unsigned char checksum;
+ int count;
+ unsigned char ch;
+
+ if (strlen(buffer) >= BUFMAX)
+ panic("kgdb: buffer overflow");
+
+ /* $<packet info>#<checksum>. */
+ do
+ {
+/*
+ * This is a non-standard hack to allow use of the serial console for
+ * operation as well as debugging. Simply turn on 'remotechat' in gdb.
+ *
+ * This extension is not part of the Cygnus protocol, is kinda gross,
+ * but gets the job done.
+ */
+#ifdef GDB_REMOTE_CHAT
+ putDebugChar ('|');
+ putDebugChar ('|');
+ putDebugChar ('|');
+ putDebugChar ('|');
+#endif
+ 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<count;i++) {
+ ch = get_char (mem++);
+ if (ch == -1)
+ return NULL;
+ *buf++ = hexchars[ch >> 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<count;i++) {
+ ch = hex(*buf++) << 4;
+ ch = ch + hex(*buf++);
+ rv = set_char (mem++, ch);
+ if (rv == -1)
+ return NULL;
+ }
+ return(buf);
+}
+
+/* this function takes the 386 exception vector and attempts to
+ translate this number into a unix compatible signal value */
+static int
+computeSignal (int entry, int code)
+{
+ switch (entry) {
+ case ALPHA_KENTRY_INT:
+ case ALPHA_KENTRY_ARITH:
+ return SIGILL; /* ? can this happen? */
+ case ALPHA_KENTRY_MM:
+ switch (code) {
+ case ALPHA_MMCSR_INVALTRANS:
+ return SIGSEGV;
+ case ALPHA_MMCSR_ACCESS:
+ case ALPHA_MMCSR_FOR:
+ case ALPHA_MMCSR_FOE:
+ case ALPHA_MMCSR_FOW:
+ return SIGBUS;
+ }
+ case ALPHA_KENTRY_IF:
+ switch (code) {
+ case ALPHA_IF_CODE_BUGCHK:
+ case ALPHA_IF_CODE_BPT:
+ return SIGTRAP;
+ case ALPHA_IF_CODE_GENTRAP:
+ case ALPHA_IF_CODE_FEN:
+ case ALPHA_IF_CODE_OPDEC:
+ return SIGILL;
+ }
+ case ALPHA_KENTRY_UNA:
+ return SIGSEGV;
+ case ALPHA_KENTRY_SYS:
+ return SIGILL;
+ }
+ return SIGILL;
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+
+static int
+hexToInt(char **ptr, long *intValue)
+{
+ int numChars = 0;
+ int hexValue;
+
+ *intValue = 0;
+
+ while (**ptr)
+ {
+ hexValue = hex(**ptr);
+ if (hexValue >=0)
+ {
+ *intValue = (*intValue <<4) | hexValue;
+ numChars ++;
+ }
+ else
+ break;
+
+ (*ptr)++;
+ }
+
+ return (numChars);
+}
+
+static enum {
+ NONE,
+ NORMAL,
+ BRANCH
+} ss_mode = NONE;
+
+struct ss_bpt {
+ int active;
+ vm_offset_t addr;
+ u_int32_t contents;
+};
+
+static struct ss_bpt ss_bp1, ss_bp2;
+
+static int
+set_bpt(struct ss_bpt* bp)
+{
+ u_int32_t bp_ins = BKPT_INST;
+ if (bp->active) return 0;
+ if (badaddr((caddr_t)bp->addr, 4))
+ return 0;
+ db_read_bytes(bp->addr, 4, (caddr_t) &bp->contents);
+ db_write_bytes(bp->addr, 4, (caddr_t) &bp_ins);
+ bp->active = 1;
+ return 1;
+}
+
+static void
+clear_bpt(struct ss_bpt* bp)
+{
+ if (!bp->active) return;
+ if (badaddr((caddr_t) bp->addr, 4))
+ return;
+ db_write_bytes(bp->addr, 4, (caddr_t) &bp->contents);
+ bp->active = 0;
+}
+
+static int
+set_single_step(db_regs_t* regs)
+{
+ u_int32_t ins;
+ vm_offset_t pc = regs->tf_regs[FRAME_PC];
+
+ if (ss_mode != NONE) {
+ printf("single_step botch\n");
+ return 0;
+ }
+
+ if (badaddr((caddr_t) pc, 4))
+ return 0;
+ db_read_bytes(pc, 4, (caddr_t) &ins);
+ ss_bp1.addr = pc + 4;
+ if (db_inst_branch(ins)) {
+ ss_bp2.addr = db_branch_taken(ins, pc, regs);
+ if (!set_bpt(&ss_bp1))
+ return 0;
+ if (!set_bpt(&ss_bp2)) {
+ clear_bpt(&ss_bp1);
+ return 0;
+ }
+ ss_mode = BRANCH;
+ } else {
+ if (!set_bpt(&ss_bp1))
+ return 0;
+ ss_mode = NORMAL;
+ }
+
+ return 1;
+}
+
+static void
+clear_single_step(db_regs_t* regs)
+{
+ /* if we hit one of the step breakpoints, adjust pc */
+ if (ss_mode == BRANCH)
+ {
+ /* remove in reverse order in case they are at the same address */
+ if (regs->tf_regs[FRAME_PC] == ss_bp1.addr + 4
+ || regs->tf_regs[FRAME_PC] == ss_bp2.addr + 4)
+ regs->tf_regs[FRAME_PC] -= 4;
+ clear_bpt(&ss_bp2);
+ clear_bpt(&ss_bp1);
+ }
+ else if (ss_mode == NORMAL)
+ {
+ if (regs->tf_regs[FRAME_PC] == ss_bp1.addr + 4)
+ regs->tf_regs[FRAME_PC] -= 4;
+ clear_bpt(&ss_bp1);
+ }
+ ss_mode = NONE;
+}
+
+#define NUMREGBYTES (sizeof registers)
+#define PC 64
+#define SP 30
+#define FP 15
+#define VFP 65
+#define NUM_REGS 66
+
+/*
+ * Map trapframe indices into gdb (integer) register indices.
+ * Entries not in integer register set are set to -1.
+ */
+static int tf2gdb[FRAME_SIZE] = {
+ R_V0, R_T0, R_T1, R_T2, R_T3, R_T4, R_T5, R_T6,
+ R_T7, R_S0, R_S1, R_S2, R_S3, R_S4, R_S5, R_S6,
+ R_A3, R_A4, R_A5, R_T8, R_T9, R_T10, R_T11, R_RA,
+ R_T12, R_AT, R_SP, -1, -1, R_GP, R_A0, R_A1,
+ R_A2,
+};
+
+/*
+ * Map gdb register indices back to trapframe.
+ * Entries not in trapframe are set to -1.
+ */
+static int gdb2tf[NUM_REGS] = {
+ /* integer registers */
+ FRAME_V0, FRAME_T0, FRAME_T1, FRAME_T2,
+ FRAME_T3, FRAME_T4, FRAME_T5, FRAME_T6,
+ FRAME_T7, FRAME_S0, FRAME_S1, FRAME_S2,
+ FRAME_S3, FRAME_S4, FRAME_S5, FRAME_S6,
+ FRAME_A0, FRAME_A1, FRAME_A2, FRAME_A3,
+ FRAME_A4, FRAME_A5, FRAME_T8, FRAME_T9,
+ FRAME_T10, FRAME_T11, FRAME_RA, FRAME_T12,
+ FRAME_AT, FRAME_GP, FRAME_SP, -1,
+ /* float registers */
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /* misc registers */
+ FRAME_PC, -1,
+};
+
+/*
+ * 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;
+ long addr, length;
+ char * ptr;
+ struct alpharegs {
+ u_int64_t r[32];
+ u_int64_t f[32];
+ u_int64_t pc, vfp;
+ };
+ static struct alpharegs registers;
+ int i;
+
+ clear_single_step(raw_regs);
+
+ bzero(&registers, sizeof registers);
+
+ /*
+ * Map trapframe to registers.
+ * Ignore float regs for now.
+ */
+ for (i = 0; i < FRAME_SIZE; i++)
+ if (tf2gdb[i] > 0)
+ registers.r[tf2gdb[i]] = raw_regs->tf_regs[i];
+ registers.pc = raw_regs->tf_regs[FRAME_PC];
+
+ /* reply to host that an exception has occurred */
+ sigval = computeSignal (type, code);
+ 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)&registers.pc, ptr, 8);
+ *ptr++ = ';';
+
+ *ptr++ = hexchars[FP >> 4];
+ *ptr++ = hexchars[FP & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex ((vm_offset_t)&registers.r[FP], ptr, 8);
+ *ptr++ = ';';
+
+ *ptr++ = hexchars[SP >> 4];
+ *ptr++ = hexchars[SP & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex ((vm_offset_t)&registers.r[SP], ptr, 8);
+ *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 'D': /* detach; say OK and turn off gdb */
+ putpacket(remcomOutBuffer);
+ boothowto &= ~RB_GDB;
+ return;
+
+ case 'k':
+ prom_halt();
+ /*NOTREACHED*/
+ break;
+
+ case 'g': /* return the value of the CPU registers */
+ mem2hex ((vm_offset_t)&registers, remcomOutBuffer, NUMREGBYTES);
+ break;
+
+ case 'G': /* set the value of the CPU registers - return OK */
+ hex2mem (&remcomInBuffer[1], (vm_offset_t)&registers, NUMREGBYTES);
+ strcpy (remcomOutBuffer, "OK");
+ break;
+
+ case 'P': /* Set the value of one register */
+ {
+ long regno;
+
+ ptr = &remcomInBuffer[1];
+
+ if (hexToInt (&ptr, &regno)
+ && *ptr++ == '='
+ && regno < NUM_REGS)
+ {
+ hex2mem (ptr, (vm_offset_t)&registers + regno * 8, 8);
+ 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.pc = addr;
+
+ /*
+ * Map gdb registers back to trapframe (ignoring fp regs).
+ */
+ for (i = 0; i < NUM_REGS; i++)
+ if (gdb2tf[i] > 0)
+ raw_regs->tf_regs[gdb2tf[i]] = registers.r[i];
+ raw_regs->tf_regs[FRAME_PC] = registers.pc;
+
+ if (remcomInBuffer[0] == 's')
+ if (!set_single_step(raw_regs))
+ printf("Can't set single step breakpoint\n");
+
+ return;
+
+ } /* switch */
+
+ /* reply to the request */
+ putpacket (remcomOutBuffer);
+ }
+}
+#endif /* NSIO > 0 */
diff --git a/sys/alpha/alpha/db_interface.c b/sys/alpha/alpha/db_interface.c
index ec42c89..99bae72 100644
--- a/sys/alpha/alpha/db_interface.c
+++ b/sys/alpha/alpha/db_interface.c
@@ -72,6 +72,12 @@
#include <ddb/db_access.h>
#include <ddb/db_sym.h>
#include <ddb/db_variables.h>
+#include <setjmp.h>
+
+static jmp_buf *db_nofault = 0;
+extern jmp_buf db_jmpbuf;
+
+extern void gdb_handle_exception __P((db_regs_t *, int, int));
extern label_t *db_recover;
@@ -142,10 +148,11 @@ ddbprinttrap(a0, a1, a2, entry)
* ddb_trap - field a kernel trap
*/
int
-ddb_trap(a0, a1, a2, entry, regs)
+kdb_trap(a0, a1, a2, entry, regs)
unsigned long a0, a1, a2, entry;
db_regs_t *regs;
{
+ int ddb_mode = !(boothowto & RB_GDB);
int s;
/*
@@ -158,26 +165,21 @@ ddb_trap(a0, a1, a2, entry, regs)
if (entry != ALPHA_KENTRY_IF ||
(a0 != ALPHA_IF_CODE_BUGCHK && a0 != ALPHA_IF_CODE_BPT
&& a0 != ALPHA_IF_CODE_GENTRAP)) {
- db_printf("ddbprinttrap from 0x%lx\n", /* XXX */
- regs->tf_regs[FRAME_PC]);
- ddbprinttrap(a0, a1, a2, entry);
-#if 0
- if (db_recover != 0) {
+ if (ddb_mode) {
+ db_printf("ddbprinttrap from 0x%lx\n", /* XXX */
+ regs->tf_regs[FRAME_PC]);
+ ddbprinttrap(a0, a1, a2, entry);
/*
- * XXX Sould longjump back into command loop!
+ * Tell caller "We did NOT handle the trap."
+ * Caller should panic, or whatever.
*/
- db_printf("Faulted in DDB; continuing...\n");
- alpha_pal_halt(); /* XXX */
- db_error("Faulted in DDB; continuing...\n");
- /* NOTREACHED */
+ return (0);
+ }
+ if (db_nofault) {
+ jmp_buf *no_fault = db_nofault;
+ db_nofault = 0;
+ longjmp(*no_fault, 1);
}
-#endif
-
- /*
- * Tell caller "We did NOT handle the trap."
- * Caller should panic, or whatever.
- */
- return (0);
}
/*
@@ -191,7 +193,10 @@ ddb_trap(a0, a1, a2, entry, regs)
db_active++;
cnpollc(TRUE); /* Set polling mode, unblank video */
- db_trap(entry, a0); /* Where the work happens */
+ if (ddb_mode)
+ db_trap(entry, a0); /* Where the work happens */
+ else
+ gdb_handle_exception(&ddb_regs, entry, a0);
cnpollc(FALSE); /* Resume interrupt mode */
db_active--;
@@ -217,9 +222,13 @@ db_read_bytes(addr, size, data)
{
register char *src;
+ db_nofault = &db_jmpbuf;
+
src = (char *)addr;
while (size-- > 0)
*data++ = *src++;
+
+ db_nofault = 0;
}
/*
@@ -233,10 +242,14 @@ db_write_bytes(addr, size, data)
{
register char *dst;
+ db_nofault = &db_jmpbuf;
+
dst = (char *)addr;
while (size-- > 0)
*dst++ = *data++;
alpha_pal_imb();
+
+ db_nofault = 0;
}
void
diff --git a/sys/alpha/alpha/machdep.c b/sys/alpha/alpha/machdep.c
index aa4c791..27912cc 100644
--- a/sys/alpha/alpha/machdep.c
+++ b/sys/alpha/alpha/machdep.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: machdep.c,v 1.3 1998/06/10 20:35:10 dfr Exp $
+ * $Id: machdep.c,v 1.4 1998/06/28 00:45:50 dfr Exp $
*/
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -524,8 +524,45 @@ alpha_init(pfn, ptb, bim, bip, biv)
* information provided by the boot program).
*/
bootinfo_msg = NULL;
- if (0) {
- /* bootinfo goes here */
+ if (bim == BOOTINFO_MAGIC) {
+ if (biv == 0) { /* backward compat */
+ biv = *(u_long *)bip;
+ bip += 8;
+ }
+ switch (biv) {
+ case 1: {
+ struct bootinfo_v1 *v1p = (struct bootinfo_v1 *)bip;
+
+ bootinfo.ssym = v1p->ssym;
+ bootinfo.esym = v1p->esym;
+ /* hwrpb may not be provided by boot block in v1 */
+ if (v1p->hwrpb != NULL) {
+ bootinfo.hwrpb_phys =
+ ((struct rpb *)v1p->hwrpb)->rpb_phys;
+ bootinfo.hwrpb_size = v1p->hwrpbsize;
+ } else {
+ bootinfo.hwrpb_phys =
+ ((struct rpb *)HWRPB_ADDR)->rpb_phys;
+ bootinfo.hwrpb_size =
+ ((struct rpb *)HWRPB_ADDR)->rpb_size;
+ }
+ bcopy(v1p->boot_flags, bootinfo.boot_flags,
+ min(sizeof v1p->boot_flags,
+ sizeof bootinfo.boot_flags));
+ bcopy(v1p->booted_kernel, bootinfo.booted_kernel,
+ min(sizeof v1p->booted_kernel,
+ sizeof bootinfo.booted_kernel));
+ /* booted dev not provided in bootinfo */
+ init_prom_interface((struct rpb *)
+ ALPHA_PHYS_TO_K0SEG(bootinfo.hwrpb_phys));
+ prom_getenv(PROM_E_BOOTED_DEV, bootinfo.booted_dev,
+ sizeof bootinfo.booted_dev);
+ break;
+ }
+ default:
+ bootinfo_msg = "unknown bootinfo version";
+ goto nobootinfo;
+ }
} else {
bootinfo_msg = "boot program did not pass bootinfo";
nobootinfo:
@@ -555,6 +592,7 @@ alpha_init(pfn, ptb, bim, bip, biv)
prom_getenv(PROM_E_BOOTED_DEV, bootinfo.booted_dev,
sizeof bootinfo.booted_dev);
}
+ printf("ssym=%lx, esym=%lx\n", bootinfo.ssym, bootinfo.esym);
/*
* Initialize the kernel's mapping of the RPB. It's needed for
@@ -877,6 +915,7 @@ alpha_init(pfn, ptb, bim, bip, biv)
#ifdef KADB
boothowto |= RB_KDB;
#endif
+/* boothowto |= RB_KDB | RB_GDB; */
for (p = bootinfo.boot_flags; p && *p != '\0'; p++) {
/*
* Note that we'd really like to differentiate case here,
@@ -896,11 +935,15 @@ alpha_init(pfn, ptb, bim, bip, biv)
break;
#endif
-#if defined(KGDB) || defined(DDB)
+#if defined(DDB)
case 'd': /* break into the kernel debugger ASAP */
case 'D':
boothowto |= RB_KDB;
break;
+ case 'g': /* use kernel gdb */
+ case 'G':
+ boothowto |= RB_GDB;
+ break;
#endif
case 'h': /* always halt, never reboot */
diff --git a/sys/alpha/alpha/trap.c b/sys/alpha/alpha/trap.c
index 9fbabbb..c6cd53f 100644
--- a/sys/alpha/alpha/trap.c
+++ b/sys/alpha/alpha/trap.c
@@ -1,4 +1,4 @@
-/* $Id: trap.c,v 1.2 1998/06/10 20:12:22 dfr Exp $ */
+/* $Id: trap.c,v 1.3 1998/06/28 00:47:20 dfr Exp $ */
/* $NetBSD: trap.c,v 1.31 1998/03/26 02:21:46 thorpej Exp $ */
/*
@@ -273,7 +273,7 @@ trap(a0, a1, a2, entry, framep)
|| a0 == ALPHA_IF_CODE_GENTRAP
#endif
) {
- if (ddb_trap(a0, a1, a2, entry, framep))
+ if (kdb_trap(a0, a1, a2, entry, framep))
goto out;
}
@@ -467,20 +467,7 @@ dopanic:
/* XXX dump registers */
#ifdef DDB
- /* XXX
- * Really would like to be able to indicate that the
- * kernel should _not_ panic, here. However, two problems
- * exist:
- *
- * (a) There is not currently a way for DDB to distinguish
- * between "continue and panic" and "continue, and
- * don't panic".
- *
- * (b) panic() will again invoke the debugger, so calling
- * it here is silly.
- *
- * For now, we just do nothing.
- */
+ kdb_trap(a0, a1, a2, entry, framep);
#endif
panic("trap");
diff --git a/sys/alpha/include/db_machdep.h b/sys/alpha/include/db_machdep.h
index a8c6b1f..1824cd9 100644
--- a/sys/alpha/include/db_machdep.h
+++ b/sys/alpha/include/db_machdep.h
@@ -100,7 +100,7 @@ db_addr_t db_branch_taken __P((int inst, db_addr_t pc, db_regs_t *regs));
#define next_instr_address(v, b) ((db_addr_t) ((b) ? (v) : ((v) + 4)))
u_long db_register_value __P((db_regs_t *, int));
-int ddb_trap __P((unsigned long, unsigned long, unsigned long,
+int kdb_trap __P((unsigned long, unsigned long, unsigned long,
unsigned long, struct trapframe *));
/*
OpenPOWER on IntegriCloud