xref: /csrg-svn/sys/hp300/hp300/kgdb_stub.c (revision 54245)
141475Smckusick /*
247211Skarels  * Copyright (c) 1990 Regents of the University of California.
341475Smckusick  * All rights reserved.
441475Smckusick  *
541475Smckusick  * %sccs.include.redist.c%
641475Smckusick  *
7*54245Smckusick  *	@(#)kgdb_stub.c	7.12 (Berkeley) 06/22/92
841475Smckusick  */
941475Smckusick /*
1047211Skarels  * "Stub" to allow remote cpu to debug over a serial line using gdb.
1147211Skarels  */
1241475Smckusick #ifdef KGDB
1347211Skarels #ifndef lint
1448473Skarels static char rcsid[] = "$Header: kgdb_stub.c,v 1.13 91/03/23 13:55:57 mccanne Exp $";
1547211Skarels #endif
1641475Smckusick 
1747211Skarels #include "param.h"
1847211Skarels #include "systm.h"
1948473Skarels #include "../include/trap.h"
2048473Skarels #include "../include/cpu.h"
2148473Skarels #include "../include/psl.h"
2248473Skarels #include "../include/reg.h"
2348473Skarels #include "../include/frame.h"
2447211Skarels #include "buf.h"
2553933Shibler #include "hp/dev/cons.h"
2647211Skarels 
2747211Skarels #include "kgdb_proto.h"
2847211Skarels #include "machine/remote-sl.h"
2947211Skarels 
3041475Smckusick extern int kernacc();
3141475Smckusick extern void chgkprot();
3241475Smckusick 
3342367Smckusick #ifndef KGDBDEV
3450225Skarels #define KGDBDEV NODEV
3542367Smckusick #endif
3642367Smckusick #ifndef KGDBRATE
3742367Smckusick #define KGDBRATE 9600
3842367Smckusick #endif
3942367Smckusick 
4050225Skarels dev_t kgdb_dev = KGDBDEV;	/* remote debugging device (NODEV if none) */
4142367Smckusick int kgdb_rate = KGDBRATE;	/* remote debugging baud rate */
4247211Skarels int kgdb_active = 0;            /* remote debugging active if != 0 */
4341475Smckusick int kgdb_debug_init = 0;	/* != 0 waits for remote at system init */
4447471Skarels int kgdb_debug_panic = 1;	/* != 0 waits for remote on panic */
4547211Skarels int kgdb_debug = 0;
4641475Smckusick 
4747211Skarels #define GETC	((*kgdb_getc)(kgdb_dev))
4847211Skarels #define PUTC(c)	((*kgdb_putc)(kgdb_dev, c))
4947211Skarels #define PUTESC(c) { \
5047211Skarels 	if (c == FRAME_END) { \
5147211Skarels 		PUTC(FRAME_ESCAPE); \
5247211Skarels 		c = TRANS_FRAME_END; \
5347211Skarels 	} else if (c == FRAME_ESCAPE) { \
5447211Skarels 		PUTC(FRAME_ESCAPE); \
5547211Skarels 		c = TRANS_FRAME_ESCAPE; \
5647211Skarels 	} \
5747211Skarels 	PUTC(c); \
5842367Smckusick }
5942367Smckusick 
6047211Skarels static int (*kgdb_getc)();
6147211Skarels static int (*kgdb_putc)();
6241475Smckusick 
6341475Smckusick /*
6447211Skarels  * Send a message.  The host gets one chance to read it.
6541475Smckusick  */
6647211Skarels static void
6747211Skarels kgdb_send(type, bp, len)
6847211Skarels 	register u_char type;
6947211Skarels 	register u_char *bp;
7047211Skarels 	register int len;
7141475Smckusick {
7247211Skarels 	register u_char csum;
7347211Skarels 	register u_char *ep = bp + len;
7441475Smckusick 
7547211Skarels 	csum = type;
7647211Skarels 	PUTESC(type)
7741475Smckusick 
7847211Skarels 	while (bp < ep) {
7947211Skarels 		type = *bp++;
8047211Skarels 		csum += type;
8147211Skarels 		PUTESC(type)
8247211Skarels 	}
8347211Skarels 	csum = -csum;
8447211Skarels 	PUTESC(csum)
8547211Skarels 	PUTC(FRAME_END);
8641475Smckusick }
8741475Smckusick 
8847211Skarels static int
8947211Skarels kgdb_recv(bp, lenp)
9047211Skarels 	u_char *bp;
9147211Skarels 	int *lenp;
9241475Smckusick {
9347211Skarels 	register u_char c, csum;
9447211Skarels 	register int escape, len;
9547211Skarels 	register int type;
9641475Smckusick 
9747211Skarels 	csum = len = escape = 0;
9847211Skarels 	type = -1;
9947211Skarels 	while (1) {
10047211Skarels 		c = GETC;
10147211Skarels 		switch (c) {
10241475Smckusick 
10347211Skarels 		case FRAME_ESCAPE:
10447211Skarels 			escape = 1;
10547211Skarels 			continue;
10641475Smckusick 
10747211Skarels 		case TRANS_FRAME_ESCAPE:
10847211Skarels 			if (escape)
10947211Skarels 				c = FRAME_ESCAPE;
11047211Skarels 			break;
11141475Smckusick 
11247211Skarels 		case TRANS_FRAME_END:
11347211Skarels 			if (escape)
11447211Skarels 				c = FRAME_END;
11541475Smckusick 			break;
11641475Smckusick 
11747211Skarels 		case FRAME_END:
11847211Skarels 			if (type < 0 || --len < 0) {
11947211Skarels 				csum = len = escape = 0;
12047211Skarels 				type = -1;
12147211Skarels 				continue;
12247211Skarels 			}
12347211Skarels 			if (csum != 0) {
12447211Skarels 				return (0);
12547211Skarels 			}
12647211Skarels 			*lenp = len;
12747211Skarels 			return type;
12841475Smckusick 		}
12947211Skarels 		csum += c;
13047211Skarels 		if (type < 0) {
13147211Skarels 			type = c;
13247211Skarels 			escape = 0;
13347211Skarels 			continue;
13441475Smckusick 		}
13548473Skarels 		if (++len > SL_BUFSIZE) {
13647211Skarels 			while (GETC != FRAME_END)
13747211Skarels 				;
13847211Skarels 			return (0);
13947211Skarels 		}
14047211Skarels 		*bp++ = c;
14147211Skarels 		escape = 0;
14241475Smckusick 	}
14341475Smckusick }
14441475Smckusick 
14541475Smckusick /*
14641475Smckusick  * Translate a trap number into a unix compatible signal value.
14741475Smckusick  * (gdb only understands unix signal numbers).
14841475Smckusick  */
14941475Smckusick static int
15047211Skarels computeSignal(type)
15147211Skarels 	int type;
15241475Smckusick {
15341475Smckusick 	int sigval;
15441475Smckusick 
15547262Skarels 	switch (type) {
15641475Smckusick 	case T_BUSERR:
15741475Smckusick 		sigval = SIGBUS;
15847211Skarels 		break;
15941475Smckusick 	case T_ADDRERR:
16041475Smckusick 		sigval = SIGBUS;
16147211Skarels 		break;
16241475Smckusick 	case T_ILLINST:
16341475Smckusick 		sigval = SIGILL;
16447211Skarels 		break;
16541475Smckusick 	case T_ZERODIV:
16641475Smckusick 		sigval = SIGFPE;
16747211Skarels 		break;
16841475Smckusick 	case T_CHKINST:
16941475Smckusick 		sigval = SIGFPE;
17047211Skarels 		break;
17141475Smckusick 	case T_TRAPVINST:
17241475Smckusick 		sigval = SIGFPE;
17347211Skarels 		break;
17441475Smckusick 	case T_PRIVINST:
17541475Smckusick 		sigval = SIGILL;
17647211Skarels 		break;
17741475Smckusick 	case T_TRACE:
17841475Smckusick 		sigval = SIGTRAP;
17947211Skarels 		break;
18041475Smckusick 	case T_MMUFLT:
18141475Smckusick 		sigval = SIGSEGV;
18241475Smckusick 		break;
18341475Smckusick 	case T_SSIR:
18441475Smckusick 		sigval = SIGSEGV;
18541475Smckusick 		break;
18641475Smckusick 	case T_FMTERR:
18741475Smckusick 		sigval = SIGILL;
18841475Smckusick 		break;
18941475Smckusick 	case T_FPERR:
19041475Smckusick 		sigval = SIGFPE;
19141475Smckusick 		break;
19241475Smckusick 	case T_COPERR:
19341475Smckusick 		sigval = SIGFPE;
19441475Smckusick 		break;
19543413Shibler 	case T_ASTFLT:
19641475Smckusick 		sigval = SIGINT;
19741475Smckusick 		break;
19841475Smckusick 	case T_TRAP15:
19947211Skarels 		sigval = SIGTRAP;
20041475Smckusick 		break;
20141475Smckusick 	default:
20241475Smckusick 		sigval = SIGEMT;
20341475Smckusick 		break;
20441475Smckusick 	}
20541475Smckusick 	return (sigval);
20641475Smckusick }
20741475Smckusick 
20847211Skarels /*
20948473Skarels  * Trap into kgdb to wait for debugger to connect,
21047471Skarels  * noting on the console why nothing else is going on.
21147471Skarels  */
21247471Skarels kgdb_connect(verbose)
21347471Skarels 	int verbose;
21447471Skarels {
21547471Skarels 
21647471Skarels 	if (verbose)
21747471Skarels 		printf("kgdb waiting...");
21847471Skarels 	/* trap into kgdb */
21947471Skarels 	asm("trap #15;");
22047471Skarels 	if (verbose)
22147471Skarels 		printf("connected.\n");
22247471Skarels }
22347471Skarels 
22447471Skarels /*
22547471Skarels  * Decide what to do on panic.
22647471Skarels  */
22747471Skarels kgdb_panic()
22847471Skarels {
22947471Skarels 
23050225Skarels 	if (kgdb_active == 0 && kgdb_debug_panic && kgdb_dev != NODEV)
23147471Skarels 		kgdb_connect(1);
23247471Skarels }
23347471Skarels 
23447471Skarels /*
23547211Skarels  * Definitions exported from gdb.
23647211Skarels  */
23747211Skarels #define NUM_REGS 18
23847211Skarels #define REGISTER_BYTES ((16+2)*4)
23947211Skarels #define REGISTER_BYTE(N)  ((N)*4)
24041475Smckusick 
24147211Skarels #define GDB_SR 16
24247211Skarels #define GDB_PC 17
24347211Skarels 
24447262Skarels static inline void
24547262Skarels kgdb_copy(register u_char *src, register u_char *dst, register u_int nbytes)
24647211Skarels {
24747262Skarels 	register u_char *ep = src + nbytes;
24847211Skarels 
24947262Skarels 	while (src < ep)
25047262Skarels 		*dst++ = *src++;
25147211Skarels }
25247211Skarels 
25347262Skarels #define regs_to_gdb(fp, regs) \
25447262Skarels 	(kgdb_copy((u_char *)((fp)->f_regs), (u_char *)(regs), REGISTER_BYTES))
25547262Skarels 
25647262Skarels #define gdb_to_regs(fp, regs) \
25747262Skarels 	(kgdb_copy((u_char *)(regs), (u_char *)((fp)->f_regs), REGISTER_BYTES))
25847262Skarels 
25947211Skarels static u_long reg_cache[NUM_REGS];
26048473Skarels static u_char inbuffer[SL_BUFSIZE];
26148473Skarels static u_char outbuffer[SL_BUFSIZE];
26247211Skarels 
26347211Skarels /*
26441475Smckusick  * This function does all command procesing for interfacing to
26541475Smckusick  * a remote gdb.
26641475Smckusick  */
26741475Smckusick int
26847262Skarels kgdb_trap(int type, struct frame *frame)
26941475Smckusick {
27047262Skarels 	register u_long len;
27147262Skarels 	u_char *addr;
27247262Skarels 	register u_char *cp;
27347262Skarels 	register u_char out, in;
27447262Skarels 	register int outlen;
27547262Skarels 	int inlen;
27647211Skarels 	u_long gdb_regs[NUM_REGS];
27741475Smckusick 
27847211Skarels 	if (kgdb_dev < 0) {
27941475Smckusick 		/* not debugging */
28041475Smckusick 		return (0);
28147211Skarels 	}
28247211Skarels 	if (kgdb_active == 0) {
28347211Skarels 		if (type != T_TRAP15) {
28447211Skarels 			/* No debugger active -- let trap handle this. */
28547211Skarels 			return (0);
28647211Skarels 		}
28747471Skarels 		kgdb_getc = 0;
28847471Skarels 		for (inlen = 0; constab[inlen].cn_probe; inlen++)
28947471Skarels 		    if (major(constab[inlen].cn_dev) == major(kgdb_dev)) {
29047471Skarels 			kgdb_getc = constab[inlen].cn_getc;
29147471Skarels 			kgdb_putc = constab[inlen].cn_putc;
29247471Skarels 			break;
29347471Skarels 		}
29447262Skarels 		if (kgdb_getc == 0 || kgdb_putc == 0)
29547211Skarels 			return (0);
29647262Skarels 		/*
29748473Skarels 		 * If the packet that woke us up isn't an exec packet,
29847262Skarels 		 * ignore it since there is no active debugger.  Also,
29947262Skarels 		 * we check that it's not an ack to be sure that the
30047262Skarels 		 * remote side doesn't send back a response after the
30147262Skarels 		 * local gdb has exited.  Otherwise, the local host
30247262Skarels 		 * could trap into gdb if it's running a gdb kernel too.
30347262Skarels 		 */
30447262Skarels 		in = GETC;
30548473Skarels 		/*
30648473Skarels 		 * If we came in asynchronously through the serial line,
30748473Skarels 		 * the framing character is eaten by the receive interrupt,
30848473Skarels 		 * but if we come in through a synchronous trap (i.e., via
30948473Skarels 		 * kgdb_connect()), we will see the extra character.
31048473Skarels 		 */
31148473Skarels 		if (in == FRAME_END)
31248473Skarels 			in = GETC;
31348473Skarels 
31448473Skarels 		if (KGDB_CMD(in) != KGDB_EXEC || (in & KGDB_ACK) != 0)
31547262Skarels 			return (0);
31647262Skarels 		while (GETC != FRAME_END)
31747262Skarels 			;
31848473Skarels 		/*
31948473Skarels 		 * Do the printf *before* we ack the message.  This way
32048473Skarels 		 * we won't drop any inbound characters while we're
32148473Skarels 		 * doing the polling printf.
32248473Skarels 		 */
32348473Skarels 		printf("kgdb started from device %x\n", kgdb_dev);
32448473Skarels 		kgdb_send(in | KGDB_ACK, (u_char *)0, 0);
32547211Skarels 		kgdb_active = 1;
32647211Skarels 	}
32747211Skarels 	/*
32847211Skarels 	 * Stick frame regs into our reg cache then tell remote host
32947211Skarels 	 * that an exception has occured.
33047211Skarels 	 */
33147211Skarels 	regs_to_gdb(frame, gdb_regs);
33248473Skarels 	if (type != T_TRAP15) {
33348473Skarels 		/*
33448473Skarels 		 * Only send an asynchronous SIGNAL message when we hit
33548473Skarels 		 * a breakpoint.  Otherwise, we will drop the incoming
33648473Skarels 		 * packet while we output this one (and on entry the other
33748473Skarels 		 * side isn't interested in the SIGNAL type -- if it is,
33848473Skarels 		 * it will have used a signal packet.)
33948473Skarels 		 */
34048473Skarels 		outbuffer[0] = computeSignal(type);
34148473Skarels 		kgdb_send(KGDB_SIGNAL, outbuffer, 1);
34248473Skarels 	}
34341475Smckusick 
34447211Skarels 	while (1) {
34547211Skarels 		in = kgdb_recv(inbuffer, &inlen);
34647211Skarels 		if (in == 0 || (in & KGDB_ACK))
34747211Skarels 			/* Ignore inbound acks and error conditions. */
34847211Skarels 			continue;
34941475Smckusick 
35047211Skarels 		out = in | KGDB_ACK;
35147262Skarels 		switch (KGDB_CMD(in)) {
35247211Skarels 
35347211Skarels 		case KGDB_SIGNAL:
35447262Skarels 			/*
35547262Skarels 			 * if this command came from a running gdb,
35647262Skarels 			 * answer it -- the other guy has no way of
35747262Skarels 			 * knowing if we're in or out of this loop
35847262Skarels 			 * when he issues a "remote-signal".  (Note
35947262Skarels 			 * that without the length check, we could
36047262Skarels 			 * loop here forever if the ourput line is
36147262Skarels 			 * looped back or the remote host is echoing.)
36247262Skarels 			 */
36347262Skarels 			if (inlen == 0) {
36447262Skarels 				outbuffer[0] = computeSignal(type);
36547262Skarels 				kgdb_send(KGDB_SIGNAL, outbuffer, 1);
36647262Skarels 			}
36747262Skarels 			continue;
36847211Skarels 
36947211Skarels 		case KGDB_REG_R:
37047211Skarels 		case KGDB_REG_R | KGDB_DELTA:
37147211Skarels 			cp = outbuffer;
37247211Skarels 			outlen = 0;
37347262Skarels 			for (len = inbuffer[0]; len < NUM_REGS; ++len) {
37447262Skarels 				if (reg_cache[len] != gdb_regs[len] ||
37547211Skarels 				    (in & KGDB_DELTA) == 0) {
37647211Skarels 					if (outlen + 5 > SL_MAXMSG) {
37747211Skarels 						out |= KGDB_MORE;
37847211Skarels 						break;
37947211Skarels 					}
38047262Skarels 					cp[outlen] = len;
38147262Skarels 					kgdb_copy((u_char *)&gdb_regs[len],
38247262Skarels 						  &cp[outlen + 1], 4);
38347262Skarels 					reg_cache[len] = gdb_regs[len];
38447211Skarels 					outlen += 5;
38547211Skarels 				}
38641475Smckusick 			}
38741475Smckusick 			break;
38847211Skarels 
38947211Skarels 		case KGDB_REG_W:
39047211Skarels 		case KGDB_REG_W | KGDB_DELTA:
39147211Skarels 			cp = inbuffer;
39247262Skarels 			for (len = 0; len < inlen; len += 5) {
39347262Skarels 				register int j = cp[len];
39441475Smckusick 
39547262Skarels 				kgdb_copy(&cp[len + 1],
39647262Skarels 					  (u_char *)&gdb_regs[j], 4);
39747211Skarels 				reg_cache[j] = gdb_regs[j];
39841475Smckusick 			}
39947211Skarels 			gdb_to_regs(frame, gdb_regs);
40047211Skarels 			outlen = 0;
40147211Skarels 			break;
40247211Skarels 
40347211Skarels 		case KGDB_MEM_R:
40447262Skarels 			len = inbuffer[0];
40547262Skarels 			kgdb_copy(&inbuffer[1], (u_char *)&addr, 4);
40647262Skarels 			if (len + 1 > SL_MAXMSG) {
40747211Skarels 				outlen = 1;
40847211Skarels 				outbuffer[0] = E2BIG;
40947262Skarels 			} else if (!kgdb_acc(addr, len, B_READ)) {
41047211Skarels 				outlen = 1;
41147211Skarels 				outbuffer[0] = EFAULT;
41247211Skarels 			} else {
41347262Skarels 				outlen = len + 1;
41447211Skarels 				outbuffer[0] = 0;
41547262Skarels 				kgdb_copy(addr, &outbuffer[1], len);
41641475Smckusick 			}
41741475Smckusick 			break;
41841475Smckusick 
41947211Skarels 		case KGDB_MEM_W:
42047262Skarels 			len = inlen - 4;
42147262Skarels 			kgdb_copy(inbuffer, (u_char *)&addr, 4);
42247211Skarels 			outlen = 1;
42347262Skarels 			if (!kgdb_acc(addr, len, B_READ))
42447211Skarels 				outbuffer[0] = EFAULT;
42547211Skarels 			else {
42647211Skarels 				outbuffer[0] = 0;
42747262Skarels 				if (!kgdb_acc(addr, len, B_WRITE))
42847262Skarels 					chgkprot(addr, len, B_WRITE);
42947262Skarels 				kgdb_copy(&inbuffer[4], addr, len);
430*54245Smckusick 				ICIA();
43141475Smckusick 			}
43241475Smckusick 			break;
43341475Smckusick 
43447211Skarels 		case KGDB_KILL:
43547211Skarels 			kgdb_active = 0;
43648473Skarels 			printf("kgdb detached\n");
43747211Skarels 			/* fall through */
43847211Skarels 		case KGDB_CONT:
43947211Skarels 			kgdb_send(out, 0, 0);
44047211Skarels 			frame->f_sr &=~ PSL_T;
44147211Skarels 			return (1);
44241475Smckusick 
44347211Skarels 		case KGDB_STEP:
44447211Skarels 			kgdb_send(out, 0, 0);
44547211Skarels 			frame->f_sr |= PSL_T;
44641475Smckusick 			return (1);
44741475Smckusick 
44848473Skarels 		case KGDB_EXEC:
44947211Skarels 		default:
45047211Skarels 			/* Unknown command.  Ack with a null message. */
45147211Skarels 			outlen = 0;
45247211Skarels 			break;
45341475Smckusick 		}
45447211Skarels 		/* Send the reply */
45547211Skarels 		kgdb_send(out, outbuffer, outlen);
45641475Smckusick 	}
45741475Smckusick }
45847262Skarels 
45947262Skarels /*
46047262Skarels  * XXX do kernacc call if safe, otherwise attempt
46147262Skarels  * to simulate by simple bounds-checking.
46247262Skarels  */
46347262Skarels kgdb_acc(addr, len, rw)
46447262Skarels 	caddr_t addr;
46547262Skarels {
46649119Skarels 	extern char proc0paddr[], kstack[];	/* XXX */
46747262Skarels 	extern char *kernel_map;		/* XXX! */
46847262Skarels 
46947262Skarels 	if (kernel_map != NULL)
47047262Skarels 		return (kernacc(addr, len, rw));
47147262Skarels 	if (addr < proc0paddr + UPAGES * NBPG  ||
47249119Skarels 	    kstack <= addr && addr < kstack + UPAGES * NBPG)
47347262Skarels 		return (1);
47447262Skarels 	return (0);
47547262Skarels }
47641475Smckusick #endif
477