static char rcsid[] = "$Header: debugger.c,v 820.1 86/12/04 19:53:08 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*	debug.c	1.00	84/01/25	*/

/*
 * History:
 * ========
 * 8602xx elp -- Added support for r  ==> format "struct proc";
 * 8602xx jht -- Added support for W  ==> "wakeup(accum)";
 * 8603xx jht -- Added support for I  ==> format "struct inode";
 * 860321 jht -- Rationalize and tidy up H ==> "help";
 * 8603xx jht -- Added support for U^ ==> format "struct user";
 * 8603xx jht -- Added support for P^ ==> synonym for 'r': proc display;
 * 8603xx jht -- Added support for E^ ==> format "struct exceptionFrame";
 * 8603xx jht -- Added support for S^ ==> format statistics and time-info;
 * 8603xx jht -- Added support for C^ ==> format "struct ctxt";
 * 860403 jht -- Added support for F^ ==> format "struct file";
 * 860405 jht -- Added support for m  ==> display 16 bytes of memory a'la 'M';
 * 860519 jht -- Augment mmu subsystem with CMD_BINGO debugging facility..
 * 860602 jht -- Add 'quicken' facility: jsr lmul ==> 68020 machine code.
 */

#include "../machine/psl.h"
#include "../machine/reg.h"
#include "../machine/pte.h"
#include "../machine/cpu.h"
#include "../machine/ecm.h"
#include "../machine/context.h"
#include "../machine/trap.h"		/* T_TRAPn	   */
#include "../machine/frame.h"		/* Exception frame */

#include "../h/param.h"
#include "../h/vmparam.h"
#include "../h/vmmac.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/seg.h"
#include "../h/text.h"
#include "../h/acct.h"
#include "../h/kernel.h"

#include "../s32/debug.h"
#include "../h/map.h"
#ifdef	VALID_EFS
#include "../efs/efs.h"		/* For F^ command:  "struct file" */
#endif	VALID_EFS

#include "../usr.include/a.out.h"

char	wantdebug;
char	fastdebug = 0;		/* must be in data segment */
#ifdef	BRKDEBUG_ON
char	brkdebug = 1;
#else	BRKDEBUG_ON
char	brkdebug = 0;
#endif	BRKDEBUG_ON

#ifdef	CMD_BINGO		/* C.f., s32/{context.c,map.c,startup.c}    */
short	cmd_BINGO;	  	/* 0==>Disable; 1==>Enable pattern match'g  */
char	cmd_BINGO_cmd[32];	/* Command for which a match ==> "BINGO!"   */
#endif	CMD_BINGO

u_long readmem();

#ifdef	M68000
extern	char		*trap_type_68000[];
#define	trap_type	 trap_type_68000
#endif	M68000

#ifdef	M68010
extern	char *trap_type_68010[];
#endif	M68010

#ifdef	M68020
extern	char *trap_type_68020[];
#endif	M68020

#define TRAP_TYPES	48	/* All exception types through 'trap #0xf' */
#define	USER		0x1000	/* User-mode flag added to 'type'	   */
#define NOPID		((u_short)(-1))

#define MAXBRK 20
#define BRK_NONE	0		/* No breakpoint set	  */
#define BRK_PERM	1		/* Permanent breakpoint	  */
#define BRK_TEMP	2		/* Temporary breakpoint	  */
#define BRK_SUBR	3		/* End of subroutine step */

#define DBGVEC		(T_TRAP8<<2)	/* Enter debugger vector address    */
#define DBGINST		0x4E48		/* Enter debugger inst: T_TRAP8     */

#define BRKVEC		(T_TRAP9<<2)	/* Breakpoint vector address	    */
#define BRKINST		0x4E49		/* Breakpoint instruction: T_TRAP9) */
#define BRKLEN		2		/* Length of break inst bytes       */

#define BERRVEC		(T_BUSERR<<2)	/* Bus	   Error vector address	*/
#define AERRVEC		(T_ADDRERR<<2)	/* Address Error vector address	*/
#define TRCVEC		0x24		/* Trace	 vector address	*/

#define JSRINST		0x4EB9		/* First word of subroutine call    */
#define JSRLEN		6		/* # of bytes in a subroutine call  */
#define RTSINST		0x4E75		/* Return from subroutine inst.	    */

#define DEBUG_VA	0x2000		/* Base of debugger play area		*/
#define DEBUG_PAGE	0x2		/* 1st page the debugger plays with */
#define DEBUG_PAGES	10		/* # of pages the debugger may use  */
#define DEBUG_SYMPAGES	DEBUG_PAGES

	/* Formats for address spaces and sizes */

#define FMT_KERNEL	0x0001
#define FMT_PHYS	0x0002
#define FMT_USER	0x0004
#define FMT_INSTR	0x0008
#define FMT_DATA	0x0010
#define FMT_CPU		0x0020
#define FMT_BYTE	0x0040
#define FMT_SHORT	0x0080
#define FMT_LONG	0x0100

/*
 * Dangerous commands must be typed twice.  We
 * keep a bit mask to store the previous command
 * to simplify the checking.
 */

	/* Every other bit here ... */

#define DANGER_RESTART	0x0001
#define DANGER_VRM	0x0004

#define DANGER_ALL	(DANGER_RESTART | DANGER_VRM)

struct bpt
{
	u_long	addr;		/* Address of the breakpoint */
	u_short	content;	/* Contents of the address */
	u_short	pid;		/* Process ID to which breakpoint belongs */
	u_char	type;		/* Type of breakpoint */
	u_char	extra[7];	/* Filller */
} bpt[MAXBRK];

u_long	*userregs;		/* User's registers */
u_long	dbgregs[NIPCREG];	/* Current registers */
u_long	keptregs[NIPCREG];	/* Registers which have been kept */

char	debugstack[1000];	/* Debugger runs with it's stack in here */
char	*dbgstktop = &debugstack[1000]; /* Top of stack (where SP starts) */

int	tracing;		/* Set if we are tracing */
int	tracingcalls;		/* Set if we are only tracing calls */
long	savetrace;		/* Saved value of trace vector */

long	skipaddr = -1;		/* Address to skip breakpoint for */
int	nbrk;			/* Number of breakpoints */
u_short	dbgtype;		/* Type of debug entry (vector offset) */
label_t	myfault;		/* longjmp via this buffer on memory fault */

u_short	savedmap[DEBUG_PAGES];	/* Place to save when mapping things in */
int	savedcount;		/* Number of valid entries in savedmap */

int	fastbreak;		/* Set so first break enables debugger */

breakkey()
{
#ifdef SLOWDEBUG
	static long lastbreak = 0;
	static int state = 0;
	int s = spl6();

	if (state == 1 &&
	    2 <= time.tv_sec-lastbreak && time.tv_sec-lastbreak <= 3)
		state = 2;
	else if (state == 2 && time.tv_sec == lastbreak)
	{
		state = 0;
		wantdebug = 1;
	}
	else
		state = 1;
	if (fastdebug)
		wantdebug = 1;
	lastbreak = time.tv_sec;
	splx(s);
#else SLOWDEBUG
	wantdebug = 1;
#endif SLOWDEBUG
}

cdebugger(msg)
   char *msg;
{
	extern dbgtrap();

	printf("cdebugger entered: %s\n", msg);
	*(u_long *)DBGVEC = (u_long)dbgtrap;	/* Trap #8 for debugger	*/
	asm("trap #8");				/* T_TRAP8		*/
}

#ifdef	WHITE_V_PRESENT
#define DummyMap  (btop(DUMMYU_PA)|V_PRESENT)
#else	WHITE_V_PRESENT
#define DummyMap  (btop(DUMMYU_PA))
#endif	WHITE_V_PRESENT

/*
 * Processor dependent values
 * from busErr or addrErr exception stack.
 * These are allocated within locore.s
 */
#if	defined(M68000) || defined(M68010) || defined(M68020)
extern	u_short	ctxtReg;	/* Context at time of the bus/addr fault */
extern	u_short	iReg;		/* Instruction which caused fault	 */
extern	u_long	aAddr;		/* (Virt.) Address of the bus/addr fault */
#endif	defined(M68000) || defined(M68010) || defined(M68020)

int	wildAndWoolly = 0;	/* 1==> Remap our u-page! 0==> Don't. */

/*
 * Canned commands to execute during each cycle of debugging.
 * Use the 'B^' command to gate the string into the command parser.
 */
short	doCannedCmd	= 0; /* 0==>Disable; ~0==>Enable parsing of cannedCmd */
char	cannedCmds[256]	= "=hyperMmu=liiiBL";
char  * cannedCmdp	= cannedCmds;

