xref: /csrg-svn/sys/hp300/hp300/kgdb_stub.c (revision 56508)
141475Smckusick /*
247211Skarels  * Copyright (c) 1990 Regents of the University of California.
341475Smckusick  * All rights reserved.
441475Smckusick  *
555673Smckusick  * This code is derived from software contributed to Berkeley by
655673Smckusick  * Van Jacobson and Steven McCanne of Lawrence Berkeley Laboratory.
755673Smckusick  *
841475Smckusick  * %sccs.include.redist.c%
941475Smckusick  *
10*56508Sbostic  *	@(#)kgdb_stub.c	7.14 (Berkeley) 10/11/92
1141475Smckusick  */
1255673Smckusick 
1341475Smckusick /*
1447211Skarels  * "Stub" to allow remote cpu to debug over a serial line using gdb.
1547211Skarels  */
1641475Smckusick #ifdef KGDB
1747211Skarels #ifndef lint
1855673Smckusick static char rcsid[] = "$Header: kgdb_stub.c,v 1.2 92/07/23 19:37:50 mccanne Exp $";
1947211Skarels #endif
2041475Smckusick 
21*56508Sbostic #include <sys/param.h>
22*56508Sbostic #include <sys/systm.h>
2347211Skarels 
24*56508Sbostic #include <machine/trap.h>
25*56508Sbostic #include <machine/cpu.h>
26*56508Sbostic #include <machine/psl.h>
27*56508Sbostic #include <machine/reg.h>
28*56508Sbostic #include <machine/frame.h>
2947211Skarels 
30*56508Sbostic #include <sys/buf.h>
31*56508Sbostic #include <hp/dev/cons.h>
32*56508Sbostic 
33*56508Sbostic #include <hp300/hp300/kgdb_proto.h>
34*56508Sbostic #include <machine/remote-sl.h>
35*56508Sbostic 
3641475Smckusick extern int kernacc();
3741475Smckusick extern void chgkprot();
3841475Smckusick 
3942367Smckusick #ifndef KGDBDEV
4050225Skarels #define KGDBDEV NODEV
4142367Smckusick #endif
4242367Smckusick #ifndef KGDBRATE
4342367Smckusick #define KGDBRATE 9600
4442367Smckusick #endif
4542367Smckusick 
4650225Skarels dev_t kgdb_dev = KGDBDEV;	/* remote debugging device (NODEV if none) */
4742367Smckusick int kgdb_rate = KGDBRATE;	/* remote debugging baud rate */
4847211Skarels int kgdb_active = 0;            /* remote debugging active if != 0 */
4941475Smckusick int kgdb_debug_init = 0;	/* != 0 waits for remote at system init */
5047471Skarels int kgdb_debug_panic = 1;	/* != 0 waits for remote on panic */
5147211Skarels int kgdb_debug = 0;
5241475Smckusick 
5347211Skarels #define GETC	((*kgdb_getc)(kgdb_dev))
5447211Skarels #define PUTC(c)	((*kgdb_putc)(kgdb_dev, c))
5547211Skarels #define PUTESC(c) { \
5647211Skarels 	if (c == FRAME_END) { \
5747211Skarels 		PUTC(FRAME_ESCAPE); \
5847211Skarels 		c = TRANS_FRAME_END; \
5947211Skarels 	} else if (c == FRAME_ESCAPE) { \
6047211Skarels 		PUTC(FRAME_ESCAPE); \
6147211Skarels 		c = TRANS_FRAME_ESCAPE; \
6255673Smckusick 	} else if (c == FRAME_START) { \
6355673Smckusick 		PUTC(FRAME_ESCAPE); \
6455673Smckusick 		c = TRANS_FRAME_START; \
6547211Skarels 	} \
6647211Skarels 	PUTC(c); \
6742367Smckusick }
6847211Skarels static int (*kgdb_getc)();
6947211Skarels static int (*kgdb_putc)();
7041475Smckusick 
7141475Smckusick /*
7247211Skarels  * Send a message.  The host gets one chance to read it.
7341475Smckusick  */
7447211Skarels static void
7547211Skarels kgdb_send(type, bp, len)
7647211Skarels 	register u_char type;
7747211Skarels 	register u_char *bp;
7847211Skarels 	register int len;
7941475Smckusick {
8047211Skarels 	register u_char csum;
8147211Skarels 	register u_char *ep = bp + len;
8241475Smckusick 
8355673Smckusick 	PUTC(FRAME_START);
8455673Smckusick 	PUTESC(type);
8555673Smckusick 
8647211Skarels 	csum = type;
8747211Skarels 	while (bp < ep) {
8847211Skarels 		type = *bp++;
8947211Skarels 		csum += type;
9047211Skarels 		PUTESC(type)
9147211Skarels 	}
9247211Skarels 	csum = -csum;
9347211Skarels 	PUTESC(csum)
9447211Skarels 	PUTC(FRAME_END);
9541475Smckusick }
9641475Smckusick 
9747211Skarels static int
9847211Skarels kgdb_recv(bp, lenp)
9947211Skarels 	u_char *bp;
10047211Skarels 	int *lenp;
10141475Smckusick {
10247211Skarels 	register u_char c, csum;
10347211Skarels 	register int escape, len;
10447211Skarels 	register int type;
10541475Smckusick 
10655673Smckusick restart:
10747211Skarels 	csum = len = escape = 0;
10847211Skarels 	type = -1;
10947211Skarels 	while (1) {
11047211Skarels 		c = GETC;
11147211Skarels 		switch (c) {
11241475Smckusick 
11347211Skarels 		case FRAME_ESCAPE:
11447211Skarels 			escape = 1;
11547211Skarels 			continue;
11641475Smckusick 
11747211Skarels 		case TRANS_FRAME_ESCAPE:
11847211Skarels 			if (escape)
11947211Skarels 				c = FRAME_ESCAPE;
12047211Skarels 			break;
12141475Smckusick 
12247211Skarels 		case TRANS_FRAME_END:
12347211Skarels 			if (escape)
12447211Skarels 				c = FRAME_END;
12541475Smckusick 			break;
12641475Smckusick 
12755673Smckusick 		case TRANS_FRAME_START:
12855673Smckusick 			if (escape)
12955673Smckusick 				c = FRAME_START;
13055673Smckusick 			break;
13155673Smckusick 
13255673Smckusick 		case FRAME_START:
13355673Smckusick 			goto restart;
13455673Smckusick 
13547211Skarels 		case FRAME_END:
13647211Skarels 			if (type < 0 || --len < 0) {
13747211Skarels 				csum = len = escape = 0;
13847211Skarels 				type = -1;
13947211Skarels 				continue;
14047211Skarels 			}
14147211Skarels 			if (csum != 0) {
14247211Skarels 				return (0);
14347211Skarels 			}
14447211Skarels 			*lenp = len;
14547211Skarels 			return type;
14641475Smckusick 		}
14747211Skarels 		csum += c;
14847211Skarels 		if (type < 0) {
14947211Skarels 			type = c;
15047211Skarels 			escape = 0;
15147211Skarels 			continue;
15241475Smckusick 		}
15355673Smckusick 		if (++len > SL_RPCSIZE) {
15447211Skarels 			while (GETC != FRAME_END)
15547211Skarels 				;
15647211Skarels 			return (0);
15747211Skarels 		}
15847211Skarels 		*bp++ = c;
15947211Skarels 		escape = 0;
16041475Smckusick 	}
16141475Smckusick }
16241475Smckusick 
16341475Smckusick /*
16441475Smckusick  * Translate a trap number into a unix compatible signal value.
16541475Smckusick  * (gdb only understands unix signal numbers).
16641475Smckusick  */
16741475Smckusick static int
16847211Skarels computeSignal(type)
16947211Skarels 	int type;
17041475Smckusick {
17141475Smckusick 	int sigval;
17241475Smckusick 
17347262Skarels 	switch (type) {
17441475Smckusick 	case T_BUSERR:
17541475Smckusick 		sigval = SIGBUS;
17647211Skarels 		break;
17741475Smckusick 	case T_ADDRERR:
17841475Smckusick 		sigval = SIGBUS;
17947211Skarels 		break;
18041475Smckusick 	case T_ILLINST:
18141475Smckusick 		sigval = SIGILL;
18247211Skarels 		break;
18341475Smckusick 	case T_ZERODIV:
18441475Smckusick 		sigval = SIGFPE;
18547211Skarels 		break;
18641475Smckusick 	case T_CHKINST:
18741475Smckusick 		sigval = SIGFPE;
18847211Skarels 		break;
18941475Smckusick 	case T_TRAPVINST:
19041475Smckusick 		sigval = SIGFPE;
19147211Skarels 		break;
19241475Smckusick 	case T_PRIVINST:
19341475Smckusick 		sigval = SIGILL;
19447211Skarels 		break;
19541475Smckusick 	case T_TRACE:
19641475Smckusick 		sigval = SIGTRAP;
19747211Skarels 		break;
19841475Smckusick 	case T_MMUFLT:
19941475Smckusick 		sigval = SIGSEGV;
20041475Smckusick 		break;
20141475Smckusick 	case T_SSIR:
20241475Smckusick 		sigval = SIGSEGV;
20341475Smckusick 		break;
20441475Smckusick 	case T_FMTERR:
20541475Smckusick 		sigval = SIGILL;
20641475Smckusick 		break;
20741475Smckusick 	case T_FPERR:
20841475Smckusick 		sigval = SIGFPE;
20941475Smckusick 		break;
21041475Smckusick 	case T_COPERR:
21141475Smckusick 		sigval = SIGFPE;
21241475Smckusick 		break;
21343413Shibler 	case T_ASTFLT:
21441475Smckusick 		sigval = SIGINT;
21541475Smckusick 		break;
21641475Smckusick 	case T_TRAP15:
21747211Skarels 		sigval = SIGTRAP;
21841475Smckusick 		break;
21941475Smckusick 	default:
22041475Smckusick 		sigval = SIGEMT;
22141475Smckusick 		break;
22241475Smckusick 	}
22341475Smckusick 	return (sigval);
22441475Smckusick }
22541475Smckusick 
22647211Skarels /*
22748473Skarels  * Trap into kgdb to wait for debugger to connect,
22847471Skarels  * noting on the console why nothing else is going on.
22947471Skarels  */
23047471Skarels kgdb_connect(verbose)
23147471Skarels 	int verbose;
23247471Skarels {
23347471Skarels 
23447471Skarels 	if (verbose)
23547471Skarels 		printf("kgdb waiting...");
23647471Skarels 	/* trap into kgdb */
23747471Skarels 	asm("trap #15;");
23847471Skarels 	if (verbose)
23947471Skarels 		printf("connected.\n");
24047471Skarels }
24147471Skarels 
24247471Skarels /*
24347471Skarels  * Decide what to do on panic.
24447471Skarels  */
24547471Skarels kgdb_panic()
24647471Skarels {
24747471Skarels 
24850225Skarels 	if (kgdb_active == 0 && kgdb_debug_panic && kgdb_dev != NODEV)
24947471Skarels 		kgdb_connect(1);
25047471Skarels }
25147471Skarels 
25247471Skarels /*
25347211Skarels  * Definitions exported from gdb.
25447211Skarels  */
25547211Skarels #define NUM_REGS 18
25647211Skarels #define REGISTER_BYTES ((16+2)*4)
25747211Skarels #define REGISTER_BYTE(N)  ((N)*4)
25841475Smckusick 
25947211Skarels #define GDB_SR 16
26047211Skarels #define GDB_PC 17
26147211Skarels 
26247262Skarels static inline void
26347262Skarels kgdb_copy(register u_char *src, register u_char *dst, register u_int nbytes)
26447211Skarels {
26547262Skarels 	register u_char *ep = src + nbytes;
26647211Skarels 
26747262Skarels 	while (src < ep)
26847262Skarels 		*dst++ = *src++;
26947211Skarels }
27047211Skarels 
27147262Skarels #define regs_to_gdb(fp, regs) \
27247262Skarels 	(kgdb_copy((u_char *)((fp)->f_regs), (u_char *)(regs), REGISTER_BYTES))
27347262Skarels 
27447262Skarels #define gdb_to_regs(fp, regs) \
27547262Skarels 	(kgdb_copy((u_char *)(regs), (u_char *)((fp)->f_regs), REGISTER_BYTES))
27647262Skarels 
27747211Skarels static u_long reg_cache[NUM_REGS];
27855673Smckusick static u_char inbuffer[SL_RPCSIZE+1];
27955673Smckusick static u_char outbuffer[SL_RPCSIZE];
28047211Skarels 
28147211Skarels /*
28241475Smckusick  * This function does all command procesing for interfacing to
28341475Smckusick  * a remote gdb.
28441475Smckusick  */
28541475Smckusick int
28647262Skarels kgdb_trap(int type, struct frame *frame)
28741475Smckusick {
28847262Skarels 	register u_long len;
28947262Skarels 	u_char *addr;
29047262Skarels 	register u_char *cp;
29147262Skarels 	register u_char out, in;
29247262Skarels 	register int outlen;
29347262Skarels 	int inlen;
29447211Skarels 	u_long gdb_regs[NUM_REGS];
29541475Smckusick 
29647211Skarels 	if (kgdb_dev < 0) {
29741475Smckusick 		/* not debugging */
29841475Smckusick 		return (0);
29947211Skarels 	}
30047211Skarels 	if (kgdb_active == 0) {
30147211Skarels 		if (type != T_TRAP15) {
30247211Skarels 			/* No debugger active -- let trap handle this. */
30347211Skarels 			return (0);
30447211Skarels 		}
30547471Skarels 		kgdb_getc = 0;
30647471Skarels 		for (inlen = 0; constab[inlen].cn_probe; inlen++)
30747471Skarels 		    if (major(constab[inlen].cn_dev) == major(kgdb_dev)) {
30847471Skarels 			kgdb_getc = constab[inlen].cn_getc;
30947471Skarels 			kgdb_putc = constab[inlen].cn_putc;
31047471Skarels 			break;
31147471Skarels 		}
31247262Skarels 		if (kgdb_getc == 0 || kgdb_putc == 0)
31347211Skarels 			return (0);
31447262Skarels 		/*
31548473Skarels 		 * If the packet that woke us up isn't an exec packet,
31647262Skarels 		 * ignore it since there is no active debugger.  Also,
31747262Skarels 		 * we check that it's not an ack to be sure that the
31847262Skarels 		 * remote side doesn't send back a response after the
31947262Skarels 		 * local gdb has exited.  Otherwise, the local host
32047262Skarels 		 * could trap into gdb if it's running a gdb kernel too.
32147262Skarels 		 */
32247262Skarels 		in = GETC;
32348473Skarels 		/*
32448473Skarels 		 * If we came in asynchronously through the serial line,
32548473Skarels 		 * the framing character is eaten by the receive interrupt,
32648473Skarels 		 * but if we come in through a synchronous trap (i.e., via
32748473Skarels 		 * kgdb_connect()), we will see the extra character.
32848473Skarels 		 */
32955673Smckusick 		if (in == FRAME_START)
33048473Skarels 			in = GETC;
33148473Skarels 
33255673Smckusick 		/*
33355673Smckusick 		 * Check that this is a debugger exec message.  If so,
33455673Smckusick 		 * slurp up the entire message then ack it, and fall
33555673Smckusick 		 * through to the recv loop.
33655673Smckusick 		 */
33748473Skarels 		if (KGDB_CMD(in) != KGDB_EXEC || (in & KGDB_ACK) != 0)
33847262Skarels 			return (0);
33947262Skarels 		while (GETC != FRAME_END)
34047262Skarels 			;
34148473Skarels 		/*
34248473Skarels 		 * Do the printf *before* we ack the message.  This way
34348473Skarels 		 * we won't drop any inbound characters while we're
34448473Skarels 		 * doing the polling printf.
34548473Skarels 		 */
34648473Skarels 		printf("kgdb started from device %x\n", kgdb_dev);
34748473Skarels 		kgdb_send(in | KGDB_ACK, (u_char *)0, 0);
34847211Skarels 		kgdb_active = 1;
34947211Skarels 	}
35047211Skarels 	/*
35147211Skarels 	 * Stick frame regs into our reg cache then tell remote host
35247211Skarels 	 * that an exception has occured.
35347211Skarels 	 */
35447211Skarels 	regs_to_gdb(frame, gdb_regs);
35548473Skarels 	if (type != T_TRAP15) {
35648473Skarels 		/*
35748473Skarels 		 * Only send an asynchronous SIGNAL message when we hit
35848473Skarels 		 * a breakpoint.  Otherwise, we will drop the incoming
35948473Skarels 		 * packet while we output this one (and on entry the other
36048473Skarels 		 * side isn't interested in the SIGNAL type -- if it is,
36148473Skarels 		 * it will have used a signal packet.)
36248473Skarels 		 */
36348473Skarels 		outbuffer[0] = computeSignal(type);
36448473Skarels 		kgdb_send(KGDB_SIGNAL, outbuffer, 1);
36548473Skarels 	}
36641475Smckusick 
36747211Skarels 	while (1) {
36847211Skarels 		in = kgdb_recv(inbuffer, &inlen);
36947211Skarels 		if (in == 0 || (in & KGDB_ACK))
37047211Skarels 			/* Ignore inbound acks and error conditions. */
37147211Skarels 			continue;
37241475Smckusick 
37347211Skarels 		out = in | KGDB_ACK;
37447262Skarels 		switch (KGDB_CMD(in)) {
37547211Skarels 
37647211Skarels 		case KGDB_SIGNAL:
37747262Skarels 			/*
37847262Skarels 			 * if this command came from a running gdb,
37947262Skarels 			 * answer it -- the other guy has no way of
38047262Skarels 			 * knowing if we're in or out of this loop
38147262Skarels 			 * when he issues a "remote-signal".  (Note
38247262Skarels 			 * that without the length check, we could
38347262Skarels 			 * loop here forever if the ourput line is
38447262Skarels 			 * looped back or the remote host is echoing.)
38547262Skarels 			 */
38647262Skarels 			if (inlen == 0) {
38747262Skarels 				outbuffer[0] = computeSignal(type);
38847262Skarels 				kgdb_send(KGDB_SIGNAL, outbuffer, 1);
38947262Skarels 			}
39047262Skarels 			continue;
39147211Skarels 
39247211Skarels 		case KGDB_REG_R:
39347211Skarels 		case KGDB_REG_R | KGDB_DELTA:
39447211Skarels 			cp = outbuffer;
39547211Skarels 			outlen = 0;
39647262Skarels 			for (len = inbuffer[0]; len < NUM_REGS; ++len) {
39747262Skarels 				if (reg_cache[len] != gdb_regs[len] ||
39847211Skarels 				    (in & KGDB_DELTA) == 0) {
39955673Smckusick 					if (outlen + 5 > SL_MAXDATA) {
40047211Skarels 						out |= KGDB_MORE;
40147211Skarels 						break;
40247211Skarels 					}
40347262Skarels 					cp[outlen] = len;
40447262Skarels 					kgdb_copy((u_char *)&gdb_regs[len],
40547262Skarels 						  &cp[outlen + 1], 4);
40647262Skarels 					reg_cache[len] = gdb_regs[len];
40747211Skarels 					outlen += 5;
40847211Skarels 				}
40941475Smckusick 			}
41041475Smckusick 			break;
41147211Skarels 
41247211Skarels 		case KGDB_REG_W:
41347211Skarels 		case KGDB_REG_W | KGDB_DELTA:
41447211Skarels 			cp = inbuffer;
41547262Skarels 			for (len = 0; len < inlen; len += 5) {
41647262Skarels 				register int j = cp[len];
41741475Smckusick 
41847262Skarels 				kgdb_copy(&cp[len + 1],
41947262Skarels 					  (u_char *)&gdb_regs[j], 4);
42047211Skarels 				reg_cache[j] = gdb_regs[j];
42141475Smckusick 			}
42247211Skarels 			gdb_to_regs(frame, gdb_regs);
42347211Skarels 			outlen = 0;
42447211Skarels 			break;
42547211Skarels 
42647211Skarels 		case KGDB_MEM_R:
42747262Skarels 			len = inbuffer[0];
42847262Skarels 			kgdb_copy(&inbuffer[1], (u_char *)&addr, 4);
42955673Smckusick 			if (len > SL_MAXDATA) {
43047211Skarels 				outlen = 1;
43147211Skarels 				outbuffer[0] = E2BIG;
43247262Skarels 			} else if (!kgdb_acc(addr, len, B_READ)) {
43347211Skarels 				outlen = 1;
43447211Skarels 				outbuffer[0] = EFAULT;
43547211Skarels 			} else {
43647262Skarels 				outlen = len + 1;
43747211Skarels 				outbuffer[0] = 0;
43847262Skarels 				kgdb_copy(addr, &outbuffer[1], len);
43941475Smckusick 			}
44041475Smckusick 			break;
44141475Smckusick 
44247211Skarels 		case KGDB_MEM_W:
44347262Skarels 			len = inlen - 4;
44447262Skarels 			kgdb_copy(inbuffer, (u_char *)&addr, 4);
44547211Skarels 			outlen = 1;
44647262Skarels 			if (!kgdb_acc(addr, len, B_READ))
44747211Skarels 				outbuffer[0] = EFAULT;
44847211Skarels 			else {
44947211Skarels 				outbuffer[0] = 0;
45047262Skarels 				if (!kgdb_acc(addr, len, B_WRITE))
45147262Skarels 					chgkprot(addr, len, B_WRITE);
45247262Skarels 				kgdb_copy(&inbuffer[4], addr, len);
45354245Smckusick 				ICIA();
45441475Smckusick 			}
45541475Smckusick 			break;
45641475Smckusick 
45747211Skarels 		case KGDB_KILL:
45847211Skarels 			kgdb_active = 0;
45948473Skarels 			printf("kgdb detached\n");
46047211Skarels 			/* fall through */
46147211Skarels 		case KGDB_CONT:
46247211Skarels 			kgdb_send(out, 0, 0);
46347211Skarels 			frame->f_sr &=~ PSL_T;
46447211Skarels 			return (1);
46541475Smckusick 
46647211Skarels 		case KGDB_STEP:
46747211Skarels 			kgdb_send(out, 0, 0);
46847211Skarels 			frame->f_sr |= PSL_T;
46941475Smckusick 			return (1);
47041475Smckusick 
47148473Skarels 		case KGDB_EXEC:
47247211Skarels 		default:
47347211Skarels 			/* Unknown command.  Ack with a null message. */
47447211Skarels 			outlen = 0;
47547211Skarels 			break;
47641475Smckusick 		}
47747211Skarels 		/* Send the reply */
47847211Skarels 		kgdb_send(out, outbuffer, outlen);
47941475Smckusick 	}
48041475Smckusick }
48147262Skarels 
48247262Skarels /*
48347262Skarels  * XXX do kernacc call if safe, otherwise attempt
48447262Skarels  * to simulate by simple bounds-checking.
48547262Skarels  */
48647262Skarels kgdb_acc(addr, len, rw)
48747262Skarels 	caddr_t addr;
48847262Skarels {
48949119Skarels 	extern char proc0paddr[], kstack[];	/* XXX */
49047262Skarels 	extern char *kernel_map;		/* XXX! */
49147262Skarels 
49247262Skarels 	if (kernel_map != NULL)
49347262Skarels 		return (kernacc(addr, len, rw));
49447262Skarels 	if (addr < proc0paddr + UPAGES * NBPG  ||
49549119Skarels 	    kstack <= addr && addr < kstack + UPAGES * NBPG)
49647262Skarels 		return (1);
49747262Skarels 	return (0);
49847262Skarels }
49941475Smckusick #endif
500