141475Smckusick /* 241475Smckusick * Copyright (c) 1988 University of Utah. 341475Smckusick * Copyright (c) 1990 The Regents of the University of California. 441475Smckusick * All rights reserved. 541475Smckusick * 641475Smckusick * This code is derived from software contributed to Berkeley by 741475Smckusick * the Systems Programming Group of the University of Utah Computer 841475Smckusick * Science Department. 941475Smckusick * 1041475Smckusick * %sccs.include.redist.c% 1141475Smckusick * 12*43413Shibler * @(#)kgdb_stub.c 7.3 (Berkeley) 06/22/90 1341475Smckusick */ 1441475Smckusick 1541475Smckusick /* 1641475Smckusick * 1741475Smckusick * The following gdb commands are supported: 1841475Smckusick * 1941475Smckusick * command function Return value 2041475Smckusick * 2141475Smckusick * g return the value of the CPU registers hex data or ENN 2241475Smckusick * G set the value of the CPU registers OK or ENN 2341475Smckusick * 2441475Smckusick * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN 2541475Smckusick * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN 2641475Smckusick * 2741475Smckusick * c Resume at current address SNN ( signal NN) 2841475Smckusick * cAA..AA Continue at address AA..AA SNN 2941475Smckusick * 3041475Smckusick * s Step one instruction SNN 3141475Smckusick * sAA..AA Step one instruction from AA..AA SNN 3241475Smckusick * 3341475Smckusick * k kill 3441475Smckusick * 3541475Smckusick * ? What was the last sigval ? SNN (signal NN) 3641475Smckusick * 3741475Smckusick * All commands and responses are sent with a packet which includes a 3841475Smckusick * checksum. A packet consists of 3941475Smckusick * 4041475Smckusick * $<packet info>#<checksum>. 4141475Smckusick * 4241475Smckusick * where 4341475Smckusick * <packet info> :: <characters representing the command or response> 4441475Smckusick * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> 4541475Smckusick * 4641475Smckusick * When a packet is received, it is first acknowledged with either '+' or '-'. 4741475Smckusick * '+' indicates a successful transfer. '-' indicates a failed transfer. 4841475Smckusick * 4941475Smckusick * Example: 5041475Smckusick * 5141475Smckusick * Host: Reply: 5241475Smckusick * $m0,10#2a +$00010203040506070809101112131415#42 5341475Smckusick * 5441475Smckusick ****************************************************************************/ 5541475Smckusick 5641475Smckusick #ifdef KGDB 5741475Smckusick #include "param.h" 5841475Smckusick #include "systm.h" 5941475Smckusick #include "trap.h" 6041475Smckusick #include "cpu.h" 6141475Smckusick #include "psl.h" 6241475Smckusick #include "reg.h" 6341475Smckusick #include "frame.h" 6441475Smckusick #include "buf.h" 6541475Smckusick 6641475Smckusick extern void printf(); 6741475Smckusick extern void bcopy(); 6841475Smckusick extern int kernacc(); 6941475Smckusick extern void chgkprot(); 7041475Smckusick 7141475Smckusick /* # of additional (beyond 4) bytes in 680x0 exception frame format n */ 7241475Smckusick static int frame_bytes[16] = { 7341475Smckusick 4, 4, 8, 4, 7441475Smckusick 4, 4, 4, 4, 7541475Smckusick 54, 16, 28, 88, 7641475Smckusick 4, 4, 4, 4 7741475Smckusick }; 7841475Smckusick 7941475Smckusick #define USER 040 /* (XXX from trap.c) user-mode flag in type */ 8041475Smckusick 8141475Smckusick /* 8241475Smckusick * BUFMAX defines the maximum number of characters in inbound/outbound 8341475Smckusick * buffers. At least NUMREGBYTES*2 are needed for register packets. 8441475Smckusick */ 8541475Smckusick #define BUFMAX 512 8641475Smckusick 8742367Smckusick #ifndef KGDBDEV 8842367Smckusick #define KGDBDEV -1 8942367Smckusick #endif 9042367Smckusick #ifndef KGDBRATE 9142367Smckusick #define KGDBRATE 9600 9242367Smckusick #endif 9342367Smckusick 9442367Smckusick int kgdb_dev = KGDBDEV; /* remote debugging device (-1 if none) */ 9542367Smckusick int kgdb_rate = KGDBRATE; /* remote debugging baud rate */ 9641475Smckusick int kgdb_debug_init = 0; /* != 0 waits for remote at system init */ 9741475Smckusick int kgdb_debug = 0; /* > 0 prints command & checksum errors */ 9841475Smckusick 9942367Smckusick #include "../hp300/cons.h" 10041475Smckusick 10142367Smckusick #define GETC \ 10242367Smckusick (constab[major(kgdb_dev)].cn_getc ? \ 10342367Smckusick (*constab[major(kgdb_dev)].cn_getc)(kgdb_dev) : 0) 10442367Smckusick #define PUTC(c) { \ 10542367Smckusick if (constab[major(kgdb_dev)].cn_putc) \ 10642367Smckusick (*constab[major(kgdb_dev)].cn_putc)(kgdb_dev, c); \ 10742367Smckusick } 10842367Smckusick 10941475Smckusick static char hexchars[] = "0123456789abcdef"; 11041475Smckusick 11141475Smckusick /* 11241475Smckusick * There are 180 bytes of registers on a 68020 w/68881. Many of the fpa 11341475Smckusick * registers are 12 byte (96 bit) registers. 11441475Smckusick */ 11541475Smckusick #define NUMREGBYTES 180 11641475Smckusick 11741475Smckusick static char inbuffer[BUFMAX]; 11841475Smckusick static char outbuffer[BUFMAX]; 11941475Smckusick 12041475Smckusick static inline int 12141475Smckusick hex(ch) 12241475Smckusick char ch; 12341475Smckusick { 12441475Smckusick if ((ch >= '0') && (ch <= '9')) 12541475Smckusick return (ch - '0'); 12641475Smckusick if ((ch >= 'a') && (ch <= 'f')) 12741475Smckusick return (ch - ('a' - 10)); 12841475Smckusick return (0); 12941475Smckusick } 13041475Smckusick 13141475Smckusick /* scan for the sequence $<data>#<checksum> */ 13241475Smckusick static void 13341475Smckusick getpacket(char *buffer) 13441475Smckusick { 13541475Smckusick unsigned char checksum; 13641475Smckusick unsigned char xmitcsum; 13741475Smckusick int i; 13841475Smckusick int count; 13941475Smckusick char ch; 14041475Smckusick 14141475Smckusick do { 14241475Smckusick /* 14341475Smckusick * wait around for the start character, ignore all other 14441475Smckusick * characters 14541475Smckusick */ 14641475Smckusick while ((ch = GETC) != '$') 14741475Smckusick ; 14841475Smckusick checksum = 0; 14941475Smckusick count = 0; 15041475Smckusick xmitcsum = 1; 15141475Smckusick 15241475Smckusick /* now, read until a # or end of buffer is found */ 15341475Smckusick while (count < BUFMAX) { 15441475Smckusick ch = GETC; 15541475Smckusick if (ch == '#') 15641475Smckusick break; 15741475Smckusick checksum = checksum + ch; 15841475Smckusick buffer[count] = ch; 15941475Smckusick count = count + 1; 16041475Smckusick } 16141475Smckusick buffer[count] = 0; 16241475Smckusick 16341475Smckusick if (ch == '#') { 16441475Smckusick xmitcsum = hex(GETC) << 4; 16541475Smckusick xmitcsum += hex(GETC); 16641475Smckusick if (kgdb_debug && (checksum != xmitcsum)) { 16741475Smckusick printf( 16841475Smckusick "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", 16941475Smckusick checksum, xmitcsum, buffer); 17041475Smckusick } 17142367Smckusick if (checksum != xmitcsum) { 17241475Smckusick PUTC('-'); /* failed checksum */ 17342367Smckusick } else { 17441475Smckusick PUTC('+'); /* successful transfer */ 17541475Smckusick /* 17641475Smckusick * if a sequence char is present, reply the 17741475Smckusick * sequence ID 17841475Smckusick */ 17941475Smckusick if (buffer[2] == ':') { 18041475Smckusick PUTC(buffer[0]); 18141475Smckusick PUTC(buffer[1]); 18241475Smckusick /* remove sequence chars from buffer */ 18341475Smckusick for (i = 3; i <= count; ++i) 18441475Smckusick buffer[i - 3] = buffer[i]; 18541475Smckusick } 18641475Smckusick } 18741475Smckusick } 18841475Smckusick } while (checksum != xmitcsum); 18941475Smckusick } 19041475Smckusick 19141475Smckusick /* 19241475Smckusick * send the packet in buffer. The host gets one chance to read it. This 19341475Smckusick * routine does not wait for a positive acknowledge. 19441475Smckusick */ 19541475Smckusick static void 19641475Smckusick putpacket(char *buffer) 19741475Smckusick { 19841475Smckusick unsigned char checksum; 19941475Smckusick int count; 20041475Smckusick char ch; 20141475Smckusick 20241475Smckusick /* $<packet info>#<checksum>. */ 20341475Smckusick do { 20441475Smckusick PUTC('$'); 20541475Smckusick checksum = 0; 20641475Smckusick count = 0; 20741475Smckusick 20841475Smckusick while (ch = buffer[count]) { 20941475Smckusick PUTC(ch); 21041475Smckusick checksum += ch; 21141475Smckusick count += 1; 21241475Smckusick } 21341475Smckusick PUTC('#'); 21441475Smckusick PUTC(hexchars[checksum >> 4]); 21541475Smckusick PUTC(hexchars[checksum & 15]); 21641475Smckusick 21741475Smckusick } while (0); /* (GETC != '+'); */ 21841475Smckusick 21941475Smckusick } 22041475Smckusick 22141475Smckusick static inline void 22241475Smckusick debug_error(char *format, char *parm) 22341475Smckusick { 22441475Smckusick if (kgdb_debug) 22541475Smckusick printf(format, parm); 22641475Smckusick } 22741475Smckusick 22841475Smckusick /* 22941475Smckusick * Convert at most 'dig' digits of hex data in buf into a value. 23041475Smckusick * Stop on non-hex char. Return a pointer to next char in buf. 23141475Smckusick */ 23241475Smckusick static char * 23341475Smckusick hex2val(char *buf, int *val, int dig) 23441475Smckusick { 23541475Smckusick int i, v; 23641475Smckusick char ch; 23741475Smckusick 23841475Smckusick v = 0; 23941475Smckusick for (i = dig; --i >= 0; ) { 24041475Smckusick ch = *buf++; 24141475Smckusick if ((ch >= '0') && (ch <= '9')) 24241475Smckusick v = (v << 4) | (ch - '0'); 24341475Smckusick else if ((ch >= 'a') && (ch <= 'f')) 24441475Smckusick v = (v << 4) | (ch - ('a' - 10)); 24541475Smckusick else { 24641475Smckusick --buf; 24741475Smckusick break; 24841475Smckusick } 24941475Smckusick } 25041475Smckusick *val = v; 25141475Smckusick return (buf); 25241475Smckusick } 25341475Smckusick 25441475Smckusick /* 25541475Smckusick * convert the integer value 'val' into 'dig' hex digits, placing 25641475Smckusick * result in buf. Return a pointer to the last char put in buf (null). 25741475Smckusick */ 25841475Smckusick static char * 25941475Smckusick val2hex(char *buf, int val, int dig) 26041475Smckusick { 26141475Smckusick for (dig <<= 2; (dig -= 4) >= 0; ) 26241475Smckusick *buf++ = hexchars[(val >> dig) & 0xf]; 26341475Smckusick *buf = 0; 26441475Smckusick return (buf); 26541475Smckusick } 26641475Smckusick 26741475Smckusick /* 26841475Smckusick * convert the memory pointed to by mem into hex, placing result in buf. 26941475Smckusick * return a pointer to the last char put in buf (null). 27041475Smckusick */ 27141475Smckusick static char * 27241475Smckusick mem2hex(char *buf, char *mem, int count) 27341475Smckusick { 27441475Smckusick if ((count & 1) || ((int)mem & 1)) { 27541475Smckusick char ch; 27641475Smckusick 27741475Smckusick while(--count >= 0) { 27841475Smckusick ch = *mem++; 27941475Smckusick *buf++ = hexchars[ch >> 4]; 28041475Smckusick *buf++ = hexchars[ch & 15]; 28141475Smckusick } 28241475Smckusick } else { 28341475Smckusick u_short s; 28441475Smckusick u_short *mp = (u_short *)mem; 28541475Smckusick 28641475Smckusick for (count >>= 1; --count >= 0; ) { 28741475Smckusick s = *mp++; 28841475Smckusick *buf++ = hexchars[(s >> 12) & 15]; 28941475Smckusick *buf++ = hexchars[(s >> 8) & 15]; 29041475Smckusick *buf++ = hexchars[(s >> 4) & 15]; 29141475Smckusick *buf++ = hexchars[s & 15]; 29241475Smckusick } 29341475Smckusick } 29441475Smckusick *buf = 0; 29541475Smckusick return (buf); 29641475Smckusick } 29741475Smckusick 29841475Smckusick /* 29941475Smckusick * Convert the hex array pointed to by buf into binary to be placed in mem. 30041475Smckusick * Return a pointer to next char in buf. 30141475Smckusick */ 30241475Smckusick static char * 30341475Smckusick hex2mem(char *buf, char *mem, int count) 30441475Smckusick { 30541475Smckusick int i; 30641475Smckusick unsigned char ch; 30741475Smckusick 30841475Smckusick for (i = 0; i < count; ++i) { 30941475Smckusick ch = hex(*buf++) << 4; 31041475Smckusick ch = ch + hex(*buf++); 31141475Smckusick *mem++ = ch; 31241475Smckusick } 31341475Smckusick return (buf); 31441475Smckusick } 31541475Smckusick 31641475Smckusick /* 31741475Smckusick * Translate a trap number into a unix compatible signal value. 31841475Smckusick * (gdb only understands unix signal numbers). 31941475Smckusick */ 32041475Smckusick static int 32141475Smckusick computeSignal(int type) 32241475Smckusick { 32341475Smckusick int sigval; 32441475Smckusick 32541475Smckusick switch (type &~ USER) { 32641475Smckusick case T_BUSERR: 32741475Smckusick sigval = SIGBUS; 32841475Smckusick break; /* bus error */ 32941475Smckusick case T_ADDRERR: 33041475Smckusick sigval = SIGBUS; 33141475Smckusick break; /* address error */ 33241475Smckusick case T_ILLINST: 33341475Smckusick sigval = SIGILL; 33441475Smckusick break; /* illegal instruction */ 33541475Smckusick case T_ZERODIV: 33641475Smckusick sigval = SIGFPE; 33741475Smckusick break; /* zero divide */ 33841475Smckusick case T_CHKINST: 33941475Smckusick sigval = SIGFPE; 34041475Smckusick break; /* chk instruction */ 34141475Smckusick case T_TRAPVINST: 34241475Smckusick sigval = SIGFPE; 34341475Smckusick break; /* trapv instruction */ 34441475Smckusick case T_PRIVINST: 34541475Smckusick sigval = SIGILL; 34641475Smckusick break; /* privilege violation */ 34741475Smckusick case T_TRACE: 34841475Smckusick sigval = SIGTRAP; 34941475Smckusick break; /* trace trap */ 35041475Smckusick case T_MMUFLT: 35141475Smckusick sigval = SIGSEGV; 35241475Smckusick break; 35341475Smckusick case T_SSIR: 35441475Smckusick sigval = SIGSEGV; 35541475Smckusick break; 35641475Smckusick case T_FMTERR: 35741475Smckusick sigval = SIGILL; 35841475Smckusick break; 35941475Smckusick case T_FPERR: 36041475Smckusick sigval = SIGFPE; 36141475Smckusick break; 36241475Smckusick case T_COPERR: 36341475Smckusick sigval = SIGFPE; 36441475Smckusick break; 365*43413Shibler case T_ASTFLT: 36641475Smckusick sigval = SIGINT; 36741475Smckusick break; 36841475Smckusick case T_TRAP15: 36941475Smckusick sigval = SIGIOT; 37041475Smckusick break; 37141475Smckusick default: 37241475Smckusick sigval = SIGEMT; 37341475Smckusick break; 37441475Smckusick } 37541475Smckusick return (sigval); 37641475Smckusick } 37741475Smckusick 37841475Smckusick #define RESPOND(str) (bcopy(str, outbuffer, sizeof(str))) 37941475Smckusick 38041475Smckusick /* 38141475Smckusick * This function does all command procesing for interfacing to 38241475Smckusick * a remote gdb. 38341475Smckusick */ 38441475Smckusick int 38541475Smckusick kgdb_trap(int type, unsigned code, unsigned v, struct frame *frame) 38641475Smckusick { 38741475Smckusick int sigval; 38841475Smckusick int addr, length; 38941475Smckusick char *ptr; 39041475Smckusick 39141475Smckusick if (kgdb_dev < 0) 39241475Smckusick /* not debugging */ 39341475Smckusick return (0); 39441475Smckusick 39541475Smckusick if (kgdb_debug) 39641475Smckusick printf("type=%d, code=%d, vector=0x%x, pc=0x%x, sr=0x%x\n", 39741475Smckusick type, code, frame->f_vector, frame->f_pc, frame->f_sr); 39841475Smckusick 39941475Smckusick /* reply to host that an exception has occurred */ 40041475Smckusick sigval = computeSignal(type); 40141475Smckusick outbuffer[0] = 'S'; 40241475Smckusick (void)val2hex(&outbuffer[1], sigval, 2); 40341475Smckusick putpacket(outbuffer); 40441475Smckusick 40541475Smckusick while (1) { 40641475Smckusick outbuffer[0] = 0; 40741475Smckusick getpacket(inbuffer); 40841475Smckusick ptr = inbuffer; 40941475Smckusick switch (*ptr++) { 41041475Smckusick case '?': 41141475Smckusick outbuffer[0] = 'S'; 41241475Smckusick (void)val2hex(&outbuffer[1], sigval, 2); 41341475Smckusick break; 41441475Smckusick case 'g': /* return the value of the CPU registers */ 41541475Smckusick ptr = outbuffer; 41641475Smckusick if (type & USER) 41741475Smckusick ptr = mem2hex(ptr, (char *)frame->f_regs, 41841475Smckusick sizeof(frame->f_regs)); 41941475Smckusick else { 42041475Smckusick ptr = mem2hex(ptr, (char *)frame->f_regs, 42141475Smckusick sizeof(frame->f_regs) - 4); 42241475Smckusick addr = (int)&frame->f_pc - 42341475Smckusick frame_bytes[frame->f_format]; 42441475Smckusick ptr = mem2hex(ptr, (char *)&addr, sizeof(addr)); 42541475Smckusick } 42641475Smckusick addr = frame->f_sr; 42741475Smckusick ptr = mem2hex(ptr, (char *)&addr, sizeof(addr)); 42841475Smckusick ptr = mem2hex(ptr, (char *)&frame->f_pc, 42941475Smckusick sizeof(frame->f_pc)); 43041475Smckusick break; 43141475Smckusick case 'G': /* set the value of the CPU registers */ 43241475Smckusick ptr = hex2mem(ptr, (char *)frame->f_regs, 43341475Smckusick sizeof(frame->f_regs) - 4); 43441475Smckusick ptr = hex2mem(ptr, (char *)&addr, sizeof(addr)); 43541475Smckusick ptr = hex2mem(ptr, (char *)&addr, sizeof(addr)); 43641475Smckusick frame->f_sr = addr; 43741475Smckusick ptr = hex2mem(ptr, (char *)&frame->f_pc, 43841475Smckusick sizeof(frame->f_pc)); 43941475Smckusick RESPOND("OK"); 44041475Smckusick break; 44141475Smckusick 44241475Smckusick /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ 44341475Smckusick case 'm': 44441475Smckusick ptr = hex2val(ptr, &addr, 8); 44541475Smckusick if (*ptr++ != ',') { 44641475Smckusick RESPOND("E01"); 44741475Smckusick debug_error("malformed read memory cmd: %s\n", 44841475Smckusick inbuffer); 44941475Smckusick break; 45041475Smckusick } 45141475Smckusick ptr = hex2val(ptr, &length, 8); 45241475Smckusick if (length <= 0 || length >= BUFMAX*2) { 45341475Smckusick RESPOND("E02"); 45441475Smckusick if (kgdb_debug) 45541475Smckusick printf("bad read memory length: %d\n", 45641475Smckusick length); 45741475Smckusick break; 45841475Smckusick } 45941475Smckusick if (! kernacc(addr, length, B_READ)) { 46041475Smckusick RESPOND("E03"); 46141475Smckusick if (kgdb_debug) 46241475Smckusick printf("read access violation addr 0x%x len %d\n", addr, length); 46341475Smckusick break; 46441475Smckusick } 46541475Smckusick (void)mem2hex(outbuffer, (char *)addr, length); 46641475Smckusick break; 46741475Smckusick 46841475Smckusick /* 46941475Smckusick * MAA..AA,LLLL: Write LLLL bytes at address AA.AA 47041475Smckusick * return OK 47141475Smckusick */ 47241475Smckusick case 'M': 47341475Smckusick ptr = hex2val(ptr, &addr, 8); 47441475Smckusick if (*ptr++ != ',') { 47541475Smckusick RESPOND("E01"); 47641475Smckusick debug_error("malformed write memory cmd: %s\n", 47741475Smckusick inbuffer); 47841475Smckusick break; 47941475Smckusick } 48041475Smckusick ptr = hex2val(ptr, &length, 8); 48141475Smckusick if (*ptr++ != ':') { 48241475Smckusick RESPOND("E01"); 48341475Smckusick debug_error("malformed write memory cmd: %s\n", 48441475Smckusick inbuffer); 48541475Smckusick break; 48641475Smckusick } 48741475Smckusick if (length <= 0 || length >= BUFMAX*2 - 32) { 48841475Smckusick RESPOND("E02"); 48941475Smckusick if (kgdb_debug) 49041475Smckusick printf("bad write memory length: %d\n", 49141475Smckusick length); 49241475Smckusick break; 49341475Smckusick } 49441475Smckusick if (! kernacc(addr, length, B_READ)) { 49541475Smckusick RESPOND("E03"); 49641475Smckusick if (kgdb_debug) 49741475Smckusick printf("write access violation addr 0x%x len %d\n", addr, length); 49841475Smckusick break; 49941475Smckusick } 50041475Smckusick if (! kernacc(addr, length, B_WRITE)) 50141475Smckusick chgkprot(addr, length, B_WRITE); 50241475Smckusick (void)hex2mem(ptr, (char *)addr, length); 50341475Smckusick RESPOND("OK"); 50441475Smckusick break; 50541475Smckusick 50641475Smckusick /* 50741475Smckusick * cAA..AA Continue at address AA..AA 50841475Smckusick * sAA..AA Step one instruction from AA..AA 50941475Smckusick * (addresses optional) 51041475Smckusick */ 51141475Smckusick case 'c': 51241475Smckusick case 's': 51341475Smckusick /* 51441475Smckusick * try to read optional start address. 51541475Smckusick */ 51641475Smckusick if (ptr != hex2val(ptr, &addr, 8)) { 51741475Smckusick frame->f_pc = addr; 51841475Smckusick if (kgdb_debug) 51941475Smckusick printf("new pc = 0x%x\n", addr); 52041475Smckusick } 52141475Smckusick /* deal with the trace bit */ 52241475Smckusick if (inbuffer[0] == 's') 52341475Smckusick frame->f_sr |= PSL_T; 52441475Smckusick else 52541475Smckusick frame->f_sr &=~ PSL_T; 52641475Smckusick 52741475Smckusick if (kgdb_debug) 52841475Smckusick printf("restarting at 0x%x\n", frame->f_pc); 52941475Smckusick 53041475Smckusick return (1); 53141475Smckusick 53241475Smckusick /* kill the program (same as continue for now) */ 53341475Smckusick case 'k': 53441475Smckusick return (1); 53541475Smckusick } 53641475Smckusick /* reply to the request */ 53741475Smckusick putpacket(outbuffer); 53841475Smckusick } 53941475Smckusick } 54041475Smckusick #endif 541