debugger()
{
	int oldpri = spl7();
	int *oldar0 = u.u_ar0;
	u_long accum = 0;
	u_long value = 0;
	u_long	saveberr,saveaerr;
	int count;
	int temp;
	char aspace = 'v';
	char spacetype = 'k';
	int spacefmt = FMT_KERNEL;
	int dangerous = 0;
	extern int symbytes;
	extern tracer(), dbgtrap(), bpttrap(), memfault();
#ifdef WHITE
	int	omode;
#endif WHITE

	*(u_long *)DBGVEC = (u_long)dbgtrap;	/* trap #8 for debugger */
	wantdebug = 0;
	u.u_ar0 = (int *)dbgregs;
	if (nbrk)
		xchbrk();
#ifdef WHITE
	omode = dsonemode(0);
#endif WHITE
	switch (dbgtype & 0xFFF)
	{
	case BRKVEC:
	{
		register struct bpt *bp = &bpt[0];
		char disasmstr[30];
		int issubr = 0;

		dbgregs[PC] -= BRKLEN;
		for (; bp != &bpt[MAXBRK]; ++bp)
			if ((bp->type == BRK_TEMP || bp->type == BRK_SUBR) &&
			    bp->addr == dbgregs[PC])
			{
				if (bp->type == BRK_SUBR)
					issubr = 1;
				bp->type = BRK_NONE;
				--nbrk;
				break;
			}
		printf("\nBreakpoint at 0x%x%s\n", dbgregs[PC],
			issubr ? " (subroutine step)" :
				((bp == &bpt[MAXBRK]) ? "" : " (deleted)"));
		if (issubr)
		{
			diffregs(keptregs, dbgregs);
			disasm(dbgregs[PC], disasmstr);
			printf("Next instr 0x%x %s\n", dbgregs[PC], disasmstr);
		}
		break;
	}
	case TRCVEC:
	{
		char disasmstr[30];

		*(long *)TRCVEC = savetrace;
		dbgregs[PS] &= ~PSL_T;
		if (!tracing && skipaddr != -1)
		{
			skipaddr = -1;
			goto cont;	/* Continue execution */
		}
		if (tracingcalls)
		{
			register u_short instr = *(u_short *)dbgregs[PC];

			if (instr == JSRINST)
			{
				register int nargs = 0;
				register u_long *argp;

				printf(" JSR ");
				showoffset(dbgregs[PC]);
				printf(" => ");
				showoffset(*(u_long *)(dbgregs[PC] + 2));
				instr =   *(u_short *)(dbgregs[PC] + 6);
				if (instr == 0x588F)
					nargs = 4 / sizeof(long);
				else if (instr == 0x508F)
					nargs = 8 / sizeof(long);
				else if (instr == 0xDFFC)
					nargs = *(u_long *)(dbgregs[PC] + 8) / sizeof(long);
				if (nargs > 6) nargs = 6;
#ifndef	JHT_OLDWAY
				argp = (u_long *)(dbgregs[SP]+12);
#else	JHT_OLDWAY
				argp = (u_long *)(dbgregs[SP]+16);
#endif	JHT_OLDWAY
				printf("(");
				while (nargs--)
				{
					printf("0x%x", *argp++);
					if (nargs != 0)
						printf(", ");
				}
				printf(")\n");
			}
			else if (instr == RTSINST)
			{
				printf(" RTS ");
				showoffset(dbgregs[PC]);
				printf(" => ");
				showoffset(*(u_long *)(dbgregs[SP]+12));
				printf(", = 0x%x\n", dbgregs[R0]);
			}
			else
				goto cont;
			break;
		}
		printf("\nSingle step trace\n");
		diffregs(keptregs, dbgregs);
		disasm(dbgregs[PC], disasmstr);
		printf("Next instr 0x%x %s\n", dbgregs[PC], disasmstr);
		break;
	}
	default:
		printf("\nDebugger entered from vector offset 0x%x\n", dbgtype);
		/* strace(dbgregs[AR6]); */
		/* prregs(dbgregs); */
		break;
	}
	skipaddr = -1;
	tracingcalls = tracing = 0;
	accum = value = dbgregs[PC];
	saveberr = *(u_long *)BERRVEC;
	saveaerr = *(u_long *)AERRVEC;
	*(u_long *)BERRVEC = (u_long)memfault;
	*(u_long *)AERRVEC = (u_long)memfault;
	while (setjmp(&myfault))
	{
		debugunmap();
		printf("Memory fault\n");
	}
	for (;;)
	{
		register char c;
#ifdef	PANIC_LOGGING
		extern	 int	calledFromPanic;	/* Set in panic() */

		switch (calledFromPanic) {
		/*
		 * Print some nominal information
		 * to documment the panic()...
		 */
		case 3:	c = 'P';	/* Process table	*/
			calledFromPanic--;
			break;

		case 2:	c = 'F';	/* Current stack frame	*/
			calledFromPanic--;
			break;

		case 1:	c = 'U';	/* User's registers	*/
			calledFromPanic--;
			break;

		case 0:
		default:
			calledFromPanic = 0;
			/*
			 * Now we will accept cmds from console.
			 */
			c = getchar();
		}
#else	!PANIC_LOGGING
		if (doCannedCmd) {
			/*
			 * Obtain command characters only from canned buffer
			 * until the latter is exhausted.
			 */
			c = *(char *)	( (   ((u_long)cannedCmdp >= (u_long)&cannedCmds[0])
					   && ((u_long)cannedCmdp <  (u_long)&cannedCmds[sizeof cannedCmds])
					  )
						? cannedCmdp++
						: "\000"	/* Firedoor */
					);
			if (c == 0) {
				doCannedCmd = 0;	/* Terminate */
				c = getchar();
			}
		} else {
			c = getchar();
		}
#endif	!PANIC_LOGGING
	cmd:
		dangerous = (dangerous & ~DANGER_ALL) >> 1;
		debugunmap();
		switch (c)
		{

		/*
		 * "Help":  Display glossary of commands
		 * that are available herewith.
		 */
		case '?':
			printf("?  Print command list\n");
			printf("T  Stack trace\n");
			printf("F  Frame trace\n");

			printf("R  Register dump\n");
			printf("U  User register dump\n");

			printf("s  Single step\n");
			printf("S  Subroutine step\n");
			printf("K  Trace to the next call/return\n");
			printf("C  Continue\n");

			printf("v  Use virtual addresses (default)\n");
			printf("u  Use unmapped addresses\n");

			printf("l  Set accumulator to preceeding argument\n");

			printf("t  Show byte at this accumulator address\n");
			printf("n  Show byte at next accumulator address\n");
			printf("p  Show byte at previous accumulator address\n");
			printf("-  Deposit previous argument at accum addr\n");

			printf("i  Show instruction at accumulator address\n");
			printf("=  =symbol= shows hex value of symbol\n");
			printf("o  show offset from closest symbol\n");

			printf("B  Set a permanent breakpoint\n");
			printf("O  Set a once-only breakpoint\n");
			printf("D  Delete breakpoint\n");
			printf("L  List breakpoints\n");

			printf("M  Display 64 bytes at accumulator address\n");
			printf("P  Display processes\n");

			printf("V  Jump to VRM\n");
			printf("W  WAKEUP upon contents of accumulator\n");
			printf("Z  Frametrace process designated by slot # in accumulator\n");
			printf("z  Stacktrace process designated by slot # in accumulator\n");
			printf("q  show PAGE map\n");
			printf("Q  show SEGMENT map\n");
			printf("#[u]{p,s,m} show map or memory for location\n");
			printf("_[u]{p,s,m}  set map or memory for location\n");

			printf("r  Display PROC structure at accumulator address\n");
			printf("P^ Display PROC structure at accumulator address\n");
			printf("C^ Display ctxt_t structure at accumulator address\n");
			printf("S^ Display stats: ctxt_stats\n");
			printf("I  Display designated INODE\n");
			printf("E^ Display designated EXCEPTION FRAME\n");
			printf("F^ Display designated FILE descriptor\n");
			printf("Q^ Display mmu_sizing[i] entry by slot #\n");
			printf("T^ Display current time-related info\n");
			printf("U^ Display current UPAGEs\n");
			printf("*  Dereference the accumulator: accum=*accum\n");
			printf("B^ Process 'cannedCmd'\n");
			break;

#if 0	/* Templates */
			printf(" @ 0x%x, =0x%x ",
			     &, );
			printf(" @ 0x%x, =0x%x\n",
			     &, );
#endif 0

		/*
		 * Display mmu context data structure.
		 */
		case '\02': /* CTL-C: C^: Format context information */
		{
			doCannedCmd = 1;
			break;
		}

		/*
		 * Dereference the value of the accumulator.
		 */
		case '*':   /* Indirection thru the accumulator: dereference */
			if (
#ifdef	M68020
			     (chipType!=CHIPTYPE_68020) &&
#endif	M68020
			     ((u_long)accum & 1)
			   )
			{
				printf(" May not be odd value: accum=0x%x\n",
					accum);
				break;
			}
			printf("0x%x==", accum);
			accum = *(u_long *) accum;  /* Perhaps "Memory fault" */
			printf("0x%x; ", accum);
			break;

		/*
		 * Display stack-frame:
		 *	'T' ==> Shortform display;
		 *	'F' ==> Detail display:  routine names, offsets, params;
		 */
		case 'T':     strace(dbgregs[AR6]);	break;
		case 'F': frametrace(dbgregs[AR6]);	break;


		/*
		 * Detailed display of an accumulator-specified proc-structure.
		 */
		case '\020':	/* CTL-P: P^: Print out proc entry in readable format */
		case 'r':	/* Print out proc entry in readable format */
		{
			register struct proc *p = (struct proc *)accum;
			register i;

			if ((((accum - (u_long)proc) % sizeof(struct proc))!=0)
			  ||  (accum < (u_long)proc)
			  ||  (accum > (u_long)procNPROC))
			{
				printf(" 0x%x not a proc addr\n",accum);
				break;
			}
			printf(": Proc entry @ 0x%x, slot %d, pid %d:\n",
				p, p-proc, p->p_pid);
			printf("p_link=0x%x  p_rlink=0x%x  p_addr=0x%x p_usrpri=%d p_pri=%d\n",
				p->p_link, p->p_rlink, p->p_addr,
				p->p_usrpri, p->p_pri);
			printf("p_cpu=%d  p_st=%d  p_time=%d  p_nice=%d  p_slptime=%d p_cursig=0x%x\n",
				p->p_cpu, p->p_time, p->p_nice,
				p->p_slptime, p->p_cursig);
			printf("p_sig=0x%x  p_sigmask=0x%x  p_sigignore=0x%x  p_sigcatch=0x%x\n",
				p->p_sig, p->p_sigmask, p->p_sigignore,
				p->p_sigcatch);
			printf("p_flag=0x%x  p_uid=%d  p_pgrp=%d  p_pid=%d  p_ppid=%d\n",
				p->p_flag, p->p_uid, p->p_pgrp,
				p->p_pid, p->p_ppid);
			printf("p_xstat=%d   p_ru=0x%x  p_poip=%d  p_szpt=%d\n",
				p->p_xstat, p->p_ru, p->p_poip,
				p->p_szpt);
			printf("p_tsize=0x%x  p_dsize=0x%x  p_ssize=0x%x  p_rssize=0x%x\n",
				p->p_tsize, p->p_dsize, p->p_ssize,
				p->p_rssize);
			printf("p_maxrss=0x%x  p_swrss=0x%x  p_swaddr=0x%x  p_wchan=0x%x\n",
				p->p_maxrss, p->p_swrss, 
				p->p_swaddr, p->p_wchan);
			printf("p_textp=0x%x  p_p0br=0x%x  p_xlink=0x%x  p_cpticks=%d\n",
				p->p_textp, p->p_p0br, p->p_xlink,
				p->p_cpticks);
			printf("p_pctcpu=%d   p_ndx=%d  p_idhash=%d  p_pptr=0x%x p_cptr=0x%x\n",
				p->p_pctcpu, p->p_ndx, p->p_idhash,
				p->p_pptr, p->p_cptr);
			printf("p_osptr=0x%x  p_ysptr=0x%x  p_quota=0x%x p_rpcresults=0x%x\n",
				p->p_osptr, p->p_ysptr,
				p->p_quota, p->p_rpcresults);
			printf("p_rpcXXX=0x%x  p_rpcflags=0x%x  p_rpcerror=0x%x\n",
				p->p_rpcXXX, p->p_rpcflags,
				p->p_rpcerror);
#ifdef	USE_CTXT
			printf("p_lru=0x%x  p_mru=0x%x  p_ctxt=0x%x  p_smaps=0x%x p_needmap=0x%x\n",
				p->p_lru, p->p_mru, p->p_ctxt,
				p->p_smaps, p->p_needmap);
#endif	USE_CTXT
			printf("p_mmuIndx=0x%x\n",
				p->p_mmuIndx);
			accum += sizeof(struct proc); /* Repetition...*/
			break;
		}

		case 'I':	/* I: Format inode buckets */
		{
			register struct	inode	*ip = (struct inode *)accum;
#ifdef	VALID_DFS
			/*
			 * Generally the inodes lie within the range
			 *
			 *	*inode <= ip <= *inodeNINODE
			 *
			 * But since an inode could be in a DFS network buffer,
			 * we relax the constraint.
			 */
#endif	VALID_DFS
			printf(" 0x%X:\n", accum);
			printf("i_forw=0x%X i_back=0x%X i_flag=0x%X i_count=%d i_dev=%02x/%02x\n",
				ip->i_forw,	ip->i_back,
				ip->i_flag,	ip->i_count,
				major(ip->i_dev),
				minor(ip->i_dev));

			printf("i_shlockc=%d i_exlockc=%d i_number=0x%x=%d i_fs=0x%X i_dquot=0x%X\n",
				ip->i_shlockc,	ip->i_exlockc,
				ip->i_number,	ip->i_number,
				ip->i_fs, ip->i_dquot);

			printf("i_link=0x%X i_socket=0x%X i_freef=0x%X i_freeb=0x%X\n",
				ip->i_socket, ip->i_socket, 
				ip->i_freef, ip->i_freeb);

			printf("i_mode=0x%x i_nlink=0x%x i_uid=0x%x i_gid=0x%x\n",
				ip->i_mode, ip->i_nlink, ip->i_uid, ip->i_gid);
#ifdef	VALID_DFS
			printf("i_host=0x%X i_rmt_node=0x%X i_rmt_ip=0x%X i_rmt_lock=0x%X i_wcount=0x%x\n",
				ip->i_host,  ip->i_rmt_node,  ip->i_rmt_ip,
				ip->i_rmt_lock, ip->i_wcount);
#endif	VALID_DFS

			/*
			 * In case we're looking through the inode array.
			 */
			accum += sizeof(*ip);
			break;
		}

#ifdef	M68020_REV_B	/* Not used in the Rev 8.1 kernel */
		case '\03':	/* CTL-C: C^: Format context information */
		{
			register ctxt_t	*c = (ctxt_t *)accum;
			extern   ctxt_t	ctxts[NCONTEXTS];  /* Descriptors */

			if ((((accum - (u_long) ctxts) % sizeof(ctxt_t))!=0)
			  ||  (accum < (u_long) ctxts)
			  ||  (accum > (u_long)&ctxts[NCONTEXTS]))
			{
				printf(" 0x%x not a ctxt addr\n",accum);
				break;
			}
			printf("*lru=0x%X  *mru=0x%X  number=%d",
				c->c_lru,  c->c_mru,  c->number);
			printf("  mmuIndx=0x%X  mmuIndxPrev=0x%x",
				c->mmuIndx,  c->mmuIndxPrev);
			printf("\n   *procp=0x%X  *procp->p_pid=%d  gapstart=0x%x=%d  gapend=0x%x=%d\n",
				c->c_procp,
				c->c_procp
					? c->c_procp->p_pid
					: -1,
				c->gapstart,
				c->gapstart,
				c->gapend,
				c->gapend);

			/*
			 * In case we're looking through the ctxts array.
			 */
			accum += sizeof(*c);
			break;
		}
#endif	M68020_REV_B	/* Not used in the Rev 8.1 kernel */

		case '\05':	/* CTL-E: E^: Format exception-frame in upage */
		{
			/*
			 * Ptr to R0/D0 in stack frame
			 */
			u_long *locr0 = (u_long *)(accum + 8);

			register exceptionFrame_t *efp = (exceptionFrame_t *)
							((u_long) &locr0[PS]
							/*
							 * Normalize for 'e_ssr'
							 * as either a short or
							 * a long.
							 */
							+ sizeof(long)
							- sizeof(efp->e_ssr));
			int	type = e_Vector(efp) >> 2;

			/*
			 * This support is provided to speed up
			 * diagnosis of multiple faults
			 * within the trap() code itself.
			 *
			 * For ease of use, this is written
			 * to take the address that 'F' reports
			 * for one (of perhaps several) occurrance(s) of
			 *
			 *		"yyyyy: fault+0x..  trap()"
			 *
			 * Thus:
			 *		yyyyylE^
			 *
			 * should elucidate the particular exception frame,
			 * much as trap() does.
			 */
#if	1 && defined(DEBUG)
			if ((caddr_t)&efp->e_ps !=(caddr_t)&locr0[PS]) {
			     printf( "efp->e_ps @ 0x%X  --  locr0[PS] @ 0x%X\n",
				     &efp->e_ps,	   &locr0[PS]);
			   printf("Botched exception frame address!\n");
			}
#endif	1 && defined(DEBUG)
			printf(" E^: ==> ");

			/*
			 * Should produce "fault+0x.."
			 */
			showoffset(*(u_long *)accum);  

			printf("\n");
			printf("Trap type 0x%x ==> '%s'-mode '%s'; pc=0x%x, ctxtReg=0x%x  ssr=0x%x  ssw=0x%x  faultAddr=0x%X\n",
				type,
				(type&USER) ? "User" : "Kernel",
				( ((unsigned)type < TRAP_TYPES)
					? (chipType==CHIPTYPE_68010)
						? trap_type_68010[type]
						: (chipType==CHIPTYPE_68020)
							? trap_type_68020[type]
							: "debugger/E-0:"
					: "debugger/E-1:"
				),
				efp->e_pc,
				ctxtReg,

				(u_short)efp->e_ssr,

				(u_short)	/* A typecast for sanity */
				(
				   (chipType==CHIPTYPE_68020) ? efp->e_ssw_68020
				 : (chipType==CHIPTYPE_68010) ? efp->e_ssw_68010
				 : (chipType==CHIPTYPE_68000) ? 0x68000
				 :				0xbadbad00
				),
#define	UL	(u_long)
				UL		/* A typecast for sanity */
				(
				     (e_effn(efp)== 8) ? UL efp->e_faultAddr
				   : (e_effn(efp)==11) ? UL efp->e_dataFaultAddr
				   : (e_effn(efp)==10) ? UL efp->e_dataFaultAddr
				   : (e_effn(efp)== 0) ?    efp->e_pc
				   : (e_effn(efp)== 1) ?    efp->e_pc
				   : (e_effn(efp)== 2) ? UL efp->e_instrAddr

				   /*
				    * Co-processor
				    */
				   : (e_effn(efp)== 9) ? UL efp->e_instrAddr9
				   : 0xbad00bad		/* "bad, bad"! */
				)
			);	

#undef	UL
			showregs(locr0);	/* Address of user's saved R0 */
			break;
		}

		case '\06':	/* CTL-F: F^: Format kernel file-descriptor */
		{
			register struct file	*f = (struct file *)accum;

			printf("f_flag @ 0x%x, f_flag=0x%x ",
			     &f->f_flag, f->f_flag);
			printf("f_type @ 0x%x, f_type=0x%x\n",
			     &f->f_type, f->f_type);

			printf("f_count @ 0x%x, f_count=0x%x ",
			     &f->f_count, f->f_count);
			printf("f_msgcount @ 0x%x, f_msgcount=0x%x\n",
			     &f->f_msgcount, f->f_msgcount);

			/*
			 * 'fileops' sub-structure
			 */
			printf("f_ops @ 0x%x, size=0x%x, f_ops=0x%x\n",
			     &f->f_ops, sizeof(struct fileops), f->f_ops);

			/*
			 * ...with the specifics
			 */
			if (f->f_ops)		/* Paranoid */
			{
				printf("fo_rw @ 0x%x, fo_rw=0x%x-->",
				     &f->f_ops->fo_rw, f->f_ops->fo_rw);
				showoffset(f->f_ops->fo_rw);	    /* R/W */
				printf("\n");

				printf("fo_ioctl @ 0x%x, fo_ioctl=0x%x-->",
				     &f->f_ops->fo_ioctl, f->f_ops->fo_ioctl);
				showoffset(f->f_ops->fo_ioctl);	    /* IOCTL */
				printf("\n");

				printf("fo_select @ 0x%x, fo_select=0x%x-->",
				     &f->f_ops->fo_select, f->f_ops->fo_select);
				showoffset(f->f_ops->fo_select);    /* SELECT */
				printf("\n");

				printf("fo_close @ 0x%x, fo_close=0x%x-->",
				     &f->f_ops->fo_close, f->f_ops->fo_close);
				showoffset(f->f_ops->fo_close);	    /* CLOSE */
				printf("\n");
			}


			printf("f_data @ 0x%x, f_data=0x%x ",	/* Inode */
			     &f->f_data, f->f_data);
			printf("f_offset @ 0x%x, f_offset=0x%x\n",
			     &f->f_offset, f->f_offset);
#ifdef	VALID_EFS
			/*
			 * Remote file descriptor
			 */
			printf("f_remote @ 0x%x, size=0x%x\n",
			     &f->f_remote, sizeof(efs_remoteFile_t));
#endif	VALID_EFS
			/*
			 * In case we're looking through the 'file' array.
			 */
			accum += sizeof(*f);
			break;
		}

#ifdef	M68020_REV_B	/* Not used in the Rev 8.1 kernel */
		case '\021':	/* CTL-Q: Q^: Format mmu_sizing[i] entry */
		{	register i;
			register struct mmu_sizing_t * m   = &mmu_sizing[accum
				/*
				 * Firewall range-checking
				 */
				& ( (MMU_MAX_INDX < 31)
					? ( (MMU_MAX_INDX < 15)
						  ? ( (MMU_MAX_INDX <  7)
							  ? ( (MMU_MAX_INDX < 3)
								? 1
								: 3
							    )
							  : 7
						    )
						  : 15
					  )
					: 31
				  )
									];
			if ( ((u_long)accum < 0)
			  || ((u_long)accum > MMU_MAX_INDX))
			{
				printf(" %x not an mmu_sizing[] INDEX;  Range is %d --> %d\n",
					accum, 0, MMU_MAX_INDX);
				break;
			}

			/*
			 * Identify the slot # and its address.
			 */
			printf(" -- Slot #%d for context @ 0x%x\n",
				accum, &mmu_sizing[accum]);

			/*
			 * Elucidate the contents of the context-slot.
			 */
			printf("ctxtMaxVaddr=0x%X  name=%s\n",
				m->mmu_ctxtMaxVaddr,  m->mmu_name);

			printf("usrbase=0x%X  usrtext=0x%X\n",
				m->mmu_usrbase,	m->mmu_usrtext);

			printf("usrtop=0x%X  usrstack=0x%X\n",
				m->mmu_usrtop,	m->mmu_usrstack);

			printf("statRegBits=0x%X  idsInACtxt=%d  ctxtCntsBy=%d  nContexts=%d\n",
				m->mmu_statRegBits,	m->mmu_idsInACtxt,
				m->mmu_ctxtCntsBy,	m->mmu_nContexts);

			printf("alignedIds[0-%d] = [%d",
				m->mmu_nContexts-1,
				m->mmu_alignedIds[0]);
			for (i = 1; i < m->mmu_nContexts; i++)
				printf(",%d", m->mmu_alignedIds[i]);
			printf("]\n");

			printf("nsegs=0x%X=%d  kvarea=0x%X  p1pages=0x%X  *usrpt=0x%X\n",
				m->mmu_nsegs,	m->mmu_nsegs,
				m->mmu_kvarea,
				m->mmu_p1pages,
				m->mmu_usrpt);

			printf("*mbutl=0x%X  maxVaddrMask=0x%X  SEGNO_MASK=0x%X  maxVSmaps=0x%X=%d\n",
				m->mmu_mbutl,
				m->mmu_maxVaddrMask,
				m->mmu_SEGNO_MASK,
				m->mmu_maxVSmaps,	m->mmu_maxVSmaps);

			/*
			 * In case we're looking through the mmu_sizing array,
			 * bump to the next slot number.
			 */
			accum += sizeof(mmu_sizing[0]);
			break;
		}
#endif	M68020_REV_B	/* Not used in the Rev 8.1 kernel */

		case '\024':	/* CTL-T:T^: Format TIME-related variables */
		{
			extern	long	backlogOfTicks;
			extern	long	ticksPerClkRupt;
			extern	long	prontoTicker;
			extern	long	absOfOverrun;
			extern	long	aggregatBacklog;
			extern	long	tallySmallBackLog;
			extern	long	tallyGoneLONG;
			extern	long	tallyProntoTicks;

			printf(" T^: ");	/* Echo the command */

			printf("backlogOfTicks @ 0x%x, =0x%x=%d ",
			     &backlogOfTicks,
			      backlogOfTicks,
			      backlogOfTicks);
			printf("ticksPerClkRupt @ 0x%x, =0x%x=%d\n",
			     &ticksPerClkRupt,
			      ticksPerClkRupt,
			      ticksPerClkRupt);

			printf("prontoTicker @ 0x%x, =0x%x=%d ",
			     &prontoTicker,
			      prontoTicker,
			      prontoTicker);
			printf("absOfOverrun @ 0x%x, =0x%x=%d\n",
			     &absOfOverrun,
			      absOfOverrun,
			      absOfOverrun);

			printf("aggregatBacklog @ 0x%x, =0x%x=%d ",
			     &aggregatBacklog,
			      aggregatBacklog,
			      aggregatBacklog);
			printf("tallySmallBackLog @ 0x%x, =0x%x=%d\n",
			     &tallySmallBackLog,
			      tallySmallBackLog,
			      tallySmallBackLog);

			printf("tallyGoneLONG @ 0x%x, =0x%x=%d ",
			     &tallyGoneLONG,
			      tallyGoneLONG,
			      tallyGoneLONG);
			printf("tallyProntoTicks @ 0x%x, =0x%x=%d\n",
			     &tallyProntoTicks,
			      tallyProntoTicks,
			      tallyProntoTicks);
			break;
		}

		case '\025':	/* CTL-U:U^: Format the CURRENT u-area */
		{	register i;

			printf(" U^: ");	/* Echo the command */

			printf("u_pcb @ 0x%x, size=0x%x\n",
			     &u.u_pcb, sizeof(struct pcb));

			printf("u_pcb.pcb_p0br @ 0x%x, =0x%x ",
			     &u.u_pcb.pcb_p0br, u.u_pcb.pcb_p0br);
			printf("u_pcb.pcb_p0lr @ 0x%x, =0x%x\n",
			     &u.u_pcb.pcb_p0lr, u.u_pcb.pcb_p0lr);

			printf("u_pcb.pcb_p1br @ 0x%x, =0x%x ",
			     &u.u_pcb.pcb_p1br, u.u_pcb.pcb_p1br);
			printf("u_pcb.pcb_p1lr @ 0x%x, =0x%x\n",
			     &u.u_pcb.pcb_p1lr, u.u_pcb.pcb_p1lr);

			printf("u_pcb.pcb_szpt @ 0x%x, =0x%x ",
			     &u.u_pcb.pcb_szpt, u.u_pcb.pcb_szpt);
			printf("u_pcb.pcb_cmap2 @ 0x%x, =0x%x\n",
			     &u.u_pcb.pcb_cmap2, u.u_pcb.pcb_cmap2);
			printf("u_pcb.pcb_sswap @ 0x%x, =0x%x\n",
			     &u.u_pcb.pcb_sswap, u.u_pcb.pcb_sswap);

			printf("u_procp @ 0x%x, =0x%x ",
			     &u.u_procp, u.u_procp);
			printf("u_ar0 @ 0x%x, =0x%x\n",
			     &u.u_ar0, u.u_ar0);

			printf("u_comm @ 0x%x, size=0x%x, ='%s'\n",
			      u.u_comm,  sizeof(u.u_comm), u.u_comm);

			printf("u_arg[8] @ 0x%x, =0x%x 0x%x 0x%x 0x%x : 0x%x 0x%x 0x%x 0x%x\n",
			        u.u_arg,u.u_arg[0],u.u_arg[1],u.u_arg[2],u.u_arg[3],
					u.u_arg[4],u.u_arg[5],u.u_arg[6],u.u_arg[7]);

			printf("u_ap @ 0x%x, =0x%x ",
			     &u.u_ap,  u.u_ap);
			printf("u_error @ 0x%x, =0x%x\n",
			     &u.u_error, u.u_error);

			printf("u_uid @ 0x%x, =0x%x ",
			     &u.u_uid, u.u_uid);
			printf("u_gid @ 0x%x, =0x%x\n",
			     &u.u_gid, u.u_gid);

			printf("u_ruid @ 0x%x, =0x%x ",
			     &u.u_ruid, u.u_ruid);
			printf("u_rgid @ 0x%x, =0x%x\n",
			     &u.u_rgid, u.u_rgid);

			printf("u_groups @ 0x%x, size=0x%x ==>",
			      u.u_groups, sizeof(u.u_groups));
		        for (i=0; i<NGROUPS; i++)
				printf(" %d", u.u_groups[i]);
			printf("\n");

			printf("u_tsize @ 0x%x, =0x%x ",
			     &u.u_tsize, u.u_tsize);
			printf("u_dsize @ 0x%x, =0x%x ",
			     &u.u_dsize, u.u_dsize);
			printf("u_ssize @ 0x%x, =0x%x\n",
			     &u.u_dsize, u.u_ssize);

			printf("u_dmap @ 0x%x, size=0x%x, =0x%x ",
			     &u.u_dmap, sizeof(u.u_dmap), u.u_dmap);
			printf("u_smap @ 0x%x, size=0x%x, =0x%x\n",
			     &u.u_smap, sizeof(u.u_smap), u.u_smap);

			printf("u_cdmap @ 0x%x, size=0x%x, =0x%x ",
			     &u.u_cdmap, sizeof(u.u_cdmap), u.u_cdmap);
			printf("u_csmap @ 0x%x, size=0x%x, =0x%x\n",
			     &u.u_csmap, sizeof(u.u_csmap), u.u_csmap);

			printf("u_cdir @ 0x%x, =0x%x ",
			     &u.u_cdir, u.u_cdir);
			printf("u_rdir @ 0x%x, =0x%x\n",
			     &u.u_rdir, u.u_rdir);

			printf("u_ttyp @ 0x%x, =0x%x ",
			     &u.u_ttyp, u.u_ttyp);
			printf("u_ttyd @ 0x%x, =0x%x/0x%x\n",
			     &u.u_ttyd, major(u.u_ttyd), minor(u.u_ttyd));

			printf("u_cmask @ 0x%x, =0x%x\n",
			     &u.u_cmask, u.u_cmask);

			printf("u_ssr @ 0x%x, =0x%x ",
			     &u.u_ssr, u.u_ssr);
			printf("u_aAddr @ 0x%x, =0x%x\n",
			     &u.u_aAddr, u.u_aAddr);

			/*
			 * Resource limits: current & maximum
			 */
			printf("u_rlimit @ 0x%x:\n",
			      u.u_rlimit);
			{register i;
			  for (i=0; i<RLIM_NLIMITS; i++) {
			    printf("    %s: ",
				    (
				       (i==RLIMIT_CPU  )	? "  cpu"
				     : (i==RLIMIT_FSIZE)	? "fsize"
				     : (i==RLIMIT_DATA )	? " data"
				     : (i==RLIMIT_STACK)	? "stack"
				     : (i==RLIMIT_CORE )	? " core"
				     : (i==RLIMIT_RSS  )	? "  rss"
				     :				  "UNKNOWN!"
				    )
			          );
			    printf("  cur[%d]=0x%8x=%10d",
			      i,
			      u.u_rlimit[i].rlim_cur,
			      u.u_rlimit[i].rlim_cur);
			    printf("  max[%d]=0x%8x=%10d\n",
			      i,
			      u.u_rlimit[i].rlim_max,
			      u.u_rlimit[i].rlim_max);
			  }
			}

#ifdef	M68020_REV_B	/* Not used in the Rev 8.1 kernel */
			printf("u_smapLRU_HEAD @ 0x%x, =0x%x ",
			     &u.u_smapLRU_HEAD, u.u_smapLRU_HEAD);
			printf("u_smapLRU_TAIL @ 0x%x, =0x%x\n",
			     &u.u_smapLRU_TAIL, u.u_smapLRU_TAIL);

			printf("u_vSmapsInUse @ 0x%x, =0x%x  ",
			     &u.u_vSmapsInUse, u.u_vSmapsInUse);
			printf("u_hndlrState @ 0x%x, =0x%x\n",
			     &u.u_hndlrState, u.u_hndlrState);

			printf("u_stack (REDZONE) @ 0x%x, size=0x%X\n",
			      u.u_stack,
			      (U_SMAPSNUM << pageshift) - (u_long)u.u_stack);
#endif	M68020_REV_B	/* Not used in the Rev 8.1 kernel */

#ifdef	M68881
	/*
	 * Motorola MC68881 Floating Point Co-Processor support.
	 * FPU present only with the REV_B M68020 and later cpu board sets.
	 *
	 * Savearea for:
	 *	a) 8 80-bit FPU data    registers;
	 *	b) 3 32-bit FPU control registers;	C.f., ../s32/reg.h
	 *	c) Maximum of 0xb8 bytes worth of FPU system internals;
	 *		NULL:	0x04 bytes of system state frame;
	 *		IDLE:	0x1c bytes;
	 *		BUSY:	0xB8 bytes.
	 */
		{	u_long	uFPCR, uFPSR;	/* Local copies */

			printf("u_FPDR @ 0x%x, size=0x%x:\n",
			     &u.u_FPDR[0], sizeof(u.u_FPDR));

			/*
			 * Format all of the FPU <<<DATA>>> registers.
			 */
			for (i=0; i <= 7; i++) {
				register u_long * lp = (u_long *)&u.u_FPDR[0];

				if (i == 4)	printf("\n");
				printf("    FPDR[%d]: %08x %08x %08x\n",
					i, *lp, *(lp+1), *(lp+2));
				lp += 3;
			}

			/*
			 * Format the FPU <<<CONTROL>>> Register.
			 */
			printf("u_FPCR  @ 0x%x, size=0x%x, =0x%08x\n",
			     &u.u_FPCR, sizeof(u.u_FPCR), u.u_FPCR);
			uFPCR = *(u_long *)(&u.u_FPCR);
			/*
			 * ...Exception Enable Byte...
			 */
			if (uFPCR & FPU_MASK_ENBL)
			 printf("  ==> ExecptionEnable==%s,%s,%s,%s | %s,%s,%s,%s.\n",
			  (uFPCR & FPU_BSUN_ENBL)	? "BSUN"	: "",
			  (uFPCR & FPU_SNAN_ENBL)	? "SNAN"	: "",
			  (uFPCR & FPU_OPERR_ENBL)	? "OperandErr"	: "",
			  (uFPCR & FPU_OVFL_ENBL)	? "Overflow"	: "",

			  (uFPCR & FPU_UNFL_ENBL)	? "Underflow"	: "",
			  (uFPCR & FPU_DZ_ENBL)		? "DivByZero"	: "",
			  (uFPCR & FPU_INEX2_ENBL)	? "InexactOp"	: "",
			  (uFPCR & FPU_INEX1_ENBL)	? "InexactDecIn": ""
			       );


			/*
			 * Format the FPU <<<STATUS>>> Register.
			 */
			printf("u_FPSR  @ 0x%x, size=0x%x, =0x%08x\n",
			     &u.u_FPSR, sizeof(u.u_FPSR), u.u_FPSR);
			uFPSR = *(u_long *)(&u.u_FPSR);
			/*
			 * ...Condition Code Byte...
			 */
			if (uFPSR & FPU_MASK_CCODE)
			 printf("  ==> ConditionCode==%s,%s,%s,%s.\n",
			  (uFPSR & FPU_N_CCODE)		? "Negative"	: "",
			  (uFPSR & FPU_Z_CCODE)		? "Zero"	: "",
			  (uFPSR & FPU_I_CCODE)		? "Infinity"	: "",
			  (uFPSR & FPU_NAN_CCODE)	? "NotANumber"	: ""
			       );
			/*
			 * ...Exception Status Byte...
			 */
			if (uFPSR & FPU_MASK_STAT)
			 printf("  ==> ExceptionStatus==%s,%s,%s,%s; %s,%s,%s,%s.\n",
			  (uFPSR & FPU_BSUN_STAT)	? "BSUN"	: "",
			  (uFPSR & FPU_SNAN_STAT)	? "SNAN"	: "",
			  (uFPSR & FPU_OPERR_STAT)	? "OperandErr"	: "",
			  (uFPSR & FPU_OVFL_STAT)	? "Overflow"	: "",

			  (uFPSR & FPU_UNFL_STAT)	? "Underflow"	: "",
			  (uFPSR & FPU_DZ_STAT)		? "DivByZero"	: "",
			  (uFPSR & FPU_INEX2_STAT)	? "InexactOp"	: "",
			  (uFPSR & FPU_INEX1_STAT)	? "InexactDecIn": ""
			       );
			/*
			 * ...Accrued Exception Byte...
			 */
			if (uFPSR & FPU_MASK_EXCPT)
			 printf("  ==> AccruedException==%s,%s,%s,%s| %s.\n",
			  (uFPSR & FPU_IOP_EXCPT)	? "Invalid-Op"	: "",
			  (uFPSR & FPU_OVFL_EXCPT)	? "Overflow"	: "",
			  (uFPSR & FPU_UNFL_EXCPT)	? "Underflow"	: "",
			  (uFPSR & FPU_DZ_EXCPT)	? "DivByZero"	: "",

			  (uFPSR & FPU_INEX_EXCPT)	? "Inexact"	: ""
			       );


			/*
			 * Format FPU Instruction Address Register (fpu's pc)
			 */
			printf("u_FPIAR  @ 0x%x, size=0x%x, =0x%08x\n",
			     &u.u_FPIAR, sizeof(u.u_FPIAR), u.u_FPIAR);

			/*
			 * Format our savearea for the FPU system status frame.
			 */
			printf("u_FPSSFp @ 0x%x, size=0x%x, =0x%8x *=0x%08x  ==> %s format sys-frame\n",
			     &u.u_FPSSFp, sizeof(u.u_FPSSFp), u.u_FPSSFp,
			     (u.u_FPSSFp
				? *(u_long *)u.u_FPSSFp
				: 0
			     ),
			     (  (*(u_short *)u.u_FPSSFp == 0x0018) ? "NULL"
			      : (*(u_short *)u.u_FPSSFp == 0x0118) ? "NotReady"
			      : (*(u_short *)u.u_FPSSFp == 0x0218) ? "ILLEGAL"
			      : (*(u_short *)u.u_FPSSFp == 0x1f18) ? "IDLE"
			      : (*(u_short *)u.u_FPSSFp == 0x1fB4) ? "BUSY"
			      : 				   "UNKNOWN"
			     )
			      );
			printf("u_FPSSF  @ 0x%x, size=0x%x\n",
			     &u.u_FPSSF[0], sizeof(u.u_FPSSF));
		}
#endif	M68881

			printf("u_pdir @ 0x%x, =0x%x ",
			     &u.u_pdir, u.u_pdir);
			printf("u_dirp @ 0x%x, =0x%x",
			     &u.u_dirp, u.u_dirp);
			if (u.u_dirp)
				printf(" *='%s'\n", u.u_dirp);
			else
				printf("\n");

#if 0
				****************************************
	label_t u_ssave;		/* label variable for swapping */
	size_t	u_odsize, u_ossize;	/* for (clumsy) expansion swaps */
	time_t	u_outime;		/* user time at last sample */

/* 1.3 - signal management */
	int	(*u_signal[NSIG])();	/* disposition of signals */
	int	u_sigmask[NSIG];	/* signals to be blocked */
	int	u_sigonstack;		/* signals to take on sigstack */
	int	u_oldmask;		/* saved mask from before sigpause */
	int	u_code;			/* ``code'' to trap */
	struct	sigstack u_sigstack;	/* sp & on stack state variable */
#define	u_onstack	u_sigstack.ss_onstack
#define	u_sigsp		u_sigstack.ss_sp

/* 1.4 - descriptor management */
	struct	file *u_ofile[NOFILE];	/* file structures for open files */
	char	u_pofile[NOFILE];	/* per-process flags of open files */
#define	UF_EXCLOSE 	0x1		/* auto-close on exec */
#define	UF_MAPPED 	0x2		/* mapped from device */

/* 1.5 - timing and statistics */
	struct	rusage u_ru;		/* stats for this proc */
	struct	rusage u_cru;		/* sum of stats for reaped children */
	struct	itimerval u_timer[3];
	int	u_XXX[3];
	time_t	u_start;
	short	u_acflag;

/* 1.6 - resource controls */
#ifdef	QUOTA
	struct	quota *u_quota;		/* user's quota structure */
	int	u_qflags;		/* per process quota flags */
#endif	QUOTA

/* BEGIN TRASH */
	char	u_segflg;		/* 0:user D; 1:system; 2:user I */
	caddr_t	u_base;			/* base address for IO */
	unsigned int u_count;		/* bytes remaining for IO */
	off_t	u_offset;		/* offset in file for IO */
	union {
	   struct {			/* header of executable file */
		int	Ux_mag;		/* magic number */
		unsigned Ux_tsize;	/* text size */
		unsigned Ux_dsize;	/* data size */
		unsigned Ux_bsize;	/* bss size */
		unsigned Ux_ssize;	/* symbol table size */
		unsigned Ux_entloc;	/* entry location */
		unsigned Ux_unused;
		unsigned Ux_relflg;
	   } Ux_A;
	   char ux_shell[SHSIZE];	/* #! and name of interpreter */
	} u_exdata;
#define	ux_mag		Ux_A.Ux_mag
#define	ux_tsize	Ux_A.Ux_tsize
#define	ux_dsize	Ux_A.Ux_dsize
#define	ux_bsize	Ux_A.Ux_bsize
#define	ux_ssize	Ux_A.Ux_ssize
#define	ux_entloc	Ux_A.Ux_entloc
#define	ux_unused	Ux_A.Ux_unused
#define	ux_relflg	Ux_A.Ux_relflg
	struct	direct u_dent;		/* current directory entry */
/* END TRASH */
	struct uprof {			/* profile arguments */
		short	*pr_base;	/* buffer base */
		unsigned pr_size;	/* buffer size */
		unsigned pr_off;	/* pc offset */
		unsigned pr_scale;	/* pc scaling */
	} u_prof;
#ifdef s32
	struct	exceptionInfo_t {	/* Exception-related information */
#if	defined(M68000) || defined(M68010) || defined(M68020)
		/*
		 * Common to all members of the M68000 family
		 * of microprocessor CPUs.
		 */
		u_short U_ssr;		/* System Status Register (ps)	      */
		u_long	U_aAddr;	/* Access Address on bus errors	      */
		u_short	U_iReg;		/* Instruction Register on bus errors */
#define	u_iReg	exceptionInfo.U_iReg
#endif	defined(M68000) || defined(M68010) || defined(M68020)
#ifdef	M68000
		/*
		 * Only in the M68000/M68008
		 */
		u_short	U_fCode;	/* Function Code on bus errors	      */
#define	u_fCode	exceptionInfo.U_fCode
#endif	M68000

#if	defined(M68010)  && !defined(M68020)
		/*
		 * Different in the M68010 & M68020
		 */
		u_short U_diBuf;	/* Data  input buffer */
		u_short U_doBuf;	/* Data output buffer */
#define	u_diBuf	exceptionInfo.U_diBuf
#define	u_doBuf	exceptionInfo.U_doBuf
#endif	defined(M68010)  && !defined(M68020)

#if	defined(M68010) || defined(M68020)
		/*
		 * Common to both M68010 and M68020
		 */
		u_short	U_effn;		/* Exception frame fmt # */
		u_short	U_ssw;
#define	u_effn	exceptionInfo.U_effn
#define	u_ssw	exceptionInfo.U_ssw
#endif	defined(M68010) || defined(M68020)

#ifdef	M68020
		/*
		 * Found only in the M68020:
		 * More extensive pipeline info,
		 * and larger data buffers.
		 */
		u_short	U_iRegB;	/* Stage B instruction pipe   */
		u_short	U_iRegC;	/* Stage C instruction pipe   */
		u_long	U_aAddrB;	/* "B" inst-stream addr error */
		u_long	U_aAddrC;	/* "C" inst-stream addr error */
		u_long	U_diBuf;	/* Data  input buffer	      */
		u_long	U_doBuf;	/* Data output buffer	      */
#define	u_iRegB	 exceptionInfo.U_iRegB
#define	u_iRegC	 exceptionInfo.U_iRegC
#define	u_aAddrB exceptionInfo.U_aAddrB
#define	u_aAddrC exceptionInfo.U_aAddrC
#define	u_diBuf	 exceptionInfo.U_diBuf
#define	u_doBuf	 exceptionInfo.U_doBuf

#endif	M68020
	} exceptionInfo;

	u_long	u_fpsav[8];		/* floating point registers */
	u_long	u_vmvec[64];		/* vectors for virtual machine */
	u_short	u_usrtop;		/* page number of top of stack */
	u_short	u_fppc;			/* floating point pc */
	caddr_t	u_sighandler;		/* generic signal handler */
	u_short	u_xxspare[12];		/* reserved space */
#endif s32
					****************************************
#endif 0
			break;
			}

		case '\023':	/* CTL-S:S^: Format some statistics */
		{		/* Context stats */
		extern	 smap_t		smap_free, smaps[NSMAPS];
#ifdef	USE_CTXT
		extern	 struct	ctxt_stats		 ctxt_stats;
		register struct	ctxt_stats	*c =	&ctxt_stats;
#endif	USE_CTXT
		register i, j;

#if 0	/* Template */
		printf("=0x%x =0x%x =0x%x =0x%x\n",
		        c->, c->, c->, c->);
#endif 0
		printf(" S^: ");	/* Echo the command */

		printf("smap_free=0x%x\n",
		        smap_free);
		/*
		 * Pretty-print the 'smaps' table
		 */
		for (i=0; i<NSMAPS; i++) {
			j = i+1;
			if	        (!(i % 0x10)) printf("%02x: ", i);

			printf("%02x ", smaps[i]); /* Zero-pad; 2 digit min */

			if	   (i && !(j % 0x40)) printf("\n");
			if	   (i && !(j % 0x10)) printf("\n");
			else	if (i && !(j % 0x08)) printf("| ");
		}
#ifdef	USE_CTXT

		/*
		 * ctxt_stats
		 */
		printf("sureg=0x%x       needmap=0x%x      freetaken=0x%x noctxt=0x%x\n",
		     c->sureg, c->needmap, c->freetaken, c->noctxt);
		printf("noctxttaken=0x%x  noctxtempty=0x%x  havectxt=0x%x  havectxttaken=0x%x\n",
		     c->noctxttaken, c->noctxtempty, c->havectxt, c->havectxttaken);
		printf("needctxt=0x%x  procctxt=0x%x  mapsegs=0x%x segstomap=0x%x\n",
		     c->needctxt, c->procctxt, c->mapsegs, c->segstomap);
		printf("mappages=0x%x  pagestomap=0x%x  inval=0x%x  invalctxt=0x%x\n",
		     c->mappages, c->pagestomap, c->inval, c->invalctxt);
		printf("invalsmaps=0x%x  invalneed=0x%x  pageupdates=0x%x realupdates=0x%x\n",
		     c->invalsmaps, c->invalneed, c->pageupdates, c->realupdates);
		printf("hardupdates=0x%x  updateinvals=0x%x  getprocmap=0x%x\n",
		     c->hardupdates, c->updateinvals, c->getprocmap);

#endif	USE_CTXT
		break;
		}

		case 'Z':	/* Frame-trace of a process u-area */
		case 'z':	/* Stack-trace of a process u-area */
			{
				register u_short      temp[UPAGES];
				register struct proc *p = (struct proc *)accum;
				register i;

				if ((((accum - (u_long)proc) % sizeof(struct proc))!=0)
				  || (accum <= (u_long)proc)
				  || (accum >= (u_long)procNPROC))
				{
					printf(" 0x%x not a proc addr\n",accum);
					break;
				}
			   if (wildAndWoolly) {
				/*
				 * Map in the specified process's u-area.
				 */
				for (i=0; i<UPAGES; i++)
				{

#ifdef	CMD_BINGO
				   short cmd_BINGO_old = cmd_BINGO;
					 cmd_BINGO = 0;	/* Preclude recursion */
#endif	CMD_BINGO
				   temp[i] = setpagemap(UPAGENUM+i,
#ifdef WHITE_V_PRESENT
						(p->p_addr+i)->pg_pfnum|V_PRESENT);
#else WHITE_V_PRESENT
						(p->p_addr+i)->pg_pfnum);
#endif WHITE_V_PRESENT
#if 1
				   printf(" 0x%x was @ 0x%x - now @ 0x%X;",
					UPAGENUM+i, temp[i],
					(p->p_addr+i)->pg_pfnum);
#endif
#ifdef	CMD_BINGO
				   cmd_BINGO = cmd_BINGO_old;
#endif	CMD_BINGO
				}
				i = (u_long) u.u_pcb.pcb_regs.val[LABEL_AR6];
#if 1
				printf("  Start of frame: u_pcb.pcb_reg[A6]=0x%X\n", i);
#endif
				/*
				 * Use the A6 from the last 'moveml' into upage.
				 */
				if (c=='Z')  frametrace(i);
				if (c=='z')  stacktrace(i);

				/*
				 * Put back the u-area as we found it.
				 */
				for (i=0; i<UPAGES; i++)
				{
				   register u_short oldPte;
#ifdef	CMD_BINGO
				   short cmd_BINGO_old = cmd_BINGO;
					 cmd_BINGO = 0;	/* Preclude recursion */
#endif	CMD_BINGO

				   oldPte = setpagemap(UPAGENUM+i, temp[i]);
#if 1
				   printf(" 0x%x was @ 0x%x - now @ 0x%X;",
						UPAGENUM+i, oldPte, temp[i]);
#endif
#ifdef	CMD_BINGO
				   cmd_BINGO = cmd_BINGO_old;
#endif	CMD_BINGO
				}
			   }
				break;
			}

		case 'R':
			printf("\nRegister locations: d0-d7,a0-a7 at 0x%x, ps at 0x%x, pc at 0x%x\n", &dbgregs[R0], &dbgregs[PS], &dbgregs[PC]);
			prregs(dbgregs);
			break;

		case 'W':
			printf("akeup upon 0x%X. ",accum);
			wakeup((caddr_t) accum);
			break;

		case 'U':
			if (userregs == 0)
			{
				printf(" No saved user registers\n");
				break;
			}
			printf("\nUser registers: d0-d7,a0-a6,usp at 0x%x, ps at 0x%x, pc at 0x%x, ",
				&userregs[R0],
				&userregs[PS],
				&userregs[PC]);
			/*
			 * printf() the upage frame #-s
			 * for the current process.
			 */
			prUpages("\n", u.u_procp);

			prregs(userregs);
			prframe((u_short *)&userregs[PS]+1);
			break;

		case 's':
			printf("ingle step ...\n");
			tracing = 1;
			for (count=0; count<NIPCREG; ++count)
				keptregs[count] = dbgregs[count];
			goto cont;

		case 'K':
			printf(" ");
			tracingcalls = tracing = 1;
			goto cont;

		case 'S':
			printf("ubroutine step ...\n");
			if (*(u_short *)dbgregs[PC] != JSRINST)
			{
				printf(" Not a subroutine\n");
				break;
			}
			else if (nbrk == MAXBRK)
				printf(" Breakpoint table full\n");
			else
			{
				register struct bpt *bp = &bpt[0];

				while (bp->type != BRK_NONE)
					++bp;
				bp->type = BRK_SUBR;
				bp->addr = dbgregs[PC] + JSRLEN;
				bp->content = BRKINST;
				if (USRTEXT <= bp->addr)
					bp->pid = u.u_procp->p_pid;
				else
					bp->pid = NOPID;
				++nbrk;
			}
			for (count=0; count<NIPCREG; ++count)
				keptregs[count] = dbgregs[count];
			/* Fall through */

		/*
		 * Continue from a breakpoint or cdebugger invocation.
		 */
		case 'C':
			printf("ontinuing...\n");
cont:
			u.u_ar0 = oldar0;
			*(u_long *)BERRVEC = saveberr;
			*(u_long *)AERRVEC = saveaerr;
			if (nbrk)
			{
				register struct bpt *bp = &bpt[0];

				for (; bp != &bpt[MAXBRK]; ++bp)
					if (bp->type != BRK_NONE &&
					    bp->addr == dbgregs[PC])
						skipaddr = bp->addr;
				xchbrk();
				*(u_long *)BRKVEC = (u_long)bpttrap;
			}
			if (tracing || skipaddr != -1)
			{
				savetrace = *(long *)TRCVEC;
				*(long *)TRCVEC = (long)tracer;
				dbgregs[PS] |= PSL_T;
			}
			debugunmap();
			splx(oldpri);
#ifdef WHITE
			dsonemode(omode);
#endif WHITE
			return;
		case 'v':
			aspace = 'v';
			spacetype = 'k';
			spacefmt = FMT_KERNEL;
			printf("irtual addressing mode.\n");
			break;
		case 'u':
			aspace = 'u';
			spacetype = 'p';
			spacefmt = FMT_PHYS;
			printf("nmapped addressing mode.\n");
			break;
		case 'l':
			accum = value;
			break;
		case 'n':
			value = ++accum;
			goto display;
		case 'p':
			value = --accum;
			/* Fall through */
		case 't':
		case ';':
		display:
#ifdef WHITE
			if (aspace == 'u' && (accum << segshift) < nsegs)
#else WHITE
			if (aspace == 'u')
#endif WHITE
			{
			   debugmap(accum >> pageshift, 1);
			   printf("\nu%x %x ", accum,
				   *(u_char *)(DEBUG_VA+(accum&pagemask)));
			   debugunmap();
			}
			else
			   printf("\nv%x %x ", accum, *(u_char *)accum);
			break;

		case '/':
			printf("\n%c%x %x ", spacetype, accum,
				readmem(accum, spacefmt|FMT_SHORT));
			break;

		case ':':
			printf("\n%c%x %x ", spacetype, accum,
				readmem(accum, spacefmt|FMT_LONG));
			break;

		/*
		 * Instruction disassembly -- no execution.
		 */
		case 'i': {
			char disasmstr[30];
			u_short	*savAccum = (u_short *)accum;
			extern int disasm();

			printf("\nv%x  ",accum);
			value = accum = disasm(accum,disasmstr);
			printf("%s   ",disasmstr);
#if	1
			/*
			 * Display target addr if
			 * we have a subroutine call.
			 */
			if (*savAccum == JSRINST) {
				printf("\t-->");
				showoffset(*(u_long *) ++savAccum);
				printf(" \t");
			} else

			/*
			 * 'MOVE' generic instruction, where the
			 * destination effective address is an absolute-long.
			 */
			if ((*savAccum & 0xCFC0) == 0x3EC0) { /* Magic -- jht*/
				printf("\t-->");
				showoffset(*(u_long *) ++savAccum);
				printf(" \t");
			}
#endif	1
			break;
			}
		case '-':
#ifdef WHITE
			if ((accum >> segshift) >= nsegs)
				*(u_char *)accum = (u_char)value;
			else
#endif WHITE
			if (aspace == 'u')
			{
			   debugmap(accum >> pageshift, 1);
			   *(u_char *)(DEBUG_VA+(accum&pagemask))=(u_char)value;
			   debugunmap();
			}
#ifndef WHITE
			else if ((accum >> segshift) == 1)
				*(u_char *)accum = (u_char)value;
#endif WHITE
			else
			{
			   /*
			    * (Remember that getpagemap() can return -1.)
			    */
			   debugmap(getpagemap(accum >> pageshift), 1);
			   *(u_char *)(DEBUG_VA+(accum&pagemask))=(u_char)value;
			   debugunmap();
			}
			value = ++accum;
			break;

		/*
		 * Symbol lookup
		 */
		case '=':
#ifndef	QUICKEN
			value = showsym();
#else	QUICKEN
			value = showsym(NULL,/* ==> Get sym from op's console */
					-1   /* ==> print the symbol's value  */
				       );
#endif	QUICKEN
			break;

		/*
		 * Show offset from nearest symbol
		 */
		case 'o':
			printf(" ");
			showoffset(value);
			printf("\n");
			break;

		/*
		 * Set breakpoint:
		 *	'B' ==> Permanent breakpoint;
		 *	'O' ==> Once-only breakpoint;
		 */
		case 'B':
		case 'O':
			/*
			 * Try to access the address so that we
			 * fault now instead of later when we would
			 * be half way through doing things.
			 */
			if (*(u_short *)value)
				;
			if (nbrk == MAXBRK)
				printf("reakpoint table full\n");
			else
			{
				register struct bpt *bp = &bpt[0];

				accum = value;
				for (; bp != &bpt[MAXBRK]; ++bp)
					if (bp->type != BRK_NONE &&
					    bp->addr == accum)
					{
						printf("\nAlready set\n");
						goto already;
					}
				for (bp = &bpt[0]; bp->type != BRK_NONE; ++bp)
					;
				if (c == 'O')
					bp->type = BRK_TEMP,
					printf("nce only breakpoint set\n");
				else
					bp->type = BRK_PERM,
					printf("reakpoint set (permanent)\n");
				bp->addr = accum;
				bp->content = BRKINST;
				if (USRTEXT <= accum)
					bp->pid = u.u_procp->p_pid;
				else
					bp->pid = NOPID;
				++nbrk;
			}
		already:
			break;

		/*
		 * Delete (any kind of) breakpoint
		 * from the value specified in the accumulator.
		 */
		case 'D':
			if (nbrk == 0)
				printf("\nNo breakpoints set\n");
			else
			{
				register struct bpt *bp = &bpt[0];

				accum = value;
				for (; bp != &bpt[MAXBRK]; ++bp)
					if (bp->type != BRK_NONE &&
					    bp->addr == accum)
					{
						printf("eleted\n");
						if (bp->pid != NOPID &&
						    bp->pid != u.u_procp->p_pid)
							bp->type = BRK_TEMP;
						else
						{
							bp->type = BRK_NONE;
							--nbrk;
						}
						break;
					}
				if (bp == &bpt[MAXBRK])
					printf("No such breakpoint\n");
			}
			break;

		/*
		 * List all breakpoints
		 */
		case 'L':
			if (nbrk)
			{
				register struct bpt *bp = &bpt[0];

				printf("\n%d breakpoints\n", nbrk);
				xchbrk();
				for (; bp != &bpt[MAXBRK]; ++bp)
				{
					register char type = 'P';

					if (bp->type == BRK_PERM)
						type = 'P';
					else if (bp->type == BRK_TEMP)
						type = 'T';
					else if (bp->type == BRK_SUBR)
						type = 'S';
					else
						continue;
					printf("#%d %c v%x %x   ", bp-bpt, type,
						bp->addr, bp->content);
					showoffset(bp->addr);
					printf("\n");
				}
				xchbrk();
			}
			else
				printf("\nNo breakpoints\n");
			break;

		/*
		 * Display memory:
		 *	'm' ==> One  line  comprising 16/0x10 bytes;
		 *	'M' ==> Four lines comprising 48/0x40 bytes;
		 */
		case 'm':	/* 16-byte memory display */
		case 'M':	/* 64-byte memory display */
		{
			char ascii[17];
			char *asp = &ascii[0];

			ascii[16] = '\0';
			/*
			 * Print either
			 *	'm' ==>	16 bytes or
			 *	'M' ==>	64 bytes.
			 */
			for (count=0; count < ((c=='m') ? 16: 64); ++count)
			{
				u_char byte;

				if (aspace == 'u')
				{
				   debugmap(accum >> pageshift, 1);
				   byte = *(u_char *)(DEBUG_VA+(accum&pagemask));
				   debugunmap();
				}
				else
				   byte = *(u_char *)accum;
				if (' ' <= byte && byte <= '~')
					*asp++ = byte;
				else
					*asp++ = '.';
				if (count % 16 == 0)
					printf("\n%c%06x  ", aspace, accum);
				else if (count % 4 == 0)
					printf(" ");
				printf(" %x", (byte >> 4) & 0xF);
				printf("%x", byte & 0x0F);
				if (count % 16 == 15)
					printf("  %s", ascii),
					asp = &ascii[0];
				++accum;
			}
			value = accum;
			printf("\n");
			break;
		}

		/*
		 * KLUDGE:  Dump out Multibus Omninet board memory.
		 * BUG:  Have to fix this at some later date.
		 * sas
		 */
#include "mo.h"
#if NMO > 0				/* sbs was #ifdef NMOM */
		case '@':
		{
			register char *reg = (char *)0xd800;
			char ascii[17];
			char *asp = &ascii[0];
			short counter = mogetcounter(reg);

			ascii[16] = '\0';
			for (count=0; count<64; ++count)
			{
				u_char byte;

				byte = mogetbyte(reg, accum);
				if (' ' <= byte && byte <= '~')
					*asp++ = byte;
				else
					*asp++ = '.';
				if (count % 16 == 0)
					printf("\n%c%x  ", '@', accum);
				else if (count % 4 == 0)
					printf(" ");
				printf(" %x", (byte >> 4) & 0xF);
				printf("%x", byte & 0x0F);
				if (count % 16 == 15)
					printf("  %s", ascii),
					asp = &ascii[0];
				++accum;
			}
			value = accum;
			printf("\n");
			moloadcounter(reg, counter);
			break;
		}
#endif	NMO > 0
		/*
		 * Display all non-zombie extant processes
		 * in summary format.  C.f., 'r' for expanded display.
		 */
		case 'P':
		{
			register struct proc *p;

			for (p=proc; p<procNPROC; ++p)
			{
				if (p->p_stat == 0 || p->p_stat == SZOMB)
					continue;
				printf("slot %d (0x%x), pid %d, stat 0x%x, flag 0x%x, wchan=0x%X, ",
					p-proc, p, p->p_pid, p->p_stat,
					p->p_flag,
					p->p_wchan);

				prUpages("\n",p); /* printf() upage frame #-s */
				if (p->p_flag & SLOAD)
				{
					register struct user *pu;
#ifdef	CMD_BINGO
					short	cmd_BINGO_old = cmd_BINGO;
						cmd_BINGO = 0;	/* Preclude recursion */
#endif	CMD_BINGO

					pu = (struct user *)SSEG1_VA;
					temp = setpagemap(SSEG1_VA>>pageshift,
#ifdef WHITE_V_PRESENT
							  p->p_addr->pg_pfnum|V_PRESENT);
#else WHITE_V_PRESENT
							  p->p_addr->pg_pfnum);
#endif WHITE_V_PRESENT
					printf("    pc 0x%x\t-->",
						pu->u_pcb.pcb_regs.val[12]);
					showoffset((u_long *)
						pu->u_pcb.pcb_regs.val[12]);
					printf("\n");
					setpagemap(SSEG1_VA>>pageshift, temp);
						
#ifdef	CMD_BINGO
					cmd_BINGO = cmd_BINGO_old;
#endif	CMD_BINGO
				}
			}
			break;
		}

		/*
		 * Show hardware mmu values:
		 *	'q' ==> show h/w page map entry;
		 *	'Q' ==> show h/w segment map entry.
		 */
		case 'q':
		case 'Q':
		{
			u_short oldctxt;
			u_short firstentry,preventry,lastentry;
			u_long first,prev;
			int isfirst = 1;

			getContextReg(u.u_procp,oldctxt);
			if (btop(accum) > maxpage)
				accum = 0;
			first = accum &= ~pagemask;	/* Get all high bits */
			for (;;)
			{
#ifdef WHITE
				if (c == 'q')
					lastentry = getpagemap(btop(accum))
#ifdef	WHITE_V_PRESENT
							&(V_PAGEMASK|V_PRESENT);
#else	WHITE_V_PRESENT
							&(V_PAGEMASK);
#endif	WHITE_V_PRESENT
				else
					lastentry = getsegmap(ALLCTXT, accum) & 0xFFF;
				/*
				 * (Remember that getpagemap() can return -1.)
				 */
#else WHITE
				V_CONTEXT = (oldctxt & ~V_MAP_CONTROL) |
					(c == 'q' ? V_ACCPM : V_ACCSM) |
#ifdef	M68020_REV_B
					(accum & (u_long)V_PAGEMAP ? V_ACCHIGH
#else	M68020_REV_B
					(accum >= (u_long)V_PAGEMAP ? V_ACCHIGH
#endif	M68020_REV_B
								   : V_ACCLOW);
				lastentry = *(u_short *)(accum | V_PAGEMAP);
				if (c == 'q')
					lastentry &= ~(V_DIRTY | V_USED);
#endif WHITE
				if (isfirst)
					isfirst = 0, firstentry = lastentry;
				else if ((c == 'Q' ||
#ifdef WHITE
#ifndef BITFIELDSFIXED
					 ( lastentry != DummyMap ||
					   preventry != DummyMap   ) &&
#endif BITFIELDSFIXED
#endif WHITE
					 ( (lastentry & V_MISSING) != V_MISSING
					 ||(preventry & V_MISSING) != V_MISSING
					 )) && lastentry != preventry+1)
					break;
				preventry = lastentry;
				prev = accum;
				if (c == 'q')
					accum = (accum + pagesize) & ~pagemask;
				else
					accum = (accum + segsize) & ~pagemask;
				if (btop(accum) > maxpage)
					accum = 0;
			}
			setContextReg(u.u_procp,oldctxt);
			printf("0x%x - 0x%x ", first >> 12, prev >> 12);
			if (c == 'q')
			{
				if ((firstentry & V_MISSING) == V_MISSING)
					printf("are invalid\n");
#ifdef WHITE
#ifdef BITFIELDSFIXED
				else if (firstentry == DummyMap)
					printf("are dummy invalid\n");
#endif BITFIELDSFIXED
				else
					printf("map pages 0x%x - 0x%x\n",
						firstentry & V_PAGEMASK,
						preventry & V_PAGEMASK);
#else WHITE
#ifndef BITFIELDSFIXED
				else if (firstentry == DummyMap)
					printf("are dummy invalid\n");
#endif BITFIELDSFIXED
				else
				{
					printf("map ");
					if (firstentry & V_MBIO) printf("I/O");
					else			 printf("MBUS");
					printf(" pages 0x%x - 0x%x",
						firstentry & V_PAGEMASK,
						preventry & V_PAGEMASK);
#ifdef	M68020
					if (firstentry & V_NONCACHED)
						printf (" NON CACHED\n");
					else
#endif	M68020
						printf ("\n");
				}
#endif WHITE
			}
			if (c == 'Q')
			{
				printf("prot ");
				if (firstentry & V_SUSER) printf("U");
				if (firstentry & V_SWRITE) printf("W");
				if (firstentry & V_SREAD) printf("R");
				if (firstentry & V_SEXEC) printf("X");
				printf(" tables 0x%x - 0x%x\n",
					firstentry & (V_VSEGNO>>PTOSSHIFT),
					preventry  & (V_VSEGNO>>PTOSSHIFT));
			}
			break;
		}

		case '#':
		case '_':
		{
			u_char newctxt, oldctxt;
			int user = 0;

			getContextReg(u.u_procp,newctxt);
			newctxt = (newctxt & ~V_MAP_CONTROL) |
#ifdef	M68020_REV_B
				((accum & V_PAGEMAP) ? V_ACCHIGH : V_ACCLOW);
#else	M68020_REV_B
				((accum < V_PAGEMAP) ? V_ACCLOW : V_ACCHIGH);
#endif	M68020_REV_B
			printf(c == '#' ? " show " : " set ");
		where:
			switch (getchar())
			{
			case 'k':
				printf("ernel ");
				goto where;
			case 'u':
				printf("ser ");
				user = 1;
#ifdef WHITE
				newctxt |= V_ACCUSER;
#endif WHITE
				goto where;
			case 'p':
				printf("age");
				newctxt |= V_ACCPM;
				break;
			case 's':
				printf("egment");
				newctxt |= V_ACCSM;
				break;
			case 'm':
				printf("emory ");
				if (c == '#')
				{
					if (user)
						value = fubyte(accum);
					else
						value = *(u_char *)accum;
					printf("0x%x", value);
				}
				else
					if (user)
						subyte(accum, value);
					else
						*(u_char *)accum = value;
				goto donemap;
			default:
				printf("???");
				goto donemap;
			}
			printf(" map ");
			getContextReg(u.u_procp,oldctxt);
			setContextReg(u.u_procp,newctxt);
			if (c == '#')
				value = *(u_short *)(accum|V_PAGEMAP);
			else
				*(u_short *)(accum|V_PAGEMAP) = value;
			setContextReg(u.u_procp,oldctxt);
			if (c == '#')
				printf("0x%x", value);
		donemap:
			printf("\n");
			break;
		}

#ifdef KERN_RESTART
		/*
		 * Restart the kernel!
		 */
		case 'G':
			if (dangerous & DANGER_RESTART)
			{
				printf("oing to restart kernel ...\n");
				restartkernel();
			}
			printf(" -- Hit G again to restart kernel.\n");
			dangerous |= DANGER_RESTART << 1;
			break;
#endif KERN_RESTART

		/*
		 * Exit to xRM monitor!
		 */
		case 'V':
			if (dangerous & DANGER_VRM)
				reset(0);
			printf(" -- Hit V again to jump to VRM.\n");
			dangerous |= DANGER_VRM << 1;
			break;

		/*
		 * Whitespace -- ignore.
		 */
		case '\r':
		case '\n':
			break;

		/*
		 * Everything else...
		 */
		default:
			/*
			 * Process values intended for the accumulator.
			 */
			if ('0' <= c && c <= '9' ||
			    'a' <= c && c <= 'f')
			{
				value = 0;
				do
				{
					if ('0' <= c && c <= '9')
						value = value*16 + c - '0';
					else
						value = value*16 + c - 'a' + 10;
					c = getchar();
				} while ('0' <= c && c <= '9' ||
					 'a' <= c && c <= 'f');
				goto cmd;
			}
			else
				printf(" ???\n");
			break;
		}
	}
}

