xref: /csrg-svn/sys/hp300/hp300/kgdb_stub.c (revision 47471)
141475Smckusick /*
247211Skarels  * Copyright (c) 1990 Regents of the University of California.
341475Smckusick  * All rights reserved.
441475Smckusick  *
541475Smckusick  * %sccs.include.redist.c%
641475Smckusick  *
7*47471Skarels  *	@(#)kgdb_stub.c	7.7 (Berkeley) 03/16/91
841475Smckusick  */
941475Smckusick /*
1047211Skarels  * "Stub" to allow remote cpu to debug over a serial line using gdb.
1147211Skarels  */
1241475Smckusick #ifdef KGDB
1347211Skarels #ifndef lint
1447262Skarels static char rcsid[] = "$Header: kgdb_stub.c,v 1.9 91/03/08 07:03:13 van Locked $";
1547211Skarels #endif
1641475Smckusick 
1747211Skarels #include "param.h"
1847211Skarels #include "systm.h"
1947211Skarels #include "machine/trap.h"
2047211Skarels #include "machine/cpu.h"
2147211Skarels #include "machine/psl.h"
2247211Skarels #include "machine/reg.h"
2347211Skarels #include "frame.h"
2447211Skarels #include "buf.h"
2547262Skarels #include "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
3442367Smckusick #define KGDBDEV -1
3542367Smckusick #endif
3642367Smckusick #ifndef KGDBRATE
3742367Smckusick #define KGDBRATE 9600
3842367Smckusick #endif
3942367Smckusick 
4042367Smckusick int kgdb_dev = KGDBDEV;		/* remote debugging device (-1 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 */
44*47471Skarels 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 		}
13547211Skarels 		if (++len > SL_MAXMSG) {
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 /*
209*47471Skarels  * Trap into kgdb to Wait for debugger to connect,
210*47471Skarels  * noting on the console why nothing else is going on.
211*47471Skarels  */
212*47471Skarels kgdb_connect(verbose)
213*47471Skarels 	int verbose;
214*47471Skarels {
215*47471Skarels 
216*47471Skarels 	if (verbose)
217*47471Skarels 		printf("kgdb waiting...");
218*47471Skarels 	/* trap into kgdb */
219*47471Skarels 	asm("trap #15;");
220*47471Skarels 	if (verbose)
221*47471Skarels 		printf("connected.\n");
222*47471Skarels }
223*47471Skarels 
224*47471Skarels /*
225*47471Skarels  * Decide what to do on panic.
226*47471Skarels  */
227*47471Skarels kgdb_panic()
228*47471Skarels {
229*47471Skarels 
230*47471Skarels 	if (kgdb_active == 0 && kgdb_debug_panic)
231*47471Skarels 		kgdb_connect(1);
232*47471Skarels }
233*47471Skarels 
234*47471Skarels /*
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];
26047262Skarels static u_char inbuffer[SL_MAXMSG+1];
26147262Skarels static u_char outbuffer[SL_MAXMSG];
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 		}
287*47471Skarels 		kgdb_getc = 0;
288*47471Skarels 		for (inlen = 0; constab[inlen].cn_probe; inlen++)
289*47471Skarels 		    if (major(constab[inlen].cn_dev) == major(kgdb_dev)) {
290*47471Skarels 			kgdb_getc = constab[inlen].cn_getc;
291*47471Skarels 			kgdb_putc = constab[inlen].cn_putc;
292*47471Skarels 			break;
293*47471Skarels 		}
29447262Skarels 		if (kgdb_getc == 0 || kgdb_putc == 0)
29547211Skarels 			return (0);
29647262Skarels 		/*
29747262Skarels 		 * If the packet that woke us up isn't a signal 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 #ifdef notdef
30547262Skarels 		in = GETC;
30647262Skarels 		if (KGDB_CMD(in) != KGDB_SIGNAL || (in & KGDB_ACK) != 0)
30747262Skarels 			return (0);
30847262Skarels #endif
30947262Skarels 		while (GETC != FRAME_END)
31047262Skarels 			;
31147262Skarels 
31247211Skarels 		kgdb_active = 1;
31347211Skarels 	}
31447211Skarels 	/*
31547211Skarels 	 * Stick frame regs into our reg cache then tell remote host
31647211Skarels 	 * that an exception has occured.
31747211Skarels 	 */
31847211Skarels 	regs_to_gdb(frame, gdb_regs);
31947211Skarels 	outbuffer[0] = computeSignal(type);
32047211Skarels 	kgdb_send(KGDB_SIGNAL, outbuffer, 1);
32141475Smckusick 
32247211Skarels 	while (1) {
32347211Skarels 		in = kgdb_recv(inbuffer, &inlen);
32447211Skarels 		if (in == 0 || (in & KGDB_ACK))
32547211Skarels 			/* Ignore inbound acks and error conditions. */
32647211Skarels 			continue;
32741475Smckusick 
32847211Skarels 		out = in | KGDB_ACK;
32947262Skarels 		switch (KGDB_CMD(in)) {
33047211Skarels 
33147211Skarels 		case KGDB_SIGNAL:
33247262Skarels 			/*
33347262Skarels 			 * if this command came from a running gdb,
33447262Skarels 			 * answer it -- the other guy has no way of
33547262Skarels 			 * knowing if we're in or out of this loop
33647262Skarels 			 * when he issues a "remote-signal".  (Note
33747262Skarels 			 * that without the length check, we could
33847262Skarels 			 * loop here forever if the ourput line is
33947262Skarels 			 * looped back or the remote host is echoing.)
34047262Skarels 			 */
34147262Skarels 			if (inlen == 0) {
34247262Skarels 				outbuffer[0] = computeSignal(type);
34347262Skarels 				kgdb_send(KGDB_SIGNAL, outbuffer, 1);
34447262Skarels 			}
34547262Skarels 			continue;
34647211Skarels 
34747211Skarels 		case KGDB_REG_R:
34847211Skarels 		case KGDB_REG_R | KGDB_DELTA:
34947211Skarels 			cp = outbuffer;
35047211Skarels 			outlen = 0;
35147262Skarels 			for (len = inbuffer[0]; len < NUM_REGS; ++len) {
35247262Skarels 				if (reg_cache[len] != gdb_regs[len] ||
35347211Skarels 				    (in & KGDB_DELTA) == 0) {
35447211Skarels 					if (outlen + 5 > SL_MAXMSG) {
35547211Skarels 						out |= KGDB_MORE;
35647211Skarels 						break;
35747211Skarels 					}
35847262Skarels 					cp[outlen] = len;
35947262Skarels 					kgdb_copy((u_char *)&gdb_regs[len],
36047262Skarels 						  &cp[outlen + 1], 4);
36147262Skarels 					reg_cache[len] = gdb_regs[len];
36247211Skarels 					outlen += 5;
36347211Skarels 				}
36441475Smckusick 			}
36541475Smckusick 			break;
36647211Skarels 
36747211Skarels 		case KGDB_REG_W:
36847211Skarels 		case KGDB_REG_W | KGDB_DELTA:
36947211Skarels 			cp = inbuffer;
37047262Skarels 			for (len = 0; len < inlen; len += 5) {
37147262Skarels 				register int j = cp[len];
37241475Smckusick 
37347262Skarels 				kgdb_copy(&cp[len + 1],
37447262Skarels 					  (u_char *)&gdb_regs[j], 4);
37547211Skarels 				reg_cache[j] = gdb_regs[j];
37641475Smckusick 			}
37747211Skarels 			gdb_to_regs(frame, gdb_regs);
37847211Skarels 			outlen = 0;
37947211Skarels 			break;
38047211Skarels 
38147211Skarels 		case KGDB_MEM_R:
38247262Skarels 			len = inbuffer[0];
38347262Skarels 			kgdb_copy(&inbuffer[1], (u_char *)&addr, 4);
38447262Skarels 			if (len + 1 > SL_MAXMSG) {
38547211Skarels 				outlen = 1;
38647211Skarels 				outbuffer[0] = E2BIG;
38747262Skarels 			} else if (!kgdb_acc(addr, len, B_READ)) {
38847211Skarels 				outlen = 1;
38947211Skarels 				outbuffer[0] = EFAULT;
39047211Skarels 			} else {
39147262Skarels 				outlen = len + 1;
39247211Skarels 				outbuffer[0] = 0;
39347262Skarels 				kgdb_copy(addr, &outbuffer[1], len);
39441475Smckusick 			}
39541475Smckusick 			break;
39641475Smckusick 
39747211Skarels 		case KGDB_MEM_W:
39847262Skarels 			len = inlen - 4;
39947262Skarels 			kgdb_copy(inbuffer, (u_char *)&addr, 4);
40047211Skarels 			outlen = 1;
40147262Skarels 			if (!kgdb_acc(addr, len, B_READ))
40247211Skarels 				outbuffer[0] = EFAULT;
40347211Skarels 			else {
40447211Skarels 				outbuffer[0] = 0;
40547262Skarels 				if (!kgdb_acc(addr, len, B_WRITE))
40647262Skarels 					chgkprot(addr, len, B_WRITE);
40747262Skarels 				kgdb_copy(&inbuffer[4], addr, len);
40841475Smckusick 			}
40941475Smckusick 			break;
41041475Smckusick 
41147211Skarels 		case KGDB_KILL:
41247211Skarels 			kgdb_active = 0;
41347211Skarels 			/* fall through */
41447211Skarels 		case KGDB_CONT:
41547211Skarels 			kgdb_send(out, 0, 0);
41647211Skarels 			frame->f_sr &=~ PSL_T;
41747211Skarels 			return (1);
41841475Smckusick 
41947211Skarels 		case KGDB_STEP:
42047211Skarels 			kgdb_send(out, 0, 0);
42147211Skarels 			frame->f_sr |= PSL_T;
42241475Smckusick 			return (1);
42341475Smckusick 
42447211Skarels 		default:
42547211Skarels 			/* Unknown command.  Ack with a null message. */
42647211Skarels 			outlen = 0;
42747211Skarels 			break;
42841475Smckusick 		}
42947211Skarels 		/* Send the reply */
43047211Skarels 		kgdb_send(out, outbuffer, outlen);
43141475Smckusick 	}
43241475Smckusick }
43347262Skarels 
43447262Skarels /*
43547262Skarels  * XXX do kernacc call if safe, otherwise attempt
43647262Skarels  * to simulate by simple bounds-checking.
43747262Skarels  */
43847262Skarels kgdb_acc(addr, len, rw)
43947262Skarels 	caddr_t addr;
44047262Skarels {
44147262Skarels 	extern char proc0paddr[], u[];		/* XXX! */
44247262Skarels 	extern char *kernel_map;		/* XXX! */
44347262Skarels 
44447262Skarels 	if (kernel_map != NULL)
44547262Skarels 		return (kernacc(addr, len, rw));
44647262Skarels 	if (addr < proc0paddr + UPAGES * NBPG  ||
44747262Skarels 	    u <= addr && addr < u + UPAGES * NBPG)
44847262Skarels 		return (1);
44947262Skarels 	return (0);
45047262Skarels }
45141475Smckusick #endif
452