1fa521b03SWarner Losh /*- 272d44f31SMarcel Moolenaar * Copyright (c) 2004 Marcel Moolenaar 372d44f31SMarcel Moolenaar * All rights reserved. 472d44f31SMarcel Moolenaar * 572d44f31SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 672d44f31SMarcel Moolenaar * modification, are permitted provided that the following conditions 772d44f31SMarcel Moolenaar * are met: 872d44f31SMarcel Moolenaar * 972d44f31SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 1072d44f31SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 1172d44f31SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 1272d44f31SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 1372d44f31SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 1472d44f31SMarcel Moolenaar * 1572d44f31SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1672d44f31SMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1772d44f31SMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1872d44f31SMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1972d44f31SMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2072d44f31SMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2172d44f31SMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2272d44f31SMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2372d44f31SMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2472d44f31SMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2572d44f31SMarcel Moolenaar */ 2672d44f31SMarcel Moolenaar 2772d44f31SMarcel Moolenaar #include <sys/cdefs.h> 2872d44f31SMarcel Moolenaar __FBSDID("$FreeBSD$"); 2972d44f31SMarcel Moolenaar 3072d44f31SMarcel Moolenaar #include <sys/param.h> 3172d44f31SMarcel Moolenaar #include <sys/systm.h> 3272d44f31SMarcel Moolenaar #include <sys/ctype.h> 3372d44f31SMarcel Moolenaar #include <sys/kdb.h> 34*27ecc2adSBenno Rice #include <sys/libkern.h> 353a5d3671SMatthew D Fleming #include <sys/ttydefaults.h> 3672d44f31SMarcel Moolenaar 3772d44f31SMarcel Moolenaar #include <machine/gdb_machdep.h> 3801bd17ccSMarcel Moolenaar #include <machine/kdb.h> 3972d44f31SMarcel Moolenaar 4072d44f31SMarcel Moolenaar #include <gdb/gdb.h> 4172d44f31SMarcel Moolenaar #include <gdb/gdb_int.h> 4272d44f31SMarcel Moolenaar 4372d44f31SMarcel Moolenaar static char gdb_rxbuf[GDB_BUFSZ]; 4472d44f31SMarcel Moolenaar char *gdb_rxp = NULL; 4572d44f31SMarcel Moolenaar size_t gdb_rxsz = 0; 4672d44f31SMarcel Moolenaar static char gdb_txbuf[GDB_BUFSZ]; 4772d44f31SMarcel Moolenaar char *gdb_txp = NULL; /* Used in inline functions. */ 4872d44f31SMarcel Moolenaar 4972d44f31SMarcel Moolenaar #define C2N(c) (((c) < 'A') ? (c) - '0' : \ 5072d44f31SMarcel Moolenaar 10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a')) 5172d44f31SMarcel Moolenaar #define N2C(n) (((n) < 10) ? (n) + '0' : (n) + 'a' - 10) 5272d44f31SMarcel Moolenaar 5372d44f31SMarcel Moolenaar /* 54f346afc4SPoul-Henning Kamp * Get a single character 55f346afc4SPoul-Henning Kamp */ 56f346afc4SPoul-Henning Kamp 57f346afc4SPoul-Henning Kamp static int 58f346afc4SPoul-Henning Kamp gdb_getc(void) 59f346afc4SPoul-Henning Kamp { 60f346afc4SPoul-Henning Kamp int c; 61f346afc4SPoul-Henning Kamp 62f346afc4SPoul-Henning Kamp do 63f346afc4SPoul-Henning Kamp c = gdb_cur->gdb_getc(); 64f346afc4SPoul-Henning Kamp while (c == -1); 653a5d3671SMatthew D Fleming 663a5d3671SMatthew D Fleming if (c == CTRL('C')) { 673a5d3671SMatthew D Fleming printf("Received ^C; trying to switch back to ddb.\n"); 683a5d3671SMatthew D Fleming 693a5d3671SMatthew D Fleming if (kdb_dbbe_select("ddb") != 0) 703a5d3671SMatthew D Fleming printf("The ddb backend could not be selected.\n"); 713a5d3671SMatthew D Fleming else { 723a5d3671SMatthew D Fleming printf("using longjmp, hope it works!\n"); 733a5d3671SMatthew D Fleming kdb_reenter(); 743a5d3671SMatthew D Fleming } 753a5d3671SMatthew D Fleming } 76f346afc4SPoul-Henning Kamp return (c); 77f346afc4SPoul-Henning Kamp } 78f346afc4SPoul-Henning Kamp 79f346afc4SPoul-Henning Kamp /* 8072d44f31SMarcel Moolenaar * Functions to receive and extract from a packet. 8172d44f31SMarcel Moolenaar */ 8272d44f31SMarcel Moolenaar 8372d44f31SMarcel Moolenaar int 8472d44f31SMarcel Moolenaar gdb_rx_begin(void) 8572d44f31SMarcel Moolenaar { 8672d44f31SMarcel Moolenaar int c, cksum; 8772d44f31SMarcel Moolenaar 8872d44f31SMarcel Moolenaar gdb_rxp = NULL; 8972d44f31SMarcel Moolenaar do { 9072d44f31SMarcel Moolenaar /* 9172d44f31SMarcel Moolenaar * Wait for the start character, ignore all others. 9272d44f31SMarcel Moolenaar * XXX needs a timeout. 9372d44f31SMarcel Moolenaar */ 94f346afc4SPoul-Henning Kamp while ((c = gdb_getc()) != '$') 9572d44f31SMarcel Moolenaar ; 9672d44f31SMarcel Moolenaar 9772d44f31SMarcel Moolenaar /* Read until a # or end of buffer is found. */ 9872d44f31SMarcel Moolenaar cksum = 0; 9972d44f31SMarcel Moolenaar gdb_rxsz = 0; 10072d44f31SMarcel Moolenaar while (gdb_rxsz < sizeof(gdb_rxbuf) - 1) { 101f346afc4SPoul-Henning Kamp c = gdb_getc(); 10272d44f31SMarcel Moolenaar if (c == '#') 10372d44f31SMarcel Moolenaar break; 10472d44f31SMarcel Moolenaar gdb_rxbuf[gdb_rxsz++] = c; 10572d44f31SMarcel Moolenaar cksum += c; 10672d44f31SMarcel Moolenaar } 10772d44f31SMarcel Moolenaar gdb_rxbuf[gdb_rxsz] = 0; 10872d44f31SMarcel Moolenaar cksum &= 0xff; 10972d44f31SMarcel Moolenaar 11072d44f31SMarcel Moolenaar /* Bail out on a buffer overflow. */ 11172d44f31SMarcel Moolenaar if (c != '#') { 11272d44f31SMarcel Moolenaar gdb_cur->gdb_putc('-'); 11372d44f31SMarcel Moolenaar return (ENOSPC); 11472d44f31SMarcel Moolenaar } 11572d44f31SMarcel Moolenaar 116f346afc4SPoul-Henning Kamp c = gdb_getc(); 11772d44f31SMarcel Moolenaar cksum -= (C2N(c) << 4) & 0xf0; 118f346afc4SPoul-Henning Kamp c = gdb_getc(); 11972d44f31SMarcel Moolenaar cksum -= C2N(c) & 0x0f; 12072d44f31SMarcel Moolenaar gdb_cur->gdb_putc((cksum == 0) ? '+' : '-'); 12172d44f31SMarcel Moolenaar if (cksum != 0) 12272d44f31SMarcel Moolenaar printf("GDB: packet `%s' has invalid checksum\n", 12372d44f31SMarcel Moolenaar gdb_rxbuf); 12472d44f31SMarcel Moolenaar } while (cksum != 0); 12572d44f31SMarcel Moolenaar 12672d44f31SMarcel Moolenaar gdb_rxp = gdb_rxbuf; 12772d44f31SMarcel Moolenaar return (0); 12872d44f31SMarcel Moolenaar } 12972d44f31SMarcel Moolenaar 13072d44f31SMarcel Moolenaar int 13172d44f31SMarcel Moolenaar gdb_rx_equal(const char *str) 13272d44f31SMarcel Moolenaar { 13372d44f31SMarcel Moolenaar int len; 13472d44f31SMarcel Moolenaar 13572d44f31SMarcel Moolenaar len = strlen(str); 13672d44f31SMarcel Moolenaar if (len > gdb_rxsz || strncmp(str, gdb_rxp, len) != 0) 13772d44f31SMarcel Moolenaar return (0); 13872d44f31SMarcel Moolenaar gdb_rxp += len; 13972d44f31SMarcel Moolenaar gdb_rxsz -= len; 14072d44f31SMarcel Moolenaar return (1); 14172d44f31SMarcel Moolenaar } 14272d44f31SMarcel Moolenaar 14372d44f31SMarcel Moolenaar int 14472d44f31SMarcel Moolenaar gdb_rx_mem(unsigned char *addr, size_t size) 14572d44f31SMarcel Moolenaar { 14601bd17ccSMarcel Moolenaar unsigned char *p; 14772d44f31SMarcel Moolenaar void *prev; 14872d44f31SMarcel Moolenaar jmp_buf jb; 14901bd17ccSMarcel Moolenaar size_t cnt; 15072d44f31SMarcel Moolenaar int ret; 15172d44f31SMarcel Moolenaar unsigned char c; 15272d44f31SMarcel Moolenaar 15372d44f31SMarcel Moolenaar if (size * 2 != gdb_rxsz) 15472d44f31SMarcel Moolenaar return (-1); 15572d44f31SMarcel Moolenaar 15672d44f31SMarcel Moolenaar prev = kdb_jmpbuf(jb); 15772d44f31SMarcel Moolenaar ret = setjmp(jb); 15872d44f31SMarcel Moolenaar if (ret == 0) { 15901bd17ccSMarcel Moolenaar p = addr; 16001bd17ccSMarcel Moolenaar cnt = size; 16101bd17ccSMarcel Moolenaar while (cnt-- > 0) { 16272d44f31SMarcel Moolenaar c = (C2N(gdb_rxp[0]) << 4) & 0xf0; 16372d44f31SMarcel Moolenaar c |= C2N(gdb_rxp[1]) & 0x0f; 16401bd17ccSMarcel Moolenaar *p++ = c; 16572d44f31SMarcel Moolenaar gdb_rxsz -= 2; 16672d44f31SMarcel Moolenaar gdb_rxp += 2; 16772d44f31SMarcel Moolenaar } 16801bd17ccSMarcel Moolenaar kdb_cpu_sync_icache(addr, size); 16972d44f31SMarcel Moolenaar } 17072d44f31SMarcel Moolenaar (void)kdb_jmpbuf(prev); 17172d44f31SMarcel Moolenaar return ((ret == 0) ? 1 : 0); 17272d44f31SMarcel Moolenaar } 17372d44f31SMarcel Moolenaar 17472d44f31SMarcel Moolenaar int 17572d44f31SMarcel Moolenaar gdb_rx_varhex(uintmax_t *vp) 17672d44f31SMarcel Moolenaar { 17772d44f31SMarcel Moolenaar uintmax_t v; 17872d44f31SMarcel Moolenaar int c, neg; 17972d44f31SMarcel Moolenaar 18072d44f31SMarcel Moolenaar c = gdb_rx_char(); 18172d44f31SMarcel Moolenaar neg = (c == '-') ? 1 : 0; 18272d44f31SMarcel Moolenaar if (neg == 1) 18372d44f31SMarcel Moolenaar c = gdb_rx_char(); 18472d44f31SMarcel Moolenaar if (!isxdigit(c)) { 18572d44f31SMarcel Moolenaar gdb_rxp -= ((c == -1) ? 0 : 1) + neg; 18672d44f31SMarcel Moolenaar gdb_rxsz += ((c == -1) ? 0 : 1) + neg; 18772d44f31SMarcel Moolenaar return (-1); 18872d44f31SMarcel Moolenaar } 18972d44f31SMarcel Moolenaar v = 0; 19072d44f31SMarcel Moolenaar do { 19172d44f31SMarcel Moolenaar v <<= 4; 19272d44f31SMarcel Moolenaar v += C2N(c); 19372d44f31SMarcel Moolenaar c = gdb_rx_char(); 19472d44f31SMarcel Moolenaar } while (isxdigit(c)); 19572d44f31SMarcel Moolenaar if (c != -1) { 19672d44f31SMarcel Moolenaar gdb_rxp--; 19772d44f31SMarcel Moolenaar gdb_rxsz++; 19872d44f31SMarcel Moolenaar } 19972d44f31SMarcel Moolenaar *vp = (neg) ? -v : v; 20072d44f31SMarcel Moolenaar return (0); 20172d44f31SMarcel Moolenaar } 20272d44f31SMarcel Moolenaar 20372d44f31SMarcel Moolenaar /* 20472d44f31SMarcel Moolenaar * Function to build and send a package. 20572d44f31SMarcel Moolenaar */ 20672d44f31SMarcel Moolenaar 20772d44f31SMarcel Moolenaar void 20872d44f31SMarcel Moolenaar gdb_tx_begin(char tp) 20972d44f31SMarcel Moolenaar { 21072d44f31SMarcel Moolenaar 21172d44f31SMarcel Moolenaar gdb_txp = gdb_txbuf; 21272d44f31SMarcel Moolenaar if (tp != '\0') 21372d44f31SMarcel Moolenaar gdb_tx_char(tp); 21472d44f31SMarcel Moolenaar } 21572d44f31SMarcel Moolenaar 21672d44f31SMarcel Moolenaar int 21772d44f31SMarcel Moolenaar gdb_tx_end(void) 21872d44f31SMarcel Moolenaar { 21972d44f31SMarcel Moolenaar const char *p; 22072d44f31SMarcel Moolenaar int runlen; 22172d44f31SMarcel Moolenaar unsigned char c, cksum; 22272d44f31SMarcel Moolenaar 22372d44f31SMarcel Moolenaar do { 22472d44f31SMarcel Moolenaar gdb_cur->gdb_putc('$'); 22572d44f31SMarcel Moolenaar 22672d44f31SMarcel Moolenaar cksum = 0; 22772d44f31SMarcel Moolenaar p = gdb_txbuf; 22872d44f31SMarcel Moolenaar while (p < gdb_txp) { 22972d44f31SMarcel Moolenaar /* Send a character and start run-length encoding. */ 23072d44f31SMarcel Moolenaar c = *p++; 23172d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 23272d44f31SMarcel Moolenaar cksum += c; 23372d44f31SMarcel Moolenaar runlen = 0; 23472d44f31SMarcel Moolenaar /* Determine run-length and update checksum. */ 23572d44f31SMarcel Moolenaar while (p < gdb_txp && *p == c) { 23672d44f31SMarcel Moolenaar runlen++; 23772d44f31SMarcel Moolenaar p++; 23872d44f31SMarcel Moolenaar } 23972d44f31SMarcel Moolenaar /* Emit the run-length encoded string. */ 24072d44f31SMarcel Moolenaar while (runlen >= 97) { 24172d44f31SMarcel Moolenaar gdb_cur->gdb_putc('*'); 24272d44f31SMarcel Moolenaar cksum += '*'; 24372d44f31SMarcel Moolenaar gdb_cur->gdb_putc(97+29); 24472d44f31SMarcel Moolenaar cksum += 97+29; 24572d44f31SMarcel Moolenaar runlen -= 97; 24672d44f31SMarcel Moolenaar if (runlen > 0) { 24772d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 24872d44f31SMarcel Moolenaar cksum += c; 24972d44f31SMarcel Moolenaar runlen--; 25072d44f31SMarcel Moolenaar } 25172d44f31SMarcel Moolenaar } 25272d44f31SMarcel Moolenaar if (runlen == 1) { 25372d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 25472d44f31SMarcel Moolenaar cksum += c; 25572d44f31SMarcel Moolenaar runlen--; 25672d44f31SMarcel Moolenaar } 25772d44f31SMarcel Moolenaar if (runlen == 0) 25872d44f31SMarcel Moolenaar continue; 25972d44f31SMarcel Moolenaar /* Don't emit '$', '#', '+' or '-'. */ 26072d44f31SMarcel Moolenaar if (runlen == 7) { 26172d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 26272d44f31SMarcel Moolenaar cksum += c; 26372d44f31SMarcel Moolenaar runlen--; 26472d44f31SMarcel Moolenaar } 26572d44f31SMarcel Moolenaar if (runlen == 6 || runlen == 14 || runlen == 16) { 26672d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 26772d44f31SMarcel Moolenaar cksum += c; 26872d44f31SMarcel Moolenaar runlen--; 26972d44f31SMarcel Moolenaar } 27072d44f31SMarcel Moolenaar gdb_cur->gdb_putc('*'); 27172d44f31SMarcel Moolenaar cksum += '*'; 27272d44f31SMarcel Moolenaar gdb_cur->gdb_putc(runlen+29); 27372d44f31SMarcel Moolenaar cksum += runlen+29; 27472d44f31SMarcel Moolenaar } 27572d44f31SMarcel Moolenaar 27672d44f31SMarcel Moolenaar gdb_cur->gdb_putc('#'); 27772d44f31SMarcel Moolenaar c = cksum >> 4; 27872d44f31SMarcel Moolenaar gdb_cur->gdb_putc(N2C(c)); 27972d44f31SMarcel Moolenaar c = cksum & 0x0f; 28072d44f31SMarcel Moolenaar gdb_cur->gdb_putc(N2C(c)); 28172d44f31SMarcel Moolenaar 282f346afc4SPoul-Henning Kamp c = gdb_getc(); 28372d44f31SMarcel Moolenaar } while (c != '+'); 28472d44f31SMarcel Moolenaar 28572d44f31SMarcel Moolenaar return (0); 28672d44f31SMarcel Moolenaar } 28772d44f31SMarcel Moolenaar 28872d44f31SMarcel Moolenaar int 28972d44f31SMarcel Moolenaar gdb_tx_mem(const unsigned char *addr, size_t size) 29072d44f31SMarcel Moolenaar { 29172d44f31SMarcel Moolenaar void *prev; 29272d44f31SMarcel Moolenaar jmp_buf jb; 29372d44f31SMarcel Moolenaar int ret; 29472d44f31SMarcel Moolenaar 29572d44f31SMarcel Moolenaar prev = kdb_jmpbuf(jb); 29672d44f31SMarcel Moolenaar ret = setjmp(jb); 29772d44f31SMarcel Moolenaar if (ret == 0) { 29872d44f31SMarcel Moolenaar while (size-- > 0) { 29972d44f31SMarcel Moolenaar *gdb_txp++ = N2C(*addr >> 4); 30072d44f31SMarcel Moolenaar *gdb_txp++ = N2C(*addr & 0x0f); 30172d44f31SMarcel Moolenaar addr++; 30272d44f31SMarcel Moolenaar } 30372d44f31SMarcel Moolenaar } 30472d44f31SMarcel Moolenaar (void)kdb_jmpbuf(prev); 30572d44f31SMarcel Moolenaar return ((ret == 0) ? 1 : 0); 30672d44f31SMarcel Moolenaar } 30772d44f31SMarcel Moolenaar 30872d44f31SMarcel Moolenaar void 30972d44f31SMarcel Moolenaar gdb_tx_reg(int regnum) 31072d44f31SMarcel Moolenaar { 31172d44f31SMarcel Moolenaar unsigned char *regp; 31272d44f31SMarcel Moolenaar size_t regsz; 31372d44f31SMarcel Moolenaar 31472d44f31SMarcel Moolenaar regp = gdb_cpu_getreg(regnum, ®sz); 31572d44f31SMarcel Moolenaar if (regp == NULL) { 31672d44f31SMarcel Moolenaar /* Register unavailable. */ 31772d44f31SMarcel Moolenaar while (regsz--) { 31872d44f31SMarcel Moolenaar gdb_tx_char('x'); 31972d44f31SMarcel Moolenaar gdb_tx_char('x'); 32072d44f31SMarcel Moolenaar } 32172d44f31SMarcel Moolenaar } else 32272d44f31SMarcel Moolenaar gdb_tx_mem(regp, regsz); 32372d44f31SMarcel Moolenaar } 324*27ecc2adSBenno Rice 325*27ecc2adSBenno Rice /* Read binary data up until the end of the packet or until we have datalen decoded bytes */ 326*27ecc2adSBenno Rice int 327*27ecc2adSBenno Rice gdb_rx_bindata(unsigned char *data, size_t datalen, size_t *amt) 328*27ecc2adSBenno Rice { 329*27ecc2adSBenno Rice int c; 330*27ecc2adSBenno Rice 331*27ecc2adSBenno Rice *amt = 0; 332*27ecc2adSBenno Rice 333*27ecc2adSBenno Rice while (*amt < datalen) { 334*27ecc2adSBenno Rice c = gdb_rx_char(); 335*27ecc2adSBenno Rice /* End of packet? */ 336*27ecc2adSBenno Rice if (c == -1) 337*27ecc2adSBenno Rice break; 338*27ecc2adSBenno Rice /* Escaped character up next */ 339*27ecc2adSBenno Rice if (c == '}') { 340*27ecc2adSBenno Rice /* Truncated packet? Bail out */ 341*27ecc2adSBenno Rice if ((c = gdb_rx_char()) == -1) 342*27ecc2adSBenno Rice return (1); 343*27ecc2adSBenno Rice c ^= 0x20; 344*27ecc2adSBenno Rice } 345*27ecc2adSBenno Rice *(data++) = c & 0xff; 346*27ecc2adSBenno Rice (*amt)++; 347*27ecc2adSBenno Rice } 348*27ecc2adSBenno Rice 349*27ecc2adSBenno Rice return (0); 350*27ecc2adSBenno Rice } 351*27ecc2adSBenno Rice 352*27ecc2adSBenno Rice int 353*27ecc2adSBenno Rice gdb_search_mem(const unsigned char *addr, size_t size, const unsigned char *pat, size_t patlen, const unsigned char **found) 354*27ecc2adSBenno Rice { 355*27ecc2adSBenno Rice void *prev; 356*27ecc2adSBenno Rice jmp_buf jb; 357*27ecc2adSBenno Rice int ret; 358*27ecc2adSBenno Rice 359*27ecc2adSBenno Rice prev = kdb_jmpbuf(jb); 360*27ecc2adSBenno Rice ret = setjmp(jb); 361*27ecc2adSBenno Rice if (ret == 0) 362*27ecc2adSBenno Rice *found = memmem(addr, size, pat, patlen); 363*27ecc2adSBenno Rice 364*27ecc2adSBenno Rice (void)kdb_jmpbuf(prev); 365*27ecc2adSBenno Rice return ((ret == 0) ? 1 : 0); 366*27ecc2adSBenno Rice } 367