/*
 * prUpages -- print upages frame numbers onto the console.
 *
 * History:
 * ========
 * 860403 jht -- Centralize the presentation of some upage frame-# info.
 */
prUpages(str, p)	/* Printf "u@[NNN,...MMM]" upon the console */
	register char	      *	str;	/* Ptr to trailing string; or NULL */
	register struct	proc  *	p;	/* The relevant process		   */
{
	register struct pte   *	pte = p->p_addr;	/* For specified proc */
	register i;

	/*
	 * Sanity check -- could be VERY early,
	 * with an incomplete upage.
	 */
	if (pte) {
#ifndef	COMPILERBUG
		printf("u@[%x", (pte++)->pg_pfnum);
		for (i=1; i<UPAGES; i++,pte++)
			printf(",%x", pte->pg_pfnum);
#else	COMPILERBUG
		/*
		 * Circumvent kernel-mode pagefaults
		 * while bit-fielding with a pte.
		 */
		int 	j;		/* For local copy of faultable pte */

		j = *((int *)(pte++));	/* Copy pte to our stack */
		printf("u@[%x", ((struct pte *)(&j))->pg_pfnum);

		for (i=1; i<UPAGES; i++,pte++) {	/* ...all remaining */
			j = *((int *)(pte));
			printf(",%x", ((struct pte *)(&j))->pg_pfnum);
		}
#endif	COMPILERBUG
	} else {
		printf("p_addr=0");
	}

	if (str)
		printf("]%s", str);
	else
		printf("]");
}

