xref: /original-bsd/sys/hp300/hp300/kgdb_stub.c (revision 673a3ece)
185e7c9a4Smckusick /*
24975c9eaSbostic  * Copyright (c) 1990, 1993
34975c9eaSbostic  *	The Regents of the University of California.  All rights reserved.
485e7c9a4Smckusick  *
59299354bSmckusick  * This software was developed by the Computer Systems Engineering group
69299354bSmckusick  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
79299354bSmckusick  * contributed to Berkeley.
89299354bSmckusick  *
99299354bSmckusick  * All advertising materials mentioning features or use of this software
109299354bSmckusick  * must display the following acknowledgement:
119299354bSmckusick  *	This product includes software developed by the University of
129299354bSmckusick  *	California, Lawrence Berkeley Laboratories.
13c8c6fa19Smckusick  *
1485e7c9a4Smckusick  * %sccs.include.redist.c%
1585e7c9a4Smckusick  *
16*673a3eceShibler  *	@(#)kgdb_stub.c	8.4 (Berkeley) 01/12/94
1785e7c9a4Smckusick  */
18c8c6fa19Smckusick 
1985e7c9a4Smckusick /*
20cbea78c6Skarels  * "Stub" to allow remote cpu to debug over a serial line using gdb.
21cbea78c6Skarels  */
2285e7c9a4Smckusick #ifdef KGDB
23cbea78c6Skarels #ifndef lint
24d8882d00Shibler static char rcsid[] = "$Header: /usr/src/sys/hp300/hp300/RCS/kgdb_stub.c,v 1.5 92/12/20 15:49:01 mike Exp $";
25cbea78c6Skarels #endif
26cbea78c6Skarels 
274e6f2c04Sbostic #include <sys/param.h>
284e6f2c04Sbostic #include <sys/systm.h>
29cbea78c6Skarels 
304e6f2c04Sbostic #include <machine/trap.h>
314e6f2c04Sbostic #include <machine/cpu.h>
324e6f2c04Sbostic #include <machine/psl.h>
334e6f2c04Sbostic #include <machine/reg.h>
344e6f2c04Sbostic #include <machine/frame.h>
354e6f2c04Sbostic 
364e6f2c04Sbostic #include <sys/buf.h>
374e6f2c04Sbostic #include <hp/dev/cons.h>
384e6f2c04Sbostic 
394e6f2c04Sbostic #include <hp300/hp300/kgdb_proto.h>
404e6f2c04Sbostic #include <machine/remote-sl.h>
4185e7c9a4Smckusick 
4285e7c9a4Smckusick extern int kernacc();
4385e7c9a4Smckusick extern void chgkprot();
4485e7c9a4Smckusick 
45bcba0716Smckusick #ifndef KGDBDEV
46aa5efb8eSkarels #define KGDBDEV NODEV
47bcba0716Smckusick #endif
48bcba0716Smckusick #ifndef KGDBRATE
49bcba0716Smckusick #define KGDBRATE 9600
50bcba0716Smckusick #endif
51bcba0716Smckusick 
52aa5efb8eSkarels dev_t kgdb_dev = KGDBDEV;	/* remote debugging device (NODEV if none) */
53bcba0716Smckusick int kgdb_rate = KGDBRATE;	/* remote debugging baud rate */
54cbea78c6Skarels int kgdb_active = 0;            /* remote debugging active if != 0 */
5585e7c9a4Smckusick int kgdb_debug_init = 0;	/* != 0 waits for remote at system init */
56b6ace64eSkarels int kgdb_debug_panic = 1;	/* != 0 waits for remote on panic */
57cbea78c6Skarels int kgdb_debug = 0;
5885e7c9a4Smckusick 
59cbea78c6Skarels #define GETC	((*kgdb_getc)(kgdb_dev))
60cbea78c6Skarels #define PUTC(c)	((*kgdb_putc)(kgdb_dev, c))
61cbea78c6Skarels #define PUTESC(c) { \
62cbea78c6Skarels 	if (c == FRAME_END) { \
63cbea78c6Skarels 		PUTC(FRAME_ESCAPE); \
64cbea78c6Skarels 		c = TRANS_FRAME_END; \
65cbea78c6Skarels 	} else if (c == FRAME_ESCAPE) { \
66cbea78c6Skarels 		PUTC(FRAME_ESCAPE); \
67cbea78c6Skarels 		c = TRANS_FRAME_ESCAPE; \
68c8c6fa19Smckusick 	} else if (c == FRAME_START) { \
69c8c6fa19Smckusick 		PUTC(FRAME_ESCAPE); \
70c8c6fa19Smckusick 		c = TRANS_FRAME_START; \
71cbea78c6Skarels 	} \
72cbea78c6Skarels 	PUTC(c); \
73bcba0716Smckusick }
74cbea78c6Skarels static int (*kgdb_getc)();
75cbea78c6Skarels static int (*kgdb_putc)();
7685e7c9a4Smckusick 
7785e7c9a4Smckusick /*
78cbea78c6Skarels  * Send a message.  The host gets one chance to read it.
7985e7c9a4Smckusick  */
80cbea78c6Skarels static void
kgdb_send(type,bp,len)81cbea78c6Skarels kgdb_send(type, bp, len)
82cbea78c6Skarels 	register u_char type;
83cbea78c6Skarels 	register u_char *bp;
84cbea78c6Skarels 	register int len;
8585e7c9a4Smckusick {
86cbea78c6Skarels 	register u_char csum;
87cbea78c6Skarels 	register u_char *ep = bp + len;
88cbea78c6Skarels 
89c8c6fa19Smckusick 	PUTC(FRAME_START);
90c8c6fa19Smckusick 	PUTESC(type);
91cbea78c6Skarels 
92c8c6fa19Smckusick 	csum = type;
93cbea78c6Skarels 	while (bp < ep) {
94cbea78c6Skarels 		type = *bp++;
95cbea78c6Skarels 		csum += type;
96cbea78c6Skarels 		PUTESC(type)
97cbea78c6Skarels 	}
98cbea78c6Skarels 	csum = -csum;
99cbea78c6Skarels 	PUTESC(csum)
100cbea78c6Skarels 	PUTC(FRAME_END);
101cbea78c6Skarels }
102cbea78c6Skarels 
103cbea78c6Skarels static int
kgdb_recv(bp,lenp)104cbea78c6Skarels kgdb_recv(bp, lenp)
105cbea78c6Skarels 	u_char *bp;
106cbea78c6Skarels 	int *lenp;
107cbea78c6Skarels {
108cbea78c6Skarels 	register u_char c, csum;
109cbea78c6Skarels 	register int escape, len;
110cbea78c6Skarels 	register int type;
111cbea78c6Skarels 
112c8c6fa19Smckusick restart:
113cbea78c6Skarels 	csum = len = escape = 0;
114cbea78c6Skarels 	type = -1;
115cbea78c6Skarels 	while (1) {
116cbea78c6Skarels 		c = GETC;
117cbea78c6Skarels 		switch (c) {
118cbea78c6Skarels 
119cbea78c6Skarels 		case FRAME_ESCAPE:
120cbea78c6Skarels 			escape = 1;
121cbea78c6Skarels 			continue;
122cbea78c6Skarels 
123cbea78c6Skarels 		case TRANS_FRAME_ESCAPE:
124cbea78c6Skarels 			if (escape)
125cbea78c6Skarels 				c = FRAME_ESCAPE;
126cbea78c6Skarels 			break;
127cbea78c6Skarels 
128cbea78c6Skarels 		case TRANS_FRAME_END:
129cbea78c6Skarels 			if (escape)
130cbea78c6Skarels 				c = FRAME_END;
131cbea78c6Skarels 			break;
132cbea78c6Skarels 
133c8c6fa19Smckusick 		case TRANS_FRAME_START:
134c8c6fa19Smckusick 			if (escape)
135c8c6fa19Smckusick 				c = FRAME_START;
136c8c6fa19Smckusick 			break;
137c8c6fa19Smckusick 
138c8c6fa19Smckusick 		case FRAME_START:
139c8c6fa19Smckusick 			goto restart;
140c8c6fa19Smckusick 
141cbea78c6Skarels 		case FRAME_END:
142cbea78c6Skarels 			if (type < 0 || --len < 0) {
143cbea78c6Skarels 				csum = len = escape = 0;
144cbea78c6Skarels 				type = -1;
145cbea78c6Skarels 				continue;
146cbea78c6Skarels 			}
147cbea78c6Skarels 			if (csum != 0) {
14885e7c9a4Smckusick 				return (0);
14985e7c9a4Smckusick 			}
150cbea78c6Skarels 			*lenp = len;
151cbea78c6Skarels 			return type;
152cbea78c6Skarels 		}
153cbea78c6Skarels 		csum += c;
154cbea78c6Skarels 		if (type < 0) {
155cbea78c6Skarels 			type = c;
156cbea78c6Skarels 			escape = 0;
157cbea78c6Skarels 			continue;
158cbea78c6Skarels 		}
159c8c6fa19Smckusick 		if (++len > SL_RPCSIZE) {
160cbea78c6Skarels 			while (GETC != FRAME_END)
16185e7c9a4Smckusick 				;
162cbea78c6Skarels 			return (0);
16385e7c9a4Smckusick 		}
164cbea78c6Skarels 		*bp++ = c;
165cbea78c6Skarels 		escape = 0;
16685e7c9a4Smckusick 	}
16785e7c9a4Smckusick }
16885e7c9a4Smckusick 
16985e7c9a4Smckusick /*
17085e7c9a4Smckusick  * Translate a trap number into a unix compatible signal value.
17185e7c9a4Smckusick  * (gdb only understands unix signal numbers).
17285e7c9a4Smckusick  */
17385e7c9a4Smckusick static int
computeSignal(type)174cbea78c6Skarels computeSignal(type)
175cbea78c6Skarels 	int type;
17685e7c9a4Smckusick {
17785e7c9a4Smckusick 	int sigval;
17885e7c9a4Smckusick 
179b971627aSkarels 	switch (type) {
18085e7c9a4Smckusick 	case T_BUSERR:
18185e7c9a4Smckusick 		sigval = SIGBUS;
182cbea78c6Skarels 		break;
18385e7c9a4Smckusick 	case T_ADDRERR:
18485e7c9a4Smckusick 		sigval = SIGBUS;
185cbea78c6Skarels 		break;
18685e7c9a4Smckusick 	case T_ILLINST:
18785e7c9a4Smckusick 		sigval = SIGILL;
188cbea78c6Skarels 		break;
18985e7c9a4Smckusick 	case T_ZERODIV:
19085e7c9a4Smckusick 		sigval = SIGFPE;
191cbea78c6Skarels 		break;
19285e7c9a4Smckusick 	case T_CHKINST:
19385e7c9a4Smckusick 		sigval = SIGFPE;
194cbea78c6Skarels 		break;
19585e7c9a4Smckusick 	case T_TRAPVINST:
19685e7c9a4Smckusick 		sigval = SIGFPE;
197cbea78c6Skarels 		break;
19885e7c9a4Smckusick 	case T_PRIVINST:
19985e7c9a4Smckusick 		sigval = SIGILL;
200cbea78c6Skarels 		break;
20185e7c9a4Smckusick 	case T_TRACE:
20285e7c9a4Smckusick 		sigval = SIGTRAP;
203cbea78c6Skarels 		break;
20485e7c9a4Smckusick 	case T_MMUFLT:
20585e7c9a4Smckusick 		sigval = SIGSEGV;
20685e7c9a4Smckusick 		break;
20785e7c9a4Smckusick 	case T_SSIR:
20885e7c9a4Smckusick 		sigval = SIGSEGV;
20985e7c9a4Smckusick 		break;
21085e7c9a4Smckusick 	case T_FMTERR:
21185e7c9a4Smckusick 		sigval = SIGILL;
21285e7c9a4Smckusick 		break;
21385e7c9a4Smckusick 	case T_FPERR:
21485e7c9a4Smckusick 		sigval = SIGFPE;
21585e7c9a4Smckusick 		break;
21685e7c9a4Smckusick 	case T_COPERR:
21785e7c9a4Smckusick 		sigval = SIGFPE;
21885e7c9a4Smckusick 		break;
2195ecb2f06Shibler 	case T_ASTFLT:
22085e7c9a4Smckusick 		sigval = SIGINT;
22185e7c9a4Smckusick 		break;
22285e7c9a4Smckusick 	case T_TRAP15:
223cbea78c6Skarels 		sigval = SIGTRAP;
22485e7c9a4Smckusick 		break;
22585e7c9a4Smckusick 	default:
22685e7c9a4Smckusick 		sigval = SIGEMT;
22785e7c9a4Smckusick 		break;
22885e7c9a4Smckusick 	}
22985e7c9a4Smckusick 	return (sigval);
23085e7c9a4Smckusick }
23185e7c9a4Smckusick 
232cbea78c6Skarels /*
233e9322392Skarels  * Trap into kgdb to wait for debugger to connect,
234b6ace64eSkarels  * noting on the console why nothing else is going on.
235b6ace64eSkarels  */
kgdb_connect(verbose)236b6ace64eSkarels kgdb_connect(verbose)
237b6ace64eSkarels 	int verbose;
238b6ace64eSkarels {
239b6ace64eSkarels 
240b6ace64eSkarels 	if (verbose)
241b6ace64eSkarels 		printf("kgdb waiting...");
242b6ace64eSkarels 	/* trap into kgdb */
243b6ace64eSkarels 	asm("trap #15;");
244b6ace64eSkarels 	if (verbose)
245b6ace64eSkarels 		printf("connected.\n");
246b6ace64eSkarels }
247b6ace64eSkarels 
248b6ace64eSkarels /*
249b6ace64eSkarels  * Decide what to do on panic.
250b6ace64eSkarels  */
kgdb_panic()251b6ace64eSkarels kgdb_panic()
252b6ace64eSkarels {
253b6ace64eSkarels 
254aa5efb8eSkarels 	if (kgdb_active == 0 && kgdb_debug_panic && kgdb_dev != NODEV)
255b6ace64eSkarels 		kgdb_connect(1);
256b6ace64eSkarels }
257b6ace64eSkarels 
258b6ace64eSkarels /*
259cbea78c6Skarels  * Definitions exported from gdb.
260cbea78c6Skarels  */
261cbea78c6Skarels #define NUM_REGS 18
262cbea78c6Skarels #define REGISTER_BYTES ((16+2)*4)
263cbea78c6Skarels #define REGISTER_BYTE(N)  ((N)*4)
264cbea78c6Skarels 
265cbea78c6Skarels #define GDB_SR 16
266cbea78c6Skarels #define GDB_PC 17
267cbea78c6Skarels 
268b971627aSkarels static inline void
kgdb_copy(src,dst,nbytes)2697b3a453cSbostic kgdb_copy(src, dst, nbytes)
2707b3a453cSbostic 	register u_char *src, *dst;
2717b3a453cSbostic 	register u_int nbytes;
272cbea78c6Skarels {
273b971627aSkarels 	register u_char *ep = src + nbytes;
274b971627aSkarels 
275b971627aSkarels 	while (src < ep)
276b971627aSkarels 		*dst++ = *src++;
277cbea78c6Skarels }
278cbea78c6Skarels 
279d8882d00Shibler /*
280d8882d00Shibler  * There is a short pad word between SP (A7) and SR which keeps the
281d8882d00Shibler  * kernel stack long word aligned (note that this is in addition to
282d8882d00Shibler  * the stack adjust short that we treat as the upper half of a longword
283d8882d00Shibler  * SR).  We must skip this when copying into and out of gdb.
284d8882d00Shibler  */
285d8882d00Shibler static inline void
regs_to_gdb(fp,regs)2867b3a453cSbostic regs_to_gdb(fp, regs)
2877b3a453cSbostic 	struct frame *fp;
2887b3a453cSbostic 	u_long *regs;
289d8882d00Shibler {
290d8882d00Shibler 	kgdb_copy((u_char *)fp->f_regs, (u_char *)regs, 16*4);
291d8882d00Shibler 	kgdb_copy((u_char *)&fp->f_stackadj, (u_char *)&regs[GDB_SR], 2*4);
292d8882d00Shibler }
293b971627aSkarels 
294d8882d00Shibler static inline void
gdb_to_regs(fp,regs)2957b3a453cSbostic gdb_to_regs(fp, regs)
2967b3a453cSbostic 	struct frame *fp;
297827ebdecSbostic 	u_long *regs;
298d8882d00Shibler {
299d8882d00Shibler 	kgdb_copy((u_char *)regs, (u_char *)fp->f_regs, 16*4);
300d8882d00Shibler 	kgdb_copy((u_char *)&regs[GDB_SR], (u_char *)&fp->f_stackadj, 2*4);
301d8882d00Shibler }
302cbea78c6Skarels 
303cbea78c6Skarels static u_long reg_cache[NUM_REGS];
304c8c6fa19Smckusick static u_char inbuffer[SL_RPCSIZE+1];
305c8c6fa19Smckusick static u_char outbuffer[SL_RPCSIZE];
30685e7c9a4Smckusick 
30785e7c9a4Smckusick /*
30885e7c9a4Smckusick  * This function does all command procesing for interfacing to
30985e7c9a4Smckusick  * a remote gdb.
31085e7c9a4Smckusick  */
31185e7c9a4Smckusick int
kgdb_trap(type,frame)3127b3a453cSbostic kgdb_trap(type, frame)
3137b3a453cSbostic 	int type;
3147b3a453cSbostic 	struct frame *frame;
31585e7c9a4Smckusick {
316b971627aSkarels 	register u_long len;
317b971627aSkarels 	u_char *addr;
318b971627aSkarels 	register u_char *cp;
319b971627aSkarels 	register u_char out, in;
320b971627aSkarels 	register int outlen;
321b971627aSkarels 	int inlen;
322cbea78c6Skarels 	u_long gdb_regs[NUM_REGS];
32385e7c9a4Smckusick 
324*673a3eceShibler 	if ((int)kgdb_dev < 0) {
32585e7c9a4Smckusick 		/* not debugging */
32685e7c9a4Smckusick 		return (0);
327cbea78c6Skarels 	}
328cbea78c6Skarels 	if (kgdb_active == 0) {
329cbea78c6Skarels 		if (type != T_TRAP15) {
330cbea78c6Skarels 			/* No debugger active -- let trap handle this. */
331cbea78c6Skarels 			return (0);
332cbea78c6Skarels 		}
333b6ace64eSkarels 		kgdb_getc = 0;
334b6ace64eSkarels 		for (inlen = 0; constab[inlen].cn_probe; inlen++)
335b6ace64eSkarels 		    if (major(constab[inlen].cn_dev) == major(kgdb_dev)) {
336b6ace64eSkarels 			kgdb_getc = constab[inlen].cn_getc;
337b6ace64eSkarels 			kgdb_putc = constab[inlen].cn_putc;
338b6ace64eSkarels 			break;
339b6ace64eSkarels 		}
340b971627aSkarels 		if (kgdb_getc == 0 || kgdb_putc == 0)
341cbea78c6Skarels 			return (0);
342b971627aSkarels 		/*
343e9322392Skarels 		 * If the packet that woke us up isn't an exec packet,
344b971627aSkarels 		 * ignore it since there is no active debugger.  Also,
345b971627aSkarels 		 * we check that it's not an ack to be sure that the
346b971627aSkarels 		 * remote side doesn't send back a response after the
347b971627aSkarels 		 * local gdb has exited.  Otherwise, the local host
348b971627aSkarels 		 * could trap into gdb if it's running a gdb kernel too.
349b971627aSkarels 		 */
350b971627aSkarels 		in = GETC;
351e9322392Skarels 		/*
352e9322392Skarels 		 * If we came in asynchronously through the serial line,
353e9322392Skarels 		 * the framing character is eaten by the receive interrupt,
354e9322392Skarels 		 * but if we come in through a synchronous trap (i.e., via
355e9322392Skarels 		 * kgdb_connect()), we will see the extra character.
356e9322392Skarels 		 */
357c8c6fa19Smckusick 		if (in == FRAME_START)
358e9322392Skarels 			in = GETC;
359e9322392Skarels 
360c8c6fa19Smckusick 		/*
361c8c6fa19Smckusick 		 * Check that this is a debugger exec message.  If so,
362c8c6fa19Smckusick 		 * slurp up the entire message then ack it, and fall
363c8c6fa19Smckusick 		 * through to the recv loop.
364c8c6fa19Smckusick 		 */
365e9322392Skarels 		if (KGDB_CMD(in) != KGDB_EXEC || (in & KGDB_ACK) != 0)
366b971627aSkarels 			return (0);
367b971627aSkarels 		while (GETC != FRAME_END)
368b971627aSkarels 			;
369e9322392Skarels 		/*
370e9322392Skarels 		 * Do the printf *before* we ack the message.  This way
371e9322392Skarels 		 * we won't drop any inbound characters while we're
372e9322392Skarels 		 * doing the polling printf.
373e9322392Skarels 		 */
374e9322392Skarels 		printf("kgdb started from device %x\n", kgdb_dev);
375e9322392Skarels 		kgdb_send(in | KGDB_ACK, (u_char *)0, 0);
376cbea78c6Skarels 		kgdb_active = 1;
377cbea78c6Skarels 	}
378cbea78c6Skarels 	/*
379cbea78c6Skarels 	 * Stick frame regs into our reg cache then tell remote host
380cbea78c6Skarels 	 * that an exception has occured.
381cbea78c6Skarels 	 */
382cbea78c6Skarels 	regs_to_gdb(frame, gdb_regs);
383e9322392Skarels 	if (type != T_TRAP15) {
384e9322392Skarels 		/*
385e9322392Skarels 		 * Only send an asynchronous SIGNAL message when we hit
386e9322392Skarels 		 * a breakpoint.  Otherwise, we will drop the incoming
387e9322392Skarels 		 * packet while we output this one (and on entry the other
388e9322392Skarels 		 * side isn't interested in the SIGNAL type -- if it is,
389e9322392Skarels 		 * it will have used a signal packet.)
390e9322392Skarels 		 */
391cbea78c6Skarels 		outbuffer[0] = computeSignal(type);
392cbea78c6Skarels 		kgdb_send(KGDB_SIGNAL, outbuffer, 1);
393e9322392Skarels 	}
39485e7c9a4Smckusick 
39585e7c9a4Smckusick 	while (1) {
396cbea78c6Skarels 		in = kgdb_recv(inbuffer, &inlen);
397cbea78c6Skarels 		if (in == 0 || (in & KGDB_ACK))
398cbea78c6Skarels 			/* Ignore inbound acks and error conditions. */
399cbea78c6Skarels 			continue;
400cbea78c6Skarels 
401cbea78c6Skarels 		out = in | KGDB_ACK;
402b971627aSkarels 		switch (KGDB_CMD(in)) {
403cbea78c6Skarels 
404cbea78c6Skarels 		case KGDB_SIGNAL:
405b971627aSkarels 			/*
406b971627aSkarels 			 * if this command came from a running gdb,
407b971627aSkarels 			 * answer it -- the other guy has no way of
408b971627aSkarels 			 * knowing if we're in or out of this loop
409b971627aSkarels 			 * when he issues a "remote-signal".  (Note
410b971627aSkarels 			 * that without the length check, we could
411b971627aSkarels 			 * loop here forever if the ourput line is
412b971627aSkarels 			 * looped back or the remote host is echoing.)
413b971627aSkarels 			 */
414b971627aSkarels 			if (inlen == 0) {
415cbea78c6Skarels 				outbuffer[0] = computeSignal(type);
416b971627aSkarels 				kgdb_send(KGDB_SIGNAL, outbuffer, 1);
417b971627aSkarels 			}
418b971627aSkarels 			continue;
419cbea78c6Skarels 
420cbea78c6Skarels 		case KGDB_REG_R:
421cbea78c6Skarels 		case KGDB_REG_R | KGDB_DELTA:
422cbea78c6Skarels 			cp = outbuffer;
423cbea78c6Skarels 			outlen = 0;
424b971627aSkarels 			for (len = inbuffer[0]; len < NUM_REGS; ++len) {
425b971627aSkarels 				if (reg_cache[len] != gdb_regs[len] ||
426cbea78c6Skarels 				    (in & KGDB_DELTA) == 0) {
427c8c6fa19Smckusick 					if (outlen + 5 > SL_MAXDATA) {
428cbea78c6Skarels 						out |= KGDB_MORE;
429cbea78c6Skarels 						break;
430cbea78c6Skarels 					}
431b971627aSkarels 					cp[outlen] = len;
432b971627aSkarels 					kgdb_copy((u_char *)&gdb_regs[len],
433cbea78c6Skarels 						  &cp[outlen + 1], 4);
434b971627aSkarels 					reg_cache[len] = gdb_regs[len];
435cbea78c6Skarels 					outlen += 5;
436cbea78c6Skarels 				}
437cbea78c6Skarels 			}
438cbea78c6Skarels 			break;
439cbea78c6Skarels 
440cbea78c6Skarels 		case KGDB_REG_W:
441cbea78c6Skarels 		case KGDB_REG_W | KGDB_DELTA:
442cbea78c6Skarels 			cp = inbuffer;
443b971627aSkarels 			for (len = 0; len < inlen; len += 5) {
444b971627aSkarels 				register int j = cp[len];
445cbea78c6Skarels 
446b971627aSkarels 				kgdb_copy(&cp[len + 1],
447b971627aSkarels 					  (u_char *)&gdb_regs[j], 4);
448cbea78c6Skarels 				reg_cache[j] = gdb_regs[j];
449cbea78c6Skarels 			}
450cbea78c6Skarels 			gdb_to_regs(frame, gdb_regs);
451cbea78c6Skarels 			outlen = 0;
452cbea78c6Skarels 			break;
453cbea78c6Skarels 
454cbea78c6Skarels 		case KGDB_MEM_R:
455b971627aSkarels 			len = inbuffer[0];
456b971627aSkarels 			kgdb_copy(&inbuffer[1], (u_char *)&addr, 4);
457c8c6fa19Smckusick 			if (len > SL_MAXDATA) {
458cbea78c6Skarels 				outlen = 1;
459cbea78c6Skarels 				outbuffer[0] = E2BIG;
460b971627aSkarels 			} else if (!kgdb_acc(addr, len, B_READ)) {
461cbea78c6Skarels 				outlen = 1;
462cbea78c6Skarels 				outbuffer[0] = EFAULT;
463cbea78c6Skarels 			} else {
464b971627aSkarels 				outlen = len + 1;
46585e7c9a4Smckusick 				outbuffer[0] = 0;
466b971627aSkarels 				kgdb_copy(addr, &outbuffer[1], len);
467cbea78c6Skarels 			}
46885e7c9a4Smckusick 			break;
469cbea78c6Skarels 
470cbea78c6Skarels 		case KGDB_MEM_W:
471b971627aSkarels 			len = inlen - 4;
472b971627aSkarels 			kgdb_copy(inbuffer, (u_char *)&addr, 4);
473cbea78c6Skarels 			outlen = 1;
474b971627aSkarels 			if (!kgdb_acc(addr, len, B_READ))
475cbea78c6Skarels 				outbuffer[0] = EFAULT;
47685e7c9a4Smckusick 			else {
477cbea78c6Skarels 				outbuffer[0] = 0;
478b971627aSkarels 				if (!kgdb_acc(addr, len, B_WRITE))
479b971627aSkarels 					chgkprot(addr, len, B_WRITE);
480b971627aSkarels 				kgdb_copy(&inbuffer[4], addr, len);
4815cee6874Smckusick 				ICIA();
482cbea78c6Skarels 			}
48385e7c9a4Smckusick 			break;
48485e7c9a4Smckusick 
485cbea78c6Skarels 		case KGDB_KILL:
486cbea78c6Skarels 			kgdb_active = 0;
487e9322392Skarels 			printf("kgdb detached\n");
488cbea78c6Skarels 			/* fall through */
489cbea78c6Skarels 		case KGDB_CONT:
490cbea78c6Skarels 			kgdb_send(out, 0, 0);
49185e7c9a4Smckusick 			frame->f_sr &=~ PSL_T;
49285e7c9a4Smckusick 			return (1);
49385e7c9a4Smckusick 
494cbea78c6Skarels 		case KGDB_STEP:
495cbea78c6Skarels 			kgdb_send(out, 0, 0);
496cbea78c6Skarels 			frame->f_sr |= PSL_T;
49785e7c9a4Smckusick 			return (1);
498cbea78c6Skarels 
499e9322392Skarels 		case KGDB_EXEC:
500cbea78c6Skarels 		default:
501cbea78c6Skarels 			/* Unknown command.  Ack with a null message. */
502cbea78c6Skarels 			outlen = 0;
503cbea78c6Skarels 			break;
50485e7c9a4Smckusick 		}
505cbea78c6Skarels 		/* Send the reply */
506cbea78c6Skarels 		kgdb_send(out, outbuffer, outlen);
50785e7c9a4Smckusick 	}
50885e7c9a4Smckusick }
509b971627aSkarels 
510b971627aSkarels /*
511b971627aSkarels  * XXX do kernacc call if safe, otherwise attempt
512b971627aSkarels  * to simulate by simple bounds-checking.
513b971627aSkarels  */
kgdb_acc(addr,len,rw)514b971627aSkarels kgdb_acc(addr, len, rw)
515b971627aSkarels 	caddr_t addr;
5167b3a453cSbostic 	int len, rw;
517b971627aSkarels {
518dca83bf2Skarels 	extern char proc0paddr[], kstack[];	/* XXX */
519b971627aSkarels 	extern char *kernel_map;		/* XXX! */
520b971627aSkarels 
521b971627aSkarels 	if (kernel_map != NULL)
522b971627aSkarels 		return (kernacc(addr, len, rw));
523b971627aSkarels 	if (addr < proc0paddr + UPAGES * NBPG  ||
524dca83bf2Skarels 	    kstack <= addr && addr < kstack + UPAGES * NBPG)
525b971627aSkarels 		return (1);
526b971627aSkarels 	return (0);
527b971627aSkarels }
5287b3a453cSbostic #endif /* KGDB */
529