1 /*- 2 * Copyright (c) 2004 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/ctype.h> 33 #include <sys/kdb.h> 34 35 #include <machine/gdb_machdep.h> 36 37 #include <gdb/gdb.h> 38 #include <gdb/gdb_int.h> 39 40 static char gdb_rxbuf[GDB_BUFSZ]; 41 char *gdb_rxp = NULL; 42 size_t gdb_rxsz = 0; 43 static char gdb_txbuf[GDB_BUFSZ]; 44 char *gdb_txp = NULL; /* Used in inline functions. */ 45 46 #define C2N(c) (((c) < 'A') ? (c) - '0' : \ 47 10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a')) 48 #define N2C(n) (((n) < 10) ? (n) + '0' : (n) + 'a' - 10) 49 50 /* 51 * Functions to receive and extract from a packet. 52 */ 53 54 int 55 gdb_rx_begin(void) 56 { 57 int c, cksum; 58 59 gdb_rxp = NULL; 60 do { 61 /* 62 * Wait for the start character, ignore all others. 63 * XXX needs a timeout. 64 */ 65 while ((c = gdb_cur->gdb_getc()) != '$') 66 ; 67 68 /* Read until a # or end of buffer is found. */ 69 cksum = 0; 70 gdb_rxsz = 0; 71 while (gdb_rxsz < sizeof(gdb_rxbuf) - 1) { 72 c = gdb_cur->gdb_getc(); 73 if (c == '#') 74 break; 75 gdb_rxbuf[gdb_rxsz++] = c; 76 cksum += c; 77 } 78 gdb_rxbuf[gdb_rxsz] = 0; 79 cksum &= 0xff; 80 81 /* Bail out on a buffer overflow. */ 82 if (c != '#') { 83 gdb_cur->gdb_putc('-'); 84 return (ENOSPC); 85 } 86 87 c = gdb_cur->gdb_getc(); 88 cksum -= (C2N(c) << 4) & 0xf0; 89 c = gdb_cur->gdb_getc(); 90 cksum -= C2N(c) & 0x0f; 91 gdb_cur->gdb_putc((cksum == 0) ? '+' : '-'); 92 if (cksum != 0) 93 printf("GDB: packet `%s' has invalid checksum\n", 94 gdb_rxbuf); 95 } while (cksum != 0); 96 97 gdb_rxp = gdb_rxbuf; 98 return (0); 99 } 100 101 int 102 gdb_rx_equal(const char *str) 103 { 104 int len; 105 106 len = strlen(str); 107 if (len > gdb_rxsz || strncmp(str, gdb_rxp, len) != 0) 108 return (0); 109 gdb_rxp += len; 110 gdb_rxsz -= len; 111 return (1); 112 } 113 114 int 115 gdb_rx_mem(unsigned char *addr, size_t size) 116 { 117 void *prev; 118 jmp_buf jb; 119 int ret; 120 unsigned char c; 121 122 if (size * 2 != gdb_rxsz) 123 return (-1); 124 125 prev = kdb_jmpbuf(jb); 126 ret = setjmp(jb); 127 if (ret == 0) { 128 while (size-- > 0) { 129 c = (C2N(gdb_rxp[0]) << 4) & 0xf0; 130 c |= C2N(gdb_rxp[1]) & 0x0f; 131 *addr++ = c; 132 gdb_rxsz -= 2; 133 gdb_rxp += 2; 134 } 135 } 136 (void)kdb_jmpbuf(prev); 137 return ((ret == 0) ? 1 : 0); 138 } 139 140 int 141 gdb_rx_varhex(uintmax_t *vp) 142 { 143 uintmax_t v; 144 int c, neg; 145 146 c = gdb_rx_char(); 147 neg = (c == '-') ? 1 : 0; 148 if (neg == 1) 149 c = gdb_rx_char(); 150 if (!isxdigit(c)) { 151 gdb_rxp -= ((c == -1) ? 0 : 1) + neg; 152 gdb_rxsz += ((c == -1) ? 0 : 1) + neg; 153 return (-1); 154 } 155 v = 0; 156 do { 157 v <<= 4; 158 v += C2N(c); 159 c = gdb_rx_char(); 160 } while (isxdigit(c)); 161 if (c != -1) { 162 gdb_rxp--; 163 gdb_rxsz++; 164 } 165 *vp = (neg) ? -v : v; 166 return (0); 167 } 168 169 /* 170 * Function to build and send a package. 171 */ 172 173 void 174 gdb_tx_begin(char tp) 175 { 176 177 gdb_txp = gdb_txbuf; 178 if (tp != '\0') 179 gdb_tx_char(tp); 180 } 181 182 int 183 gdb_tx_end(void) 184 { 185 const char *p; 186 int runlen; 187 unsigned char c, cksum; 188 189 do { 190 gdb_cur->gdb_putc('$'); 191 192 cksum = 0; 193 p = gdb_txbuf; 194 while (p < gdb_txp) { 195 /* Send a character and start run-length encoding. */ 196 c = *p++; 197 gdb_cur->gdb_putc(c); 198 cksum += c; 199 runlen = 0; 200 /* Determine run-length and update checksum. */ 201 while (p < gdb_txp && *p == c) { 202 runlen++; 203 p++; 204 } 205 /* Emit the run-length encoded string. */ 206 while (runlen >= 97) { 207 gdb_cur->gdb_putc('*'); 208 cksum += '*'; 209 gdb_cur->gdb_putc(97+29); 210 cksum += 97+29; 211 runlen -= 97; 212 if (runlen > 0) { 213 gdb_cur->gdb_putc(c); 214 cksum += c; 215 runlen--; 216 } 217 } 218 if (runlen == 1) { 219 gdb_cur->gdb_putc(c); 220 cksum += c; 221 runlen--; 222 } 223 if (runlen == 0) 224 continue; 225 /* Don't emit '$', '#', '+' or '-'. */ 226 if (runlen == 7) { 227 gdb_cur->gdb_putc(c); 228 cksum += c; 229 runlen--; 230 } 231 if (runlen == 6 || runlen == 14 || runlen == 16) { 232 gdb_cur->gdb_putc(c); 233 cksum += c; 234 runlen--; 235 } 236 gdb_cur->gdb_putc('*'); 237 cksum += '*'; 238 gdb_cur->gdb_putc(runlen+29); 239 cksum += runlen+29; 240 } 241 242 gdb_cur->gdb_putc('#'); 243 c = cksum >> 4; 244 gdb_cur->gdb_putc(N2C(c)); 245 c = cksum & 0x0f; 246 gdb_cur->gdb_putc(N2C(c)); 247 248 c = gdb_cur->gdb_getc(); 249 } while (c != '+'); 250 251 return (0); 252 } 253 254 int 255 gdb_tx_mem(const unsigned char *addr, size_t size) 256 { 257 void *prev; 258 jmp_buf jb; 259 int ret; 260 261 prev = kdb_jmpbuf(jb); 262 ret = setjmp(jb); 263 if (ret == 0) { 264 while (size-- > 0) { 265 *gdb_txp++ = N2C(*addr >> 4); 266 *gdb_txp++ = N2C(*addr & 0x0f); 267 addr++; 268 } 269 } 270 (void)kdb_jmpbuf(prev); 271 return ((ret == 0) ? 1 : 0); 272 } 273 274 void 275 gdb_tx_reg(int regnum) 276 { 277 unsigned char *regp; 278 size_t regsz; 279 280 regp = gdb_cpu_getreg(regnum, ®sz); 281 if (regp == NULL) { 282 /* Register unavailable. */ 283 while (regsz--) { 284 gdb_tx_char('x'); 285 gdb_tx_char('x'); 286 } 287 } else 288 gdb_tx_mem(regp, regsz); 289 } 290