/*
 * Print the values of all of the registers
 * from the array provided.
 */
prregs(regs)
   u_long *regs;
{
	register int reg;
	extern char *srdecode();
	int pid = (u.u_procp ? u.u_procp->p_pid : 0);

	if (regs == userregs)
		printf("pid %d, u_procp 0x%x, pc 0x%x, sr 0x%x (%s), sp (usp) 0x%x\n",
			pid, u.u_procp, regs[PC],
			regs[PS] & 0xFFFF, srdecode(regs[PS] & 0xFFFF),
			regs[SP]);
	else
		printf("pid %d, u_procp 0x%x, pc 0x%x, sr 0x%x (%s), sp 0x%x, usp 0x%x\n",
			pid, u.u_procp, regs[PC],
			regs[PS] & 0xFFFF, srdecode(regs[PS] & 0xFFFF),
			regs[SP], regs[J1]);
	for (reg=0; reg<16; ++reg)
	{
		printf("%c%d=0x%x%c",
			(reg < 8) ? 'd' : 'a',
			(reg < 8) ? reg : reg-8,
			regs[reg],
			(reg==7 || reg==15) ? '\n' : ' ');
	}
}
/*
 * Print the exception frame which begins
 * at the location supplied.
 */
prframe(base)
   u_short *base;
{
	u_short type = (base[3] & 0x0FFF) >> 2;
	extern char *ssrdecode();
#if	defined(M68020)
	extern char *sswDecode();
#endif	defined(M68020)

	printf("Trap type %d (%s), pc = 0x%x, ps = 0x%x\n",
		type,
		(type == 32) ? "system call" :
#if	defined(M68010) || defined(M68020)
			       ((type < TRAP_TYPES)
					? (chipType==CHIPTYPE_68010)
						? trap_type_68010[type]
						: (chipType==CHIPTYPE_68020)
							? trap_type_68020[type]
							: "prframe/E-0: unknown"
					: "prframe/E-1: unknown"
				),
#else	defined(M68010) || defined(M68020)
			       ((type < TRAP_TYPES)
					? trap_type[type] :
					"unknown"),
#endif	defined(M68010) || defined(M68020)
		*(u_long *)&base[1], base[0]);

	/*
	 * Decode the stack frame format
	 */
	switch ((base[3] & 0xF000) >> 12)
	{
	case 0x0:
		break;

#if	defined(M68010)
	case 0x8:	/* Bus Fault (29 words) */
		printf("ssr = 0x%x: %s\n", base[4], ssrdecode(base[4]));
		printf("addr = 0x%x, do = 0x%x, di = 0x%x, ii = 0x%x\n",
			*(u_long *)&base[5], base[8], base[10], base[12]);
		break;
#endif	defined(M68010)

#if	defined(M68020)
	case 0xA:	/* Short Bus Fault (16 words) */
		printf("ssw = 0x%x: short fault-frame (16 words): %s\n",
			base[5], sswDecode(base[5]));
		break;

	case 0xB:	/* Long Bus Fault (44 words) */
		printf("ssw = 0x%x: long fault-frame (44 words): %s\n",
			base[5], sswDecode(base[5]));
		break;

	/*
	 * Format the frame info much like trap() does it.
	 */
#endif	defined(M68020)

	default:
		printf("  unknown exception format type 0x%x\n",
			(base[3] & 0xF000) >> 12);
		break;
	}
}
/*
 * Decode the bits in the status register
 * and return a pointer to a static string
 * representing them.
 */
