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 #include <sys/libkern.h> 35 #include <sys/ttydefaults.h> 36 37 #include <machine/gdb_machdep.h> 38 #include <machine/kdb.h> 39 40 #include <gdb/gdb.h> 41 #include <gdb/gdb_int.h> 42 43 static char gdb_rxbuf[GDB_BUFSZ]; 44 char *gdb_rxp = NULL; 45 size_t gdb_rxsz = 0; 46 static char gdb_txbuf[GDB_BUFSZ]; 47 char *gdb_txp = NULL; /* Used in inline functions. */ 48 49 #define C2N(c) (((c) < 'A') ? (c) - '0' : \ 50 10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a')) 51 #define N2C(n) (((n) < 10) ? (n) + '0' : (n) + 'a' - 10) 52 53 /* 54 * Get a single character 55 */ 56 57 static int 58 gdb_getc(void) 59 { 60 int c; 61 62 do 63 c = gdb_cur->gdb_getc(); 64 while (c == -1); 65 66 if (c == CTRL('C')) { 67 printf("Received ^C; trying to switch back to ddb.\n"); 68 69 if (kdb_dbbe_select("ddb") != 0) 70 printf("The ddb backend could not be selected.\n"); 71 else { 72 printf("using longjmp, hope it works!\n"); 73 kdb_reenter(); 74 } 75 } 76 return (c); 77 } 78 79 /* 80 * Functions to receive and extract from a packet. 81 */ 82 83 int 84 gdb_rx_begin(void) 85 { 86 int c, cksum; 87 88 gdb_rxp = NULL; 89 do { 90 /* 91 * Wait for the start character, ignore all others. 92 * XXX needs a timeout. 93 */ 94 while ((c = gdb_getc()) != '$') 95 ; 96 97 /* Read until a # or end of buffer is found. */ 98 cksum = 0; 99 gdb_rxsz = 0; 100 while (gdb_rxsz < sizeof(gdb_rxbuf) - 1) { 101 c = gdb_getc(); 102 if (c == '#') 103 break; 104 gdb_rxbuf[gdb_rxsz++] = c; 105 cksum += c; 106 } 107 gdb_rxbuf[gdb_rxsz] = 0; 108 cksum &= 0xff; 109 110 /* Bail out on a buffer overflow. */ 111 if (c != '#') { 112 gdb_cur->gdb_putc('-'); 113 return (ENOSPC); 114 } 115 116 c = gdb_getc(); 117 cksum -= (C2N(c) << 4) & 0xf0; 118 c = gdb_getc(); 119 cksum -= C2N(c) & 0x0f; 120 gdb_cur->gdb_putc((cksum == 0) ? '+' : '-'); 121 if (cksum != 0) 122 printf("GDB: packet `%s' has invalid checksum\n", 123 gdb_rxbuf); 124 } while (cksum != 0); 125 126 gdb_rxp = gdb_rxbuf; 127 return (0); 128 } 129 130 int 131 gdb_rx_equal(const char *str) 132 { 133 int len; 134 135 len = strlen(str); 136 if (len > gdb_rxsz || strncmp(str, gdb_rxp, len) != 0) 137 return (0); 138 gdb_rxp += len; 139 gdb_rxsz -= len; 140 return (1); 141 } 142 143 int 144 gdb_rx_mem(unsigned char *addr, size_t size) 145 { 146 unsigned char *p; 147 void *prev; 148 jmp_buf jb; 149 size_t cnt; 150 int ret; 151 unsigned char c; 152 153 if (size * 2 != gdb_rxsz) 154 return (-1); 155 156 prev = kdb_jmpbuf(jb); 157 ret = setjmp(jb); 158 if (ret == 0) { 159 p = addr; 160 cnt = size; 161 while (cnt-- > 0) { 162 c = (C2N(gdb_rxp[0]) << 4) & 0xf0; 163 c |= C2N(gdb_rxp[1]) & 0x0f; 164 *p++ = c; 165 gdb_rxsz -= 2; 166 gdb_rxp += 2; 167 } 168 kdb_cpu_sync_icache(addr, size); 169 } 170 (void)kdb_jmpbuf(prev); 171 return ((ret == 0) ? 1 : 0); 172 } 173 174 int 175 gdb_rx_varhex(uintmax_t *vp) 176 { 177 uintmax_t v; 178 int c, neg; 179 180 c = gdb_rx_char(); 181 neg = (c == '-') ? 1 : 0; 182 if (neg == 1) 183 c = gdb_rx_char(); 184 if (!isxdigit(c)) { 185 gdb_rxp -= ((c == -1) ? 0 : 1) + neg; 186 gdb_rxsz += ((c == -1) ? 0 : 1) + neg; 187 return (-1); 188 } 189 v = 0; 190 do { 191 v <<= 4; 192 v += C2N(c); 193 c = gdb_rx_char(); 194 } while (isxdigit(c)); 195 if (c != -1) { 196 gdb_rxp--; 197 gdb_rxsz++; 198 } 199 *vp = (neg) ? -v : v; 200 return (0); 201 } 202 203 /* 204 * Function to build and send a package. 205 */ 206 207 void 208 gdb_tx_begin(char tp) 209 { 210 211 gdb_txp = gdb_txbuf; 212 if (tp != '\0') 213 gdb_tx_char(tp); 214 } 215 216 int 217 gdb_tx_end(void) 218 { 219 const char *p; 220 int runlen; 221 unsigned char c, cksum; 222 223 do { 224 gdb_cur->gdb_putc('$'); 225 226 cksum = 0; 227 p = gdb_txbuf; 228 while (p < gdb_txp) { 229 /* Send a character and start run-length encoding. */ 230 c = *p++; 231 gdb_cur->gdb_putc(c); 232 cksum += c; 233 runlen = 0; 234 /* Determine run-length and update checksum. */ 235 while (p < gdb_txp && *p == c) { 236 runlen++; 237 p++; 238 } 239 /* Emit the run-length encoded string. */ 240 while (runlen >= 97) { 241 gdb_cur->gdb_putc('*'); 242 cksum += '*'; 243 gdb_cur->gdb_putc(97+29); 244 cksum += 97+29; 245 runlen -= 97; 246 if (runlen > 0) { 247 gdb_cur->gdb_putc(c); 248 cksum += c; 249 runlen--; 250 } 251 } 252 if (runlen == 1) { 253 gdb_cur->gdb_putc(c); 254 cksum += c; 255 runlen--; 256 } 257 if (runlen == 0) 258 continue; 259 /* Don't emit '$', '#', '+' or '-'. */ 260 if (runlen == 7) { 261 gdb_cur->gdb_putc(c); 262 cksum += c; 263 runlen--; 264 } 265 if (runlen == 6 || runlen == 14 || runlen == 16) { 266 gdb_cur->gdb_putc(c); 267 cksum += c; 268 runlen--; 269 } 270 gdb_cur->gdb_putc('*'); 271 cksum += '*'; 272 gdb_cur->gdb_putc(runlen+29); 273 cksum += runlen+29; 274 } 275 276 gdb_cur->gdb_putc('#'); 277 c = cksum >> 4; 278 gdb_cur->gdb_putc(N2C(c)); 279 c = cksum & 0x0f; 280 gdb_cur->gdb_putc(N2C(c)); 281 282 c = gdb_getc(); 283 } while (c != '+'); 284 285 return (0); 286 } 287 288 int 289 gdb_tx_mem(const unsigned char *addr, size_t size) 290 { 291 void *prev; 292 jmp_buf jb; 293 int ret; 294 295 prev = kdb_jmpbuf(jb); 296 ret = setjmp(jb); 297 if (ret == 0) { 298 while (size-- > 0) { 299 *gdb_txp++ = N2C(*addr >> 4); 300 *gdb_txp++ = N2C(*addr & 0x0f); 301 addr++; 302 } 303 } 304 (void)kdb_jmpbuf(prev); 305 return ((ret == 0) ? 1 : 0); 306 } 307 308 void 309 gdb_tx_reg(int regnum) 310 { 311 unsigned char *regp; 312 size_t regsz; 313 314 regp = gdb_cpu_getreg(regnum, ®sz); 315 if (regp == NULL) { 316 /* Register unavailable. */ 317 while (regsz--) { 318 gdb_tx_char('x'); 319 gdb_tx_char('x'); 320 } 321 } else 322 gdb_tx_mem(regp, regsz); 323 } 324 325 /* Read binary data up until the end of the packet or until we have datalen decoded bytes */ 326 int 327 gdb_rx_bindata(unsigned char *data, size_t datalen, size_t *amt) 328 { 329 int c; 330 331 *amt = 0; 332 333 while (*amt < datalen) { 334 c = gdb_rx_char(); 335 /* End of packet? */ 336 if (c == -1) 337 break; 338 /* Escaped character up next */ 339 if (c == '}') { 340 /* Truncated packet? Bail out */ 341 if ((c = gdb_rx_char()) == -1) 342 return (1); 343 c ^= 0x20; 344 } 345 *(data++) = c & 0xff; 346 (*amt)++; 347 } 348 349 return (0); 350 } 351 352 int 353 gdb_search_mem(const unsigned char *addr, size_t size, const unsigned char *pat, size_t patlen, const unsigned char **found) 354 { 355 void *prev; 356 jmp_buf jb; 357 int ret; 358 359 prev = kdb_jmpbuf(jb); 360 ret = setjmp(jb); 361 if (ret == 0) 362 *found = memmem(addr, size, pat, patlen); 363 364 (void)kdb_jmpbuf(prev); 365 return ((ret == 0) ? 1 : 0); 366 } 367