1139778Simp/*- 2131899Smarcel * Copyright (c) 2004 Marcel Moolenaar 3131899Smarcel * All rights reserved. 4131899Smarcel * 5131899Smarcel * Redistribution and use in source and binary forms, with or without 6131899Smarcel * modification, are permitted provided that the following conditions 7131899Smarcel * are met: 8131899Smarcel * 9131899Smarcel * 1. Redistributions of source code must retain the above copyright 10131899Smarcel * notice, this list of conditions and the following disclaimer. 11131899Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12131899Smarcel * notice, this list of conditions and the following disclaimer in the 13131899Smarcel * documentation and/or other materials provided with the distribution. 14131899Smarcel * 15131899Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16131899Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17131899Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18131899Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19131899Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20131899Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21131899Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22131899Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23131899Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24131899Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25131899Smarcel */ 26131899Smarcel 27131899Smarcel#include <sys/cdefs.h> 28131899Smarcel__FBSDID("$FreeBSD$"); 29131899Smarcel 30131899Smarcel#include <sys/param.h> 31131899Smarcel#include <sys/systm.h> 32131899Smarcel#include <sys/ctype.h> 33131899Smarcel#include <sys/kdb.h> 34218825Smdf#include <sys/ttydefaults.h> 35131899Smarcel 36131899Smarcel#include <machine/gdb_machdep.h> 37170473Smarcel#include <machine/kdb.h> 38131899Smarcel 39131899Smarcel#include <gdb/gdb.h> 40131899Smarcel#include <gdb/gdb_int.h> 41131899Smarcel 42131899Smarcelstatic char gdb_rxbuf[GDB_BUFSZ]; 43131899Smarcelchar *gdb_rxp = NULL; 44131899Smarcelsize_t gdb_rxsz = 0; 45131899Smarcelstatic char gdb_txbuf[GDB_BUFSZ]; 46131899Smarcelchar *gdb_txp = NULL; /* Used in inline functions. */ 47131899Smarcel 48131899Smarcel#define C2N(c) (((c) < 'A') ? (c) - '0' : \ 49131899Smarcel 10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a')) 50131899Smarcel#define N2C(n) (((n) < 10) ? (n) + '0' : (n) + 'a' - 10) 51131899Smarcel 52131899Smarcel/* 53158948Sphk * Get a single character 54158948Sphk */ 55158948Sphk 56158948Sphkstatic int 57158948Sphkgdb_getc(void) 58158948Sphk{ 59158948Sphk int c; 60158948Sphk 61158948Sphk do 62158948Sphk c = gdb_cur->gdb_getc(); 63158948Sphk while (c == -1); 64218825Smdf 65218825Smdf if (c == CTRL('C')) { 66218825Smdf printf("Received ^C; trying to switch back to ddb.\n"); 67218825Smdf 68218825Smdf if (kdb_dbbe_select("ddb") != 0) 69218825Smdf printf("The ddb backend could not be selected.\n"); 70218825Smdf else { 71218825Smdf printf("using longjmp, hope it works!\n"); 72218825Smdf kdb_reenter(); 73218825Smdf } 74218825Smdf } 75158948Sphk return (c); 76158948Sphk} 77158948Sphk 78158948Sphk/* 79131899Smarcel * Functions to receive and extract from a packet. 80131899Smarcel */ 81131899Smarcel 82131899Smarcelint 83131899Smarcelgdb_rx_begin(void) 84131899Smarcel{ 85131899Smarcel int c, cksum; 86131899Smarcel 87131899Smarcel gdb_rxp = NULL; 88131899Smarcel do { 89131899Smarcel /* 90131899Smarcel * Wait for the start character, ignore all others. 91131899Smarcel * XXX needs a timeout. 92131899Smarcel */ 93158948Sphk while ((c = gdb_getc()) != '$') 94131899Smarcel ; 95131899Smarcel 96131899Smarcel /* Read until a # or end of buffer is found. */ 97131899Smarcel cksum = 0; 98131899Smarcel gdb_rxsz = 0; 99131899Smarcel while (gdb_rxsz < sizeof(gdb_rxbuf) - 1) { 100158948Sphk c = gdb_getc(); 101131899Smarcel if (c == '#') 102131899Smarcel break; 103131899Smarcel gdb_rxbuf[gdb_rxsz++] = c; 104131899Smarcel cksum += c; 105131899Smarcel } 106131899Smarcel gdb_rxbuf[gdb_rxsz] = 0; 107131899Smarcel cksum &= 0xff; 108131899Smarcel 109131899Smarcel /* Bail out on a buffer overflow. */ 110131899Smarcel if (c != '#') { 111131899Smarcel gdb_cur->gdb_putc('-'); 112131899Smarcel return (ENOSPC); 113131899Smarcel } 114131899Smarcel 115158948Sphk c = gdb_getc(); 116131899Smarcel cksum -= (C2N(c) << 4) & 0xf0; 117158948Sphk c = gdb_getc(); 118131899Smarcel cksum -= C2N(c) & 0x0f; 119131899Smarcel gdb_cur->gdb_putc((cksum == 0) ? '+' : '-'); 120131899Smarcel if (cksum != 0) 121131899Smarcel printf("GDB: packet `%s' has invalid checksum\n", 122131899Smarcel gdb_rxbuf); 123131899Smarcel } while (cksum != 0); 124131899Smarcel 125131899Smarcel gdb_rxp = gdb_rxbuf; 126131899Smarcel return (0); 127131899Smarcel} 128131899Smarcel 129131899Smarcelint 130131899Smarcelgdb_rx_equal(const char *str) 131131899Smarcel{ 132131899Smarcel int len; 133131899Smarcel 134131899Smarcel len = strlen(str); 135131899Smarcel if (len > gdb_rxsz || strncmp(str, gdb_rxp, len) != 0) 136131899Smarcel return (0); 137131899Smarcel gdb_rxp += len; 138131899Smarcel gdb_rxsz -= len; 139131899Smarcel return (1); 140131899Smarcel} 141131899Smarcel 142131899Smarcelint 143131899Smarcelgdb_rx_mem(unsigned char *addr, size_t size) 144131899Smarcel{ 145170473Smarcel unsigned char *p; 146131899Smarcel void *prev; 147131899Smarcel jmp_buf jb; 148170473Smarcel size_t cnt; 149131899Smarcel int ret; 150131899Smarcel unsigned char c; 151131899Smarcel 152131899Smarcel if (size * 2 != gdb_rxsz) 153131899Smarcel return (-1); 154131899Smarcel 155131899Smarcel prev = kdb_jmpbuf(jb); 156131899Smarcel ret = setjmp(jb); 157131899Smarcel if (ret == 0) { 158170473Smarcel p = addr; 159170473Smarcel cnt = size; 160170473Smarcel while (cnt-- > 0) { 161131899Smarcel c = (C2N(gdb_rxp[0]) << 4) & 0xf0; 162131899Smarcel c |= C2N(gdb_rxp[1]) & 0x0f; 163170473Smarcel *p++ = c; 164131899Smarcel gdb_rxsz -= 2; 165131899Smarcel gdb_rxp += 2; 166131899Smarcel } 167170473Smarcel kdb_cpu_sync_icache(addr, size); 168131899Smarcel } 169131899Smarcel (void)kdb_jmpbuf(prev); 170131899Smarcel return ((ret == 0) ? 1 : 0); 171131899Smarcel} 172131899Smarcel 173131899Smarcelint 174131899Smarcelgdb_rx_varhex(uintmax_t *vp) 175131899Smarcel{ 176131899Smarcel uintmax_t v; 177131899Smarcel int c, neg; 178131899Smarcel 179131899Smarcel c = gdb_rx_char(); 180131899Smarcel neg = (c == '-') ? 1 : 0; 181131899Smarcel if (neg == 1) 182131899Smarcel c = gdb_rx_char(); 183131899Smarcel if (!isxdigit(c)) { 184131899Smarcel gdb_rxp -= ((c == -1) ? 0 : 1) + neg; 185131899Smarcel gdb_rxsz += ((c == -1) ? 0 : 1) + neg; 186131899Smarcel return (-1); 187131899Smarcel } 188131899Smarcel v = 0; 189131899Smarcel do { 190131899Smarcel v <<= 4; 191131899Smarcel v += C2N(c); 192131899Smarcel c = gdb_rx_char(); 193131899Smarcel } while (isxdigit(c)); 194131899Smarcel if (c != -1) { 195131899Smarcel gdb_rxp--; 196131899Smarcel gdb_rxsz++; 197131899Smarcel } 198131899Smarcel *vp = (neg) ? -v : v; 199131899Smarcel return (0); 200131899Smarcel} 201131899Smarcel 202131899Smarcel/* 203131899Smarcel * Function to build and send a package. 204131899Smarcel */ 205131899Smarcel 206131899Smarcelvoid 207131899Smarcelgdb_tx_begin(char tp) 208131899Smarcel{ 209131899Smarcel 210131899Smarcel gdb_txp = gdb_txbuf; 211131899Smarcel if (tp != '\0') 212131899Smarcel gdb_tx_char(tp); 213131899Smarcel} 214131899Smarcel 215131899Smarcelint 216131899Smarcelgdb_tx_end(void) 217131899Smarcel{ 218131899Smarcel const char *p; 219131899Smarcel int runlen; 220131899Smarcel unsigned char c, cksum; 221131899Smarcel 222131899Smarcel do { 223131899Smarcel gdb_cur->gdb_putc('$'); 224131899Smarcel 225131899Smarcel cksum = 0; 226131899Smarcel p = gdb_txbuf; 227131899Smarcel while (p < gdb_txp) { 228131899Smarcel /* Send a character and start run-length encoding. */ 229131899Smarcel c = *p++; 230131899Smarcel gdb_cur->gdb_putc(c); 231131899Smarcel cksum += c; 232131899Smarcel runlen = 0; 233131899Smarcel /* Determine run-length and update checksum. */ 234131899Smarcel while (p < gdb_txp && *p == c) { 235131899Smarcel runlen++; 236131899Smarcel p++; 237131899Smarcel } 238131899Smarcel /* Emit the run-length encoded string. */ 239131899Smarcel while (runlen >= 97) { 240131899Smarcel gdb_cur->gdb_putc('*'); 241131899Smarcel cksum += '*'; 242131899Smarcel gdb_cur->gdb_putc(97+29); 243131899Smarcel cksum += 97+29; 244131899Smarcel runlen -= 97; 245131899Smarcel if (runlen > 0) { 246131899Smarcel gdb_cur->gdb_putc(c); 247131899Smarcel cksum += c; 248131899Smarcel runlen--; 249131899Smarcel } 250131899Smarcel } 251131899Smarcel if (runlen == 1) { 252131899Smarcel gdb_cur->gdb_putc(c); 253131899Smarcel cksum += c; 254131899Smarcel runlen--; 255131899Smarcel } 256131899Smarcel if (runlen == 0) 257131899Smarcel continue; 258131899Smarcel /* Don't emit '$', '#', '+' or '-'. */ 259131899Smarcel if (runlen == 7) { 260131899Smarcel gdb_cur->gdb_putc(c); 261131899Smarcel cksum += c; 262131899Smarcel runlen--; 263131899Smarcel } 264131899Smarcel if (runlen == 6 || runlen == 14 || runlen == 16) { 265131899Smarcel gdb_cur->gdb_putc(c); 266131899Smarcel cksum += c; 267131899Smarcel runlen--; 268131899Smarcel } 269131899Smarcel gdb_cur->gdb_putc('*'); 270131899Smarcel cksum += '*'; 271131899Smarcel gdb_cur->gdb_putc(runlen+29); 272131899Smarcel cksum += runlen+29; 273131899Smarcel } 274131899Smarcel 275131899Smarcel gdb_cur->gdb_putc('#'); 276131899Smarcel c = cksum >> 4; 277131899Smarcel gdb_cur->gdb_putc(N2C(c)); 278131899Smarcel c = cksum & 0x0f; 279131899Smarcel gdb_cur->gdb_putc(N2C(c)); 280131899Smarcel 281158948Sphk c = gdb_getc(); 282131899Smarcel } while (c != '+'); 283131899Smarcel 284131899Smarcel return (0); 285131899Smarcel} 286131899Smarcel 287131899Smarcelint 288131899Smarcelgdb_tx_mem(const unsigned char *addr, size_t size) 289131899Smarcel{ 290131899Smarcel void *prev; 291131899Smarcel jmp_buf jb; 292131899Smarcel int ret; 293131899Smarcel 294131899Smarcel prev = kdb_jmpbuf(jb); 295131899Smarcel ret = setjmp(jb); 296131899Smarcel if (ret == 0) { 297131899Smarcel while (size-- > 0) { 298131899Smarcel *gdb_txp++ = N2C(*addr >> 4); 299131899Smarcel *gdb_txp++ = N2C(*addr & 0x0f); 300131899Smarcel addr++; 301131899Smarcel } 302131899Smarcel } 303131899Smarcel (void)kdb_jmpbuf(prev); 304131899Smarcel return ((ret == 0) ? 1 : 0); 305131899Smarcel} 306131899Smarcel 307131899Smarcelvoid 308131899Smarcelgdb_tx_reg(int regnum) 309131899Smarcel{ 310131899Smarcel unsigned char *regp; 311131899Smarcel size_t regsz; 312131899Smarcel 313131899Smarcel regp = gdb_cpu_getreg(regnum, ®sz); 314131899Smarcel if (regp == NULL) { 315131899Smarcel /* Register unavailable. */ 316131899Smarcel while (regsz--) { 317131899Smarcel gdb_tx_char('x'); 318131899Smarcel gdb_tx_char('x'); 319131899Smarcel } 320131899Smarcel } else 321131899Smarcel gdb_tx_mem(regp, regsz); 322131899Smarcel} 323