char *srdecode(sr)
   register int sr;
{
	static char msg[9];
	register char *msgp = &msg[0];

	if (sr & 0x2000) *msgp++ = 'S';
	else             *msgp++ = 'U';
	*msgp++ = '0' + ((sr & 0x0700) >> 8);
	if (sr & 0x8000) *msgp++ = 'T';
	if (sr & 0x0010) *msgp++ = 'X';
	if (sr & 0x0008) *msgp++ = 'N';
	if (sr & 0x0004) *msgp++ = 'Z';
	if (sr & 0x0002) *msgp++ = 'V';
	if (sr & 0x0001) *msgp++ = 'C';
	*msgp++ = '\0';
	return(&msg[0]);
}

char *fcmsg[8] =
{
	"0 (unassigned)",
	"1 (user data)",
	"2 (user program)",
	"3 (unassigned)",
	"4 (unassigned)",
	"5 (kernel data)",
	"6 (kernel program)",
	"7 (cpu space)"
};

/*
 * Decode the bits in the special status
 * register obtained from a bus/address
 * error exception frame.
 */
 char *
ssrdecode(ssr)
   register int ssr;
{
	static char msg[60];

	msg[0] = '\0';
	if (ssr & 0x8000) strcat(msg, ",rr");
	if (ssr & 0x2000) strcat(msg, ",if");
	if (ssr & 0x1000) strcat(msg, ",df");
	if (ssr & 0x0800) strcat(msg, ",rmw");
	if (ssr & 0x0400) strcat(msg, ",hb");
	else              strcat(msg, ",lb");
	if (ssr & 0x0200) strcat(msg, ",byte");
	else              strcat(msg, ",word");
	if (ssr & 0x0100) strcat(msg, ",read");
	else              strcat(msg, ",write");
	strcat(msg, ",fc = ");
	strcat(msg, fcmsg[ssr & 0x0007]);
	return(&msg[1]);
}

