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 *)®s[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 *)®s[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