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