#ifdef	M68020

/*
 * Decode the bits in the special status
 * register obtained from a bus/address
 * error exception frame.
 */
 char *
sswDecode(ssW)
	register u_short ssW;
{
	static	char	msg[64];

	msg[0] = '\0';
	if  (ssW & 0x8000)	strcat(msg, ",fc");	/* Faulted stage */
	if  (ssW & 0x4000)	strcat(msg, ",fb");
	if  (ssW & 0x2000)	strcat(msg, ",rc");	/* Rerun stage */
	if  (ssW & 0x1000)	strcat(msg, ",rb");

	if  (ssW & 0x0100)	strcat(msg, ",df");	/* Data cycle */

	if  (ssW & 0x0080)	strcat(msg, ",rmw");	/* Read/modify/write */

	if ((ssW & 0x0030)==0)	strcat(msg, ",long");
	if ((ssW & 0x0030)==1)	strcat(msg, ",byte");
	if ((ssW & 0x0030)==2)	strcat(msg, ",short");
	if ((ssW & 0x0030)==3)	strcat(msg, ",3-byte");

	if  (ssW & 0x0040)	strcat(msg, ",read");
	else			strcat(msg, ",write");

	strcat(msg, ",fc = ");			/* 3-bit Function Code */
	strcat(msg, fcmsg[ssW & 0x0007]);

	return(&msg[1]);
}
#endif	M68020

/*
 * Concatenate the second string onto the
 * end of the first string.
 */
strcat(dest, source)
   register char *dest,*source;
{
	while (*dest)
		++dest;
	while (*source)
		*dest++ = *source++;
	*dest = '\0';
}
/*
 * Show the pid, pc, sr, sp, and usp and then
 * only the registers which have changed.
 */
diffregs(oldregs, regs)
   u_long *oldregs;
   u_long *regs;
{
	register int reg;
	int pid = (u.u_procp ? u.u_procp->p_pid : 0);

	printf("pid %d, pc 0x%x, sr 0x%x, sp 0x%x, usp 0x%x\n",
		pid, regs[PC], regs[PS] & 0xFFFF,
		regs[SP], regs[J1]);
	for (reg=0; reg<16; ++reg)
	{
		if (oldregs[reg] != regs[reg])
		{
			printf("%c%d 0x%x => 0x%x\n",
				(reg < 8) ? 'd' : 'a',
				(reg < 8) ? reg : reg-8,
				oldregs[reg], regs[reg]);
		}
	}
}
/*
 * Trace the stack back from a particular
 * point assuming that the frames have
 * been linked using the 68000 link instruction.
 * Abort when an address is not in the U page,
 * is not on the top 128k of the user's stack and
 * is not in the temporary stack at 0x1000.
 */
strace(stack)
   u_long *stack;
#define Stack ((u_long)stack)
{
	int count = 20;

	printf("(sp,pc):");
	while (count--)
	{
		if ((Stack & 1) ||
		    (Stack < U_PAGE+sizeof(u) || U_PAGE+(u_long)ptob(UPAGES) <= Stack) &&
		    /*
		     * Reference the current process for 'usrtop'
		     */
		    (Stack < ((u_long)ptob(usrtop(u.u_procp))-128*1024) || (u_long)ptob(usrtop(u.u_procp)) <= Stack) &&
		    (Stack < 0x0800 || 0x1000 <= Stack))
			break;
		printf(" (%x,%x)", &stack[1], stack[1]);
		stack = (u_long *)*stack;
	}
	printf("\n");
}
/*
 * Show a stack trace based on the current
 * frame pointer based on the address of a
 * local variable.
 */
stacktrace()
{
	u_long *stack;

	strace((u_long *)((u_long)&stack + 4));
}
/*
 * Show each complete frame for the given stack.
 */
frametrace(stack)
   u_long *stack;
{
	int count = 20;
	extern _etext;

	printf("(sp,pc):");
	while (count--)
	{
		if ((Stack & 1) ||
		    (Stack < U_PAGE+sizeof(u) || U_PAGE+(u_long)ptob(UPAGES) <= Stack) &&
		    /*
		     * Reference the current process for 'usrtop'
		     */
		    (Stack < (u_long)ptob(usrtop(u.u_procp))-128*1024 || (u_long)ptob(usrtop(u.u_procp)) <= Stack) &&
		    (Stack < 0x0800 || 0x1000 <= Stack))
			break;
		printf("%x: ", &stack[1]);
		if ((int)K_A <= stack[1] && stack[1] < (int)&_etext)
		{
			register int nargs = 0;
			register u_long *argp = &stack[2];
			register u_short instr;

			showoffset(stack[1]);
			if (*(u_short *)(stack[1] - 6) == JSRINST)
			{
				printf("  ");
				showoffset(*(u_long *)(stack[1]-4));
			}
			else if ((*(u_short *)(stack[1]-2) & 0xFFF8) == 0x4E90)
				printf("  [a%d]", *(u_short *)(stack[1]-2) & 7);
			instr = *(u_short *)stack[1];
			if (instr == 0x588F)		/* subql #4,a7 */
				nargs = 4 / sizeof(long);
			else if (instr == 0x508F)	/* subql #8,a7 */
				nargs = 8 / sizeof(long);
			else if (instr == 0xDFFC)	/* subl #xxx,a7 */
				nargs = *(u_long *)(stack[1] + 2) / sizeof(long);
			if (nargs > 6)
				nargs = 6;
			printf("(");
			while (nargs--)
			{
				printf("0x%x", *argp++);
				if (nargs != 0)
					printf(", ");
			}
			printf(")\n");
		}
		else
			printf("%x\n", stack[1]);
		stack = (u_long *)*stack;
	}
}
/*
 * Exchange the shorts at each breakpoint
 * location with the short stored in the
 * breakpoint structure.  This works both
 * for setting and unsetting breakpoints.
 */
xchbrk()
{
	register struct bpt *bp = &bpt[0];

	for (; bp != &bpt[MAXBRK]; ++bp)
		if (bp->type != BRK_NONE && bp->addr != skipaddr &&
		    (bp->pid == NOPID || bp->pid == u.u_procp->p_pid))
		{
			u_short temp;

			/*
			 * (Remember that getpagemap() can return -1.)
			 */
			debugmap(getpagemap(bp->addr >> pageshift), 1);
			temp = *(u_short *)(DEBUG_VA+(bp->addr&pagemask));
			*(u_short *)(DEBUG_VA+(bp->addr&pagemask))=bp->content;
			debugunmap();
			bp->content = temp;
		}
}

/*
 * showsym: lookup the typed-in symbol in the symbol table which is
 *          mapped in at DEBUG_VA
 *	    Return the value of the symbol or 0 if it is not found
 */
#ifndef	QUICKEN
showsym()
#else	QUICKEN

 int
showsym(namep, printSymVal)
/*A5*/	register char	*namep;  /* Possibly NULL ptr to sought-after sym   */
/*D7*/	register int	printSymVal;	/* 0==> DON'T print value of symbol */
#endif	QUICKEN
{
	char		symbol[64];
/*A4*/	register char	*sp	= &symbol[0];
/*D6*/	register u_long	symval	= 0 ;	/* Value of sought-after symbol */
	extern	 int	symbytes,
			oldsyms;

	if (symbytes == 0) {
		printf("\nSorry, there is no symbol table.\n");
		return(0);
	}

	for (;;)
	{
#ifdef	QUICKEN
/*A3*/		register char	* cp	=  namep;
/*A2*/		register char	* cpMax	= &namep[sizeof(symbol)-1]; /* Last slot */
#endif	QUICKEN

#ifndef	QUICKEN
		*sp = getchar();
#else	QUICKEN
		/*
		 * Either use the symbol from our invocation call,
		 * or get symbol from operator's console.
		 */
		if (namep) {
			/*
			 * Use the symbol from the parameter list:
			 * Copy symbol to our local buffer.
			 */
			while (*cp && (cp < cpMax))
				*sp++ = *cp++;
			/*
			 * Now pointing at the NUL terminator character.
			 * Compensate for subsequent '*--sp'
			 * NOTE:  Also deals with degenerate case: no symbol.
			 */
			sp++;
			break;

		} else {
			/*
			 * Get symbol from operator's console.
			 */
			*sp = getchar();
		}
#endif	QUICKEN

		if (*sp == '\b')
		{
			if (sp == &symbol[0])
				printf("=");
			else
				--sp, printf(" \b");
			continue;
		}

		if (sp == &symbol[sizeof(symbol)-1]) sp--;

		/*
		 * Check for termination condition -- end-of-symbol.
		 */
		if (*sp++ == '=' || sp[-1] == '\n')
			break;
	}

	*--sp = '\0';		/* NUL terminate the symbol */

	/*
	 * Avoid any further processing if no symbol
	 * has been specified -- maybe user changed his mind.
	 */
	if (sp == &symbol[0]) {
		printf(" No symbol specified. ");
		return NULL;
	}

	/*
	 * Map in the memory resident kernel symbol table.
	 */
	debugmap(btop(SYM_PA), DEBUG_SYMPAGES);

	if (oldsyms) {
		register char *symp = (char *)DEBUG_VA;
		register int count = symbytes;
		int i,ndef = 0;

		while (count > 0) {
/*D5*/			register int length = 6 + strlen(symp+6)+1;

			if (strcmp(symp+6,symbol) == 0) {
/*D4*/				register char type;

				++ndef;
				switch (*symp) {
				case UNDEF:	   type = 'u'; break;
				case ABS:	   type = 'a'; break;
				case TEXT:	   type = 't'; break;
				case DATA:	   type = 'd'; break;
				case BSS:	   type = 'b'; break;
				case UNDEF|EXTERN: type = 'U'; break;
				case ABS|EXTERN:   type = 'A'; break;
				case TEXT|EXTERN:  type = 'T'; break;
				case DATA|EXTERN:  type = 'D'; break;
				case BSS|EXTERN:   type = 'B'; break;
				default:	   type = '?'; break;
				}

				symval = 0;
				for (i=0; i<4; i++)
				    symval = (symval << 8)+(u_char)symp[i+2];
				/*
				 * Printf only if we were so told.
				 */
#ifdef	QUICKEN
				if (printSymVal)
#endif	QUICKEN
					printf("  0x%x %c", symval, type);
			}
			symp  += length;
			count -= length;
		}
		if (ndef == 0)	    printf(" no such symbol\n");
#ifndef	QUICKEN
		else if (ndef == 1) printf("\n");
#else	QUICKEN
		else if (ndef == 1)
			if (printSymVal) printf("\n");
			else	;
#endif	QUICKEN
		else		    printf("  (multiple definitions)\n");
	}
	else {
		printf("\nSorry, new format symbol table lookup is not yet\n");
		printf("implemented.\n");
	}
	debugunmap();
	return(symval);
}
/*
 * Find the symbol whose value is closest to,
 * but not greater than a value and PRINT the symbol
 * name and offset.
 */
showoffset(value)
   register u_long value;
{
	register u_long offset = 0xFFFFFFFF;
	char *symbol;
	extern int symbytes, oldsyms;

	if (symbytes == 0) {
		printf("\nSorry, there is no symbol table.\n");
		return;
	}
	debugmap(btop(SYM_PA), DEBUG_SYMPAGES);
	if (oldsyms) {
		register char *symp = (char *)DEBUG_VA;
		register int count = symbytes;

		while (count > 0) {
			register int i;
			register u_long symval = 0;
			register int length = 6 + strlen(symp+6)+1;

			for (i=0; i<4; i++)
			    symval = (symval << 8)+(u_char)symp[i+2];
			if (symval <= value && (value - symval) < offset)
				offset = value - symval, symbol = symp + 6;
			symp  += length;
			count -= length;
		}
	}
	else {
		printf("\nSorry, new format symbol table lookup is not yet\n");
		printf("implemented.\n");
		return;
	}
	if (offset == (u_long)0xFFFFFFFF)
		printf(" That is below all symbols\n");
	else if (offset == 0)
		printf("%s", symbol);
	else
		printf("%s+0x%x", symbol, offset);
	debugunmap();
}
/*
 * Map pages into the debugger virtual area
 * and record the old values so that they
 * can be restored.
 */
debugmap(ppage, count)
   register int ppage;	/* Could be -1. */
   register int count;
{
	register u_short *p = &savedmap[0];
	register int vpage = DEBUG_PAGE;
#ifdef	CMD_BINGO
	short	cmd_BINGO_old	= cmd_BINGO;
		cmd_BINGO	= 0;		/* Preclude recursion */
#endif	CMD_BINGO

#ifdef	LATER
	ppage &= V_PAGEMASK;
#endif	LATER
	if (savedcount)
		debugunmap();
	while (count--)
	{
#ifdef WHITE_V_PRESENT
		*p++ = setpagemap(vpage++, ppage++ | V_PRESENT);
#else WHITE_V_PRESENT
		*p++ = setpagemap(vpage++, ppage++);
#endif WHITE_V_PRESENT
		++savedcount;
	}
#ifdef	CMD_BINGO
	cmd_BINGO = cmd_BINGO_old;
#endif	CMD_BINGO
}
/*
 * Restore the map to what it was like
 * before the debugger changed it.  If
 * it has not been changed then do nothing.
 */
debugunmap()
{
	register u_short *p = &savedmap[0];
	register int vpage = DEBUG_PAGE;
#ifdef	CMD_BINGO
	short	cmd_BINGO_old	= cmd_BINGO;
		cmd_BINGO	= 0;		/* Preclude recursion */
#endif	CMD_BINGO

#ifdef	M68020_REV_B
	savedcount &= 0xF;
#endif	M68020_REV_B
	while (savedcount--)
		setpagemap(vpage++, *p++);
	savedcount = 0;
#ifdef	CMD_BINGO
	cmd_BINGO = cmd_BINGO_old;
#endif	CMD_BINGO
}
/*
 * Read from memory.  This may be user,
 * physical, etc.
 */
u_long readmem(addr, format)
   register u_long addr;
   register int format;
{
	register u_long value;

#ifdef WHITE
	if (format & FMT_PHYS && addr < 0x800000)
#else WHITE
	if (format & FMT_PHYS)
#endif WHITE
	{
		debugmap(addr >> pageshift, 1);
		addr = DEBUG_VA + (addr & pagemask);
	}
	switch (format)
	{
	case FMT_USER | FMT_BYTE: value = fubyte(addr); break;
	case FMT_USER | FMT_SHORT: value = fushort(addr); break;
	case FMT_USER | FMT_LONG: value = fuword(addr); break;
	case FMT_KERNEL | FMT_BYTE: value = *(u_char *)addr; break;
	case FMT_KERNEL | FMT_SHORT: value = *(u_short *)addr; break;
	case FMT_KERNEL | FMT_LONG: value = *(u_long *)addr; break;
	case FMT_PHYS | FMT_BYTE: value = *(u_char *)addr; break;
	case FMT_PHYS | FMT_SHORT: value = *(u_short *)addr; break;
	case FMT_PHYS | FMT_LONG: value = *(u_long *)addr; break;
	}
	if (format & FMT_PHYS)
		debugunmap();
	return(value);
}
/*
 * Write to memory.  This may be user,
 * physical, etc.
 */
writemem(addr, format, value)
   register u_long addr;
   register int format;
   register u_long value;
{
#ifdef WHITE
	if (format & FMT_PHYS && addr < 0x800000)
#else WHITE
	if (format & FMT_PHYS)
#endif WHITE
	{
		debugmap(addr >> pageshift, 1);
		addr = DEBUG_VA + (addr & pagemask);
	}
	switch (format)
	{
	case FMT_USER | FMT_BYTE: subyte(addr, value); break;
	case FMT_USER | FMT_SHORT: sushort(addr, value); break;
	case FMT_USER | FMT_LONG: suword(addr, value); break;
	case FMT_KERNEL | FMT_BYTE: *(u_char *)addr = value; break;
	case FMT_KERNEL | FMT_SHORT: *(u_short *)addr = value; break;
	case FMT_KERNEL | FMT_LONG: *(u_long *)addr = value; break;
	case FMT_PHYS | FMT_BYTE: *(u_char *)addr = value; break;
	case FMT_PHYS | FMT_SHORT: *(u_short *)addr = value; break;
	case FMT_PHYS | FMT_LONG: *(u_long *)addr = value; break;
	}
	if (format & FMT_PHYS)
		debugunmap();
}

#ifdef KERN_RESTART

int	kernrestarting = 0;	/* Should be in data space */
int	txtchksum = 0;		/* Checksum of text area */
int	datchksum = 0;		/* Checksum of saved data area */
int	symchksum = 0;		/* Checksum of saved symbol table */

/*
 * Save the initialized data portion of the
 * kernel immediately following BSS so that
 * it can be restored if the kernel is
 * restarted.  A virgin copy of the initialized
 * data can be found at 3/4 meg in physical
 * memory.
 */
savekernel()
{
	extern _edata, _etext, _end;
	register int dsize = (int)&_edata - (int)&_etext;
	register char *to = (char *)&_end;
	register char *from = (char *)0xC0000;	/* 3/4Mb: restart savearea */

	txtchksum = findchksum(K_A, (int)&_etext - K_A);
	datchksum = findchksum(from, dsize);
	symchksum = findchksum(SYM_PA, symbytes);
	bcopy(from, to, dsize);
}
/*
 * Restart the kernel by setting an identity
 * map, replacing the initialized data with
 * the saved copy, and placing the symbol
 * table after it.  Note everything must be
 * in registers since we will be destroying
 * our stack.
 */
restartkernel()
{
	extern _edata, _etext, _end;
	register int seg = nSegs;
	register int page = maxpage+1;
	register int dsize = (int)&_edata - (int)&_etext;
	register int ssize = symbytes;
	register char *to = (char *)&_etext;
	register char *from = (char *)&_end;
#ifdef	CMD_BINGO
	short	cmd_BINGO_old	= cmd_BINGO;
		cmd_BINGO	= 0;		/* Preclude recursion */
#endif	CMD_BINGO

	/*
	 * Set an identity map in both the segment
	 * and page maps.
	 */
	kernrestarting = 1;
	while (seg--)
		setSegMap(ALLCTXT, seg << SEGSHIFT, seg|SEG_ASYS, nSegs);
	while (page--)
		setpagemap(page, page);

	/*
	 * Check that none of the saved areas have
	 * been damaged.
	 */
	if (txtchksum != findchksum(K_A, (int)&_etext - K_A))
		printf("Text has been damaged\n");
	if (datchksum != findchksum(from, dsize))
		printf("Data has been damaged\n");
	if (symchksum != findchksum(SYM_PA, ssize))
		printf("Symbol table has been damaged\n");

	/*
	 * Copy the saved version of the data
	 * area immediately after text.
	 */
	while (dsize--)
		*to++ = *from++;

	/*
	 * Copy the symbol table from it place in
	 * low physical memory immediately after
	 * the data just copied.
	 */
	from = (char *)SYM_PA;
	while (ssize--)
		*to++ = *from++;

#ifdef	CMD_BINGO
	cmd_BINGO = cmd_BINGO_old;
#endif	CMD_BINGO

	/*
	 * Jump to the kernel starting address.
	 */
	asm(" .globl	start	| Entry point to kernel: == K_A");
	asm(" jmp	start");
}
/*
 * Compute a checksum of the given area of
 * memory.  This is used in determining if
 * the bytes used for a restart are corrupt
 * or not.
 */
int findchksum(buf, size)
   register unsigned char *buf;		/* Must be in a5 */
   register int size;			/* Must be in d7 */
{
	register int sum = 0;		/* Must be in d6 */

asm("	lsrl	#2,d7		");
asm("	subql	#1,d7		");
asm("findchkloop:		");
asm("	addl	a5@+,d6		");
asm("	dbf	d7,findchkloop	");

	return(sum);
}
#endif KERN_RESTART

asm("        .text			");
asm("        .globl  asmdebugger	");
asm("asmdebugger:			");
asm("        moveml  #0xFFFF,dbgregs    ");	/* Save D0-D7, A0-A7 */
asm("        movl    usp,a0		");
asm("        movl    a0,dbgregs+64.	");	/* Save USP in junk word area */
asm("        movl    sp@(6),dbgregs+72	");	/* Program counter to RTE */
asm("        clrl    d0			");
asm("        movw    sp@(4),d0		");	/* Status register to RTE */
asm("        movl    d0,dbgregs+68.	");
asm("        movw    sp@(10),dbgtype	");	/* Save format word */
asm("        movl    dbgstktop,sp	");	/* Run on a special stack */
asm("        jsr     debugger		");
asm("        movl    dbgregs+64.,a0	");	/* Restore USP */
asm("        movl    a0,usp		");
asm("        moveml  dbgregs,#0xFFFF	");	/* Restore all registers */
asm("        movl    dbgregs+72,sp@(6)	");	/* Restore PC for RTE */
asm("        movw    dbgregs+70,sp@(4)	");	/* Restore SR for RTE */
asm("        rts			");

asm("        .globl  tracer		");
asm("        .globl  dbgtrap		");
asm("        .globl  bpttrap		");
asm("tracer:				");
asm("dbgtrap:				");
asm("bpttrap:				");
asm("        movw    #0x2700,sr		");	/* Prevent interrupts on */
asm("        jsr     asmdebugger	");	/*   debug stack */
asm("        rte			");	/* SR gets restored here */

/***** BUG *******/
/* 
 *	Need to do something resonable about 68020 errata and error
 *	register handling.  This includes the toggling of the status 
 *	on timeouts.
 *
 *	ELP - 9/4/85
 */
asm("        .globl  memfault		");
asm("        .globl  longjmp		");
asm("memfault:				");
asm("        movl    #myfault,sp@-	");
asm("        jsr     longjmp		");	/* longjmp(myfault); */
