xref: /csrg-svn/sys/hp300/hp300/kgdb_stub.c (revision 55673)
141475Smckusick /*
247211Skarels  * Copyright (c) 1990 Regents of the University of California.
341475Smckusick  * All rights reserved.
441475Smckusick  *
5*55673Smckusick  * This code is derived from software contributed to Berkeley by
6*55673Smckusick  * Van Jacobson and Steven McCanne of Lawrence Berkeley Laboratory.
7*55673Smckusick  *
841475Smckusick  * %sccs.include.redist.c%
941475Smckusick  *
10*55673Smckusick  *	@(#)kgdb_stub.c	7.13 (Berkeley) 07/24/92
1141475Smckusick  */
12*55673Smckusick 
1341475Smckusick /*
1447211Skarels  * "Stub" to allow remote cpu to debug over a serial line using gdb.
1547211Skarels  */
1641475Smckusick #ifdef KGDB
1747211Skarels #ifndef lint
18*55673Smckusick static char rcsid[] = "$Header: kgdb_stub.c,v 1.2 92/07/23 19:37:50 mccanne Exp $";
1947211Skarels #endif
2041475Smckusick 
2147211Skarels #include "param.h"
2247211Skarels #include "systm.h"
2348473Skarels #include "../include/trap.h"
2448473Skarels #include "../include/cpu.h"
2548473Skarels #include "../include/psl.h"
2648473Skarels #include "../include/reg.h"
2748473Skarels #include "../include/frame.h"
2847211Skarels #include "buf.h"
2953933Shibler #include "hp/dev/cons.h"
3047211Skarels 
3147211Skarels #include "kgdb_proto.h"
3247211Skarels #include "machine/remote-sl.h"
3347211Skarels 
3441475Smckusick extern int kernacc();
3541475Smckusick extern void chgkprot();
3641475Smckusick 
3742367Smckusick #ifndef KGDBDEV
3850225Skarels #define KGDBDEV NODEV
3942367Smckusick #endif
4042367Smckusick #ifndef KGDBRATE
4142367Smckusick #define KGDBRATE 9600
4242367Smckusick #endif
4342367Smckusick 
4450225Skarels dev_t kgdb_dev = KGDBDEV;	/* remote debugging device (NODEV if none) */
4542367Smckusick int kgdb_rate = KGDBRATE;	/* remote debugging baud rate */
4647211Skarels int kgdb_active = 0;            /* remote debugging active if != 0 */
4741475Smckusick int kgdb_debug_init = 0;	/* != 0 waits for remote at system init */
4847471Skarels int kgdb_debug_panic = 1;	/* != 0 waits for remote on panic */
4947211Skarels int kgdb_debug = 0;
5041475Smckusick 
5147211Skarels #define GETC	((*kgdb_getc)(kgdb_dev))
5247211Skarels #define PUTC(c)	((*kgdb_putc)(kgdb_dev, c))
5347211Skarels #define PUTESC(c) { \
5447211Skarels 	if (c == FRAME_END) { \
5547211Skarels 		PUTC(FRAME_ESCAPE); \
5647211Skarels 		c = TRANS_FRAME_END; \
5747211Skarels 	} else if (c == FRAME_ESCAPE) { \
5847211Skarels 		PUTC(FRAME_ESCAPE); \
5947211Skarels 		c = TRANS_FRAME_ESCAPE; \
60*55673Smckusick 	} else if (c == FRAME_START) { \
61*55673Smckusick 		PUTC(FRAME_ESCAPE); \
62*55673Smckusick 		c = TRANS_FRAME_START; \
6347211Skarels 	} \
6447211Skarels 	PUTC(c); \
6542367Smckusick }
6647211Skarels static int (*kgdb_getc)();
6747211Skarels static int (*kgdb_putc)();
6841475Smckusick 
6941475Smckusick /*
7047211Skarels  * Send a message.  The host gets one chance to read it.
7141475Smckusick  */
7247211Skarels static void
7347211Skarels kgdb_send(type, bp, len)
7447211Skarels 	register u_char type;
7547211Skarels 	register u_char *bp;
7647211Skarels 	register int len;
7741475Smckusick {
7847211Skarels 	register u_char csum;
7947211Skarels 	register u_char *ep = bp + len;
8041475Smckusick 
81*55673Smckusick 	PUTC(FRAME_START);
82*55673Smckusick 	PUTESC(type);
83*55673Smckusick 
8447211Skarels 	csum = type;
8547211Skarels 	while (bp < ep) {
8647211Skarels 		type = *bp++;
8747211Skarels 		csum += type;
8847211Skarels 		PUTESC(type)
8947211Skarels 	}
9047211Skarels 	csum = -csum;
9147211Skarels 	PUTESC(csum)
9247211Skarels 	PUTC(FRAME_END);
9341475Smckusick }
9441475Smckusick 
9547211Skarels static int
9647211Skarels kgdb_recv(bp, lenp)
9747211Skarels 	u_char *bp;
9847211Skarels 	int *lenp;
9941475Smckusick {
10047211Skarels 	register u_char c, csum;
10147211Skarels 	register int escape, len;
10247211Skarels 	register int type;
10341475Smckusick 
104*55673Smckusick restart:
10547211Skarels 	csum = len = escape = 0;
10647211Skarels 	type = -1;
10747211Skarels 	while (1) {
10847211Skarels 		c = GETC;
10947211Skarels 		switch (c) {
11041475Smckusick 
11147211Skarels 		case FRAME_ESCAPE:
11247211Skarels 			escape = 1;
11347211Skarels 			continue;
11441475Smckusick 
11547211Skarels 		case TRANS_FRAME_ESCAPE:
11647211Skarels 			if (escape)
11747211Skarels 				c = FRAME_ESCAPE;
11847211Skarels 			break;
11941475Smckusick 
12047211Skarels 		case TRANS_FRAME_END:
12147211Skarels 			if (escape)
12247211Skarels 				c = FRAME_END;
12341475Smckusick 			break;
12441475Smckusick 
125*55673Smckusick 		case TRANS_FRAME_START:
126*55673Smckusick 			if (escape)
127*55673Smckusick 				c = FRAME_START;
128*55673Smckusick 			break;
129*55673Smckusick 
130*55673Smckusick 		case FRAME_START:
131*55673Smckusick 			goto restart;
132*55673Smckusick 
13347211Skarels 		case FRAME_END:
13447211Skarels 			if (type < 0 || --len < 0) {
13547211Skarels 				csum = len = escape = 0;
13647211Skarels 				type = -1;
13747211Skarels 				continue;
13847211Skarels 			}
13947211Skarels 			if (csum != 0) {
14047211Skarels 				return (0);
14147211Skarels 			}
14247211Skarels 			*lenp = len;
14347211Skarels 			return type;
14441475Smckusick 		}
14547211Skarels 		csum += c;
14647211Skarels 		if (type < 0) {
14747211Skarels 			type = c;
14847211Skarels 			escape = 0;
14947211Skarels 			continue;
15041475Smckusick 		}
151*55673Smckusick 		if (++len > SL_RPCSIZE) {
15247211Skarels 			while (GETC != FRAME_END)
15347211Skarels 				;
15447211Skarels 			return (0);
15547211Skarels 		}
15647211Skarels 		*bp++ = c;
15747211Skarels 		escape = 0;
15841475Smckusick 	}
15941475Smckusick }
16041475Smckusick 
16141475Smckusick /*
16241475Smckusick  * Translate a trap number into a unix compatible signal value.
16341475Smckusick  * (gdb only understands unix signal numbers).
16441475Smckusick  */
16541475Smckusick static int
16647211Skarels computeSignal(type)
16747211Skarels 	int type;
16841475Smckusick {
16941475Smckusick 	int sigval;
17041475Smckusick 
17147262Skarels 	switch (type) {
17241475Smckusick 	case T_BUSERR:
17341475Smckusick 		sigval = SIGBUS;
17447211Skarels 		break;
17541475Smckusick 	case T_ADDRERR:
17641475Smckusick 		sigval = SIGBUS;
17747211Skarels 		break;
17841475Smckusick 	case T_ILLINST:
17941475Smckusick 		sigval = SIGILL;
18047211Skarels 		break;
18141475Smckusick 	case T_ZERODIV:
18241475Smckusick 		sigval = SIGFPE;
18347211Skarels 		break;
18441475Smckusick 	case T_CHKINST:
18541475Smckusick 		sigval = SIGFPE;
18647211Skarels 		break;
18741475Smckusick 	case T_TRAPVINST:
18841475Smckusick 		sigval = SIGFPE;
18947211Skarels 		break;
19041475Smckusick 	case T_PRIVINST:
19141475Smckusick 		sigval = SIGILL;
19247211Skarels 		break;
19341475Smckusick 	case T_TRACE:
19441475Smckusick 		sigval = SIGTRAP;
19547211Skarels 		break;
19641475Smckusick 	case T_MMUFLT:
19741475Smckusick 		sigval = SIGSEGV;
19841475Smckusick 		break;
19941475Smckusick 	case T_SSIR:
20041475Smckusick 		sigval = SIGSEGV;
20141475Smckusick 		break;
20241475Smckusick 	case T_FMTERR:
20341475Smckusick 		sigval = SIGILL;
20441475Smckusick 		break;
20541475Smckusick 	case T_FPERR:
20641475Smckusick 		sigval = SIGFPE;
20741475Smckusick 		break;
20841475Smckusick 	case T_COPERR:
20941475Smckusick 		sigval = SIGFPE;
21041475Smckusick 		break;
21143413Shibler 	case T_ASTFLT:
21241475Smckusick 		sigval = SIGINT;
21341475Smckusick 		break;
21441475Smckusick 	case T_TRAP15:
21547211Skarels 		sigval = SIGTRAP;
21641475Smckusick 		break;
21741475Smckusick 	default:
21841475Smckusick 		sigval = SIGEMT;
21941475Smckusick 		break;
22041475Smckusick 	}
22141475Smckusick 	return (sigval);
22241475Smckusick }
22341475Smckusick 
22447211Skarels /*
22548473Skarels  * Trap into kgdb to wait for debugger to connect,
22647471Skarels  * noting on the console why nothing else is going on.
22747471Skarels  */
22847471Skarels kgdb_connect(verbose)
22947471Skarels 	int verbose;
23047471Skarels {
23147471Skarels 
23247471Skarels 	if (verbose)
23347471Skarels 		printf("kgdb waiting...");
23447471Skarels 	/* trap into kgdb */
23547471Skarels 	asm("trap #15;");
23647471Skarels 	if (verbose)
23747471Skarels 		printf("connected.\n");
23847471Skarels }
23947471Skarels 
24047471Skarels /*
24147471Skarels  * Decide what to do on panic.
24247471Skarels  */
24347471Skarels kgdb_panic()
24447471Skarels {
24547471Skarels 
24650225Skarels 	if (kgdb_active == 0 && kgdb_debug_panic && kgdb_dev != NODEV)
24747471Skarels 		kgdb_connect(1);
24847471Skarels }
24947471Skarels 
25047471Skarels /*
25147211Skarels  * Definitions exported from gdb.
25247211Skarels  */
25347211Skarels #define NUM_REGS 18
25447211Skarels #define REGISTER_BYTES ((16+2)*4)
25547211Skarels #define REGISTER_BYTE(N)  ((N)*4)
25641475Smckusick 
25747211Skarels #define GDB_SR 16
25847211Skarels #define GDB_PC 17
25947211Skarels 
26047262Skarels static inline void
26147262Skarels kgdb_copy(register u_char *src, register u_char *dst, register u_int nbytes)
26247211Skarels {
26347262Skarels 	register u_char *ep = src + nbytes;
26447211Skarels 
26547262Skarels 	while (src < ep)
26647262Skarels 		*dst++ = *src++;
26747211Skarels }
26847211Skarels 
26947262Skarels #define regs_to_gdb(fp, regs) \
27047262Skarels 	(kgdb_copy((u_char *)((fp)->f_regs), (u_char *)(regs), REGISTER_BYTES))
27147262Skarels 
27247262Skarels #define gdb_to_regs(fp, regs) \
27347262Skarels 	(kgdb_copy((u_char *)(regs), (u_char *)((fp)->f_regs), REGISTER_BYTES))
27447262Skarels 
27547211Skarels static u_long reg_cache[NUM_REGS];
276*55673Smckusick static u_char inbuffer[SL_RPCSIZE+1];
277*55673Smckusick static u_char outbuffer[SL_RPCSIZE];
27847211Skarels 
27947211Skarels /*
28041475Smckusick  * This function does all command procesing for interfacing to
28141475Smckusick  * a remote gdb.
28241475Smckusick  */
28341475Smckusick int
28447262Skarels kgdb_trap(int type, struct frame *frame)
28541475Smckusick {
28647262Skarels 	register u_long len;
28747262Skarels 	u_char *addr;
28847262Skarels 	register u_char *cp;
28947262Skarels 	register u_char out, in;
29047262Skarels 	register int outlen;
29147262Skarels 	int inlen;
29247211Skarels 	u_long gdb_regs[NUM_REGS];
29341475Smckusick 
29447211Skarels 	if (kgdb_dev < 0) {
29541475Smckusick 		/* not debugging */
29641475Smckusick 		return (0);
29747211Skarels 	}
29847211Skarels 	if (kgdb_active == 0) {
29947211Skarels 		if (type != T_TRAP15) {
30047211Skarels 			/* No debugger active -- let trap handle this. */
30147211Skarels 			return (0);
30247211Skarels 		}
30347471Skarels 		kgdb_getc = 0;
30447471Skarels 		for (inlen = 0; constab[inlen].cn_probe; inlen++)
30547471Skarels 		    if (major(constab[inlen].cn_dev) == major(kgdb_dev)) {
30647471Skarels 			kgdb_getc = constab[inlen].cn_getc;
30747471Skarels 			kgdb_putc = constab[inlen].cn_putc;
30847471Skarels 			break;
30947471Skarels 		}
31047262Skarels 		if (kgdb_getc == 0 || kgdb_putc == 0)
31147211Skarels 			return (0);
31247262Skarels 		/*
31348473Skarels 		 * If the packet that woke us up isn't an exec packet,
31447262Skarels 		 * ignore it since there is no active debugger.  Also,
31547262Skarels 		 * we check that it's not an ack to be sure that the
31647262Skarels 		 * remote side doesn't send back a response after the
31747262Skarels 		 * local gdb has exited.  Otherwise, the local host
31847262Skarels 		 * could trap into gdb if it's running a gdb kernel too.
31947262Skarels 		 */
32047262Skarels 		in = GETC;
32148473Skarels 		/*
32248473Skarels 		 * If we came in asynchronously through the serial line,
32348473Skarels 		 * the framing character is eaten by the receive interrupt,
32448473Skarels 		 * but if we come in through a synchronous trap (i.e., via
32548473Skarels 		 * kgdb_connect()), we will see the extra character.
32648473Skarels 		 */
327*55673Smckusick 		if (in == FRAME_START)
32848473Skarels 			in = GETC;
32948473Skarels 
330*55673Smckusick 		/*
331*55673Smckusick 		 * Check that this is a debugger exec message.  If so,
332*55673Smckusick 		 * slurp up the entire message then ack it, and fall
333*55673Smckusick 		 * through to the recv loop.
334*55673Smckusick 		 */
33548473Skarels 		if (KGDB_CMD(in) != KGDB_EXEC || (in & KGDB_ACK) != 0)
33647262Skarels 			return (0);
33747262Skarels 		while (GETC != FRAME_END)
33847262Skarels 			;
33948473Skarels 		/*
34048473Skarels 		 * Do the printf *before* we ack the message.  This way
34148473Skarels 		 * we won't drop any inbound characters while we're
34248473Skarels 		 * doing the polling printf.
34348473Skarels 		 */
34448473Skarels 		printf("kgdb started from device %x\n", kgdb_dev);
34548473Skarels 		kgdb_send(in | KGDB_ACK, (u_char *)0, 0);
34647211Skarels 		kgdb_active = 1;
34747211Skarels 	}
34847211Skarels 	/*
34947211Skarels 	 * Stick frame regs into our reg cache then tell remote host
35047211Skarels 	 * that an exception has occured.
35147211Skarels 	 */
35247211Skarels 	regs_to_gdb(frame, gdb_regs);
35348473Skarels 	if (type != T_TRAP15) {
35448473Skarels 		/*
35548473Skarels 		 * Only send an asynchronous SIGNAL message when we hit
35648473Skarels 		 * a breakpoint.  Otherwise, we will drop the incoming
35748473Skarels 		 * packet while we output this one (and on entry the other
35848473Skarels 		 * side isn't interested in the SIGNAL type -- if it is,
35948473Skarels 		 * it will have used a signal packet.)
36048473Skarels 		 */
36148473Skarels 		outbuffer[0] = computeSignal(type);
36248473Skarels 		kgdb_send(KGDB_SIGNAL, outbuffer, 1);
36348473Skarels 	}
36441475Smckusick 
36547211Skarels 	while (1) {
36647211Skarels 		in = kgdb_recv(inbuffer, &inlen);
36747211Skarels 		if (in == 0 || (in & KGDB_ACK))
36847211Skarels 			/* Ignore inbound acks and error conditions. */
36947211Skarels 			continue;
37041475Smckusick 
37147211Skarels 		out = in | KGDB_ACK;
37247262Skarels 		switch (KGDB_CMD(in)) {
37347211Skarels 
37447211Skarels 		case KGDB_SIGNAL:
37547262Skarels 			/*
37647262Skarels 			 * if this command came from a running gdb,
37747262Skarels 			 * answer it -- the other guy has no way of
37847262Skarels 			 * knowing if we're in or out of this loop
37947262Skarels 			 * when he issues a "remote-signal".  (Note
38047262Skarels 			 * that without the length check, we could
38147262Skarels 			 * loop here forever if the ourput line is
38247262Skarels 			 * looped back or the remote host is echoing.)
38347262Skarels 			 */
38447262Skarels 			if (inlen == 0) {
38547262Skarels 				outbuffer[0] = computeSignal(type);
38647262Skarels 				kgdb_send(KGDB_SIGNAL, outbuffer, 1);
38747262Skarels 			}
38847262Skarels 			continue;
38947211Skarels 
39047211Skarels 		case KGDB_REG_R:
39147211Skarels 		case KGDB_REG_R | KGDB_DELTA:
39247211Skarels 			cp = outbuffer;
39347211Skarels 			outlen = 0;
39447262Skarels 			for (len = inbuffer[0]; len < NUM_REGS; ++len) {
39547262Skarels 				if (reg_cache[len] != gdb_regs[len] ||
39647211Skarels 				    (in & KGDB_DELTA) == 0) {
397*55673Smckusick 					if (outlen + 5 > SL_MAXDATA) {
39847211Skarels 						out |= KGDB_MORE;
39947211Skarels 						break;
40047211Skarels 					}
40147262Skarels 					cp[outlen] = len;
40247262Skarels 					kgdb_copy((u_char *)&gdb_regs[len],
40347262Skarels 						  &cp[outlen + 1], 4);
40447262Skarels 					reg_cache[len] = gdb_regs[len];
40547211Skarels 					outlen += 5;
40647211Skarels 				}
40741475Smckusick 			}
40841475Smckusick 			break;
40947211Skarels 
41047211Skarels 		case KGDB_REG_W:
41147211Skarels 		case KGDB_REG_W | KGDB_DELTA:
41247211Skarels 			cp = inbuffer;
41347262Skarels 			for (len = 0; len < inlen; len += 5) {
41447262Skarels 				register int j = cp[len];
41541475Smckusick 
41647262Skarels 				kgdb_copy(&cp[len + 1],
41747262Skarels 					  (u_char *)&gdb_regs[j], 4);
41847211Skarels 				reg_cache[j] = gdb_regs[j];
41941475Smckusick 			}
42047211Skarels 			gdb_to_regs(frame, gdb_regs);
42147211Skarels 			outlen = 0;
42247211Skarels 			break;
42347211Skarels 
42447211Skarels 		case KGDB_MEM_R:
42547262Skarels 			len = inbuffer[0];
42647262Skarels 			kgdb_copy(&inbuffer[1], (u_char *)&addr, 4);
427*55673Smckusick 			if (len > SL_MAXDATA) {
42847211Skarels 				outlen = 1;
42947211Skarels 				outbuffer[0] = E2BIG;
43047262Skarels 			} else if (!kgdb_acc(addr, len, B_READ)) {
43147211Skarels 				outlen = 1;
43247211Skarels 				outbuffer[0] = EFAULT;
43347211Skarels 			} else {
43447262Skarels 				outlen = len + 1;
43547211Skarels 				outbuffer[0] = 0;
43647262Skarels 				kgdb_copy(addr, &outbuffer[1], len);
43741475Smckusick 			}
43841475Smckusick 			break;
43941475Smckusick 
44047211Skarels 		case KGDB_MEM_W:
44147262Skarels 			len = inlen - 4;
44247262Skarels 			kgdb_copy(inbuffer, (u_char *)&addr, 4);
44347211Skarels 			outlen = 1;
44447262Skarels 			if (!kgdb_acc(addr, len, B_READ))
44547211Skarels 				outbuffer[0] = EFAULT;
44647211Skarels 			else {
44747211Skarels 				outbuffer[0] = 0;
44847262Skarels 				if (!kgdb_acc(addr, len, B_WRITE))
44947262Skarels 					chgkprot(addr, len, B_WRITE);
45047262Skarels 				kgdb_copy(&inbuffer[4], addr, len);
45154245Smckusick 				ICIA();
45241475Smckusick 			}
45341475Smckusick 			break;
45441475Smckusick 
45547211Skarels 		case KGDB_KILL:
45647211Skarels 			kgdb_active = 0;
45748473Skarels 			printf("kgdb detached\n");
45847211Skarels 			/* fall through */
45947211Skarels 		case KGDB_CONT:
46047211Skarels 			kgdb_send(out, 0, 0);
46147211Skarels 			frame->f_sr &=~ PSL_T;
46247211Skarels 			return (1);
46341475Smckusick 
46447211Skarels 		case KGDB_STEP:
46547211Skarels 			kgdb_send(out, 0, 0);
46647211Skarels 			frame->f_sr |= PSL_T;
46741475Smckusick 			return (1);
46841475Smckusick 
46948473Skarels 		case KGDB_EXEC:
47047211Skarels 		default:
47147211Skarels 			/* Unknown command.  Ack with a null message. */
47247211Skarels 			outlen = 0;
47347211Skarels 			break;
47441475Smckusick 		}
47547211Skarels 		/* Send the reply */
47647211Skarels 		kgdb_send(out, outbuffer, outlen);
47741475Smckusick 	}
47841475Smckusick }
47947262Skarels 
48047262Skarels /*
48147262Skarels  * XXX do kernacc call if safe, otherwise attempt
48247262Skarels  * to simulate by simple bounds-checking.
48347262Skarels  */
48447262Skarels kgdb_acc(addr, len, rw)
48547262Skarels 	caddr_t addr;
48647262Skarels {
48749119Skarels 	extern char proc0paddr[], kstack[];	/* XXX */
48847262Skarels 	extern char *kernel_map;		/* XXX! */
48947262Skarels 
49047262Skarels 	if (kernel_map != NULL)
49147262Skarels 		return (kernacc(addr, len, rw));
49247262Skarels 	if (addr < proc0paddr + UPAGES * NBPG  ||
49349119Skarels 	    kstack <= addr && addr < kstack + UPAGES * NBPG)
49447262Skarels 		return (1);
49547262Skarels 	return (0);
49647262Skarels }
49741475Smckusick #endif
498