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*3a5d3671SMatthew D Fleming #include <sys/ttydefaults.h> 3572d44f31SMarcel Moolenaar 3672d44f31SMarcel Moolenaar #include <machine/gdb_machdep.h> 3701bd17ccSMarcel Moolenaar #include <machine/kdb.h> 3872d44f31SMarcel Moolenaar 3972d44f31SMarcel Moolenaar #include <gdb/gdb.h> 4072d44f31SMarcel Moolenaar #include <gdb/gdb_int.h> 4172d44f31SMarcel Moolenaar 4272d44f31SMarcel Moolenaar static char gdb_rxbuf[GDB_BUFSZ]; 4372d44f31SMarcel Moolenaar char *gdb_rxp = NULL; 4472d44f31SMarcel Moolenaar size_t gdb_rxsz = 0; 4572d44f31SMarcel Moolenaar static char gdb_txbuf[GDB_BUFSZ]; 4672d44f31SMarcel Moolenaar char *gdb_txp = NULL; /* Used in inline functions. */ 4772d44f31SMarcel Moolenaar 4872d44f31SMarcel Moolenaar #define C2N(c) (((c) < 'A') ? (c) - '0' : \ 4972d44f31SMarcel Moolenaar 10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a')) 5072d44f31SMarcel Moolenaar #define N2C(n) (((n) < 10) ? (n) + '0' : (n) + 'a' - 10) 5172d44f31SMarcel Moolenaar 5272d44f31SMarcel Moolenaar /* 53f346afc4SPoul-Henning Kamp * Get a single character 54f346afc4SPoul-Henning Kamp */ 55f346afc4SPoul-Henning Kamp 56f346afc4SPoul-Henning Kamp static int 57f346afc4SPoul-Henning Kamp gdb_getc(void) 58f346afc4SPoul-Henning Kamp { 59f346afc4SPoul-Henning Kamp int c; 60f346afc4SPoul-Henning Kamp 61f346afc4SPoul-Henning Kamp do 62f346afc4SPoul-Henning Kamp c = gdb_cur->gdb_getc(); 63f346afc4SPoul-Henning Kamp while (c == -1); 64*3a5d3671SMatthew D Fleming 65*3a5d3671SMatthew D Fleming if (c == CTRL('C')) { 66*3a5d3671SMatthew D Fleming printf("Received ^C; trying to switch back to ddb.\n"); 67*3a5d3671SMatthew D Fleming 68*3a5d3671SMatthew D Fleming if (kdb_dbbe_select("ddb") != 0) 69*3a5d3671SMatthew D Fleming printf("The ddb backend could not be selected.\n"); 70*3a5d3671SMatthew D Fleming else { 71*3a5d3671SMatthew D Fleming printf("using longjmp, hope it works!\n"); 72*3a5d3671SMatthew D Fleming kdb_reenter(); 73*3a5d3671SMatthew D Fleming } 74*3a5d3671SMatthew D Fleming } 75f346afc4SPoul-Henning Kamp return (c); 76f346afc4SPoul-Henning Kamp } 77f346afc4SPoul-Henning Kamp 78f346afc4SPoul-Henning Kamp /* 7972d44f31SMarcel Moolenaar * Functions to receive and extract from a packet. 8072d44f31SMarcel Moolenaar */ 8172d44f31SMarcel Moolenaar 8272d44f31SMarcel Moolenaar int 8372d44f31SMarcel Moolenaar gdb_rx_begin(void) 8472d44f31SMarcel Moolenaar { 8572d44f31SMarcel Moolenaar int c, cksum; 8672d44f31SMarcel Moolenaar 8772d44f31SMarcel Moolenaar gdb_rxp = NULL; 8872d44f31SMarcel Moolenaar do { 8972d44f31SMarcel Moolenaar /* 9072d44f31SMarcel Moolenaar * Wait for the start character, ignore all others. 9172d44f31SMarcel Moolenaar * XXX needs a timeout. 9272d44f31SMarcel Moolenaar */ 93f346afc4SPoul-Henning Kamp while ((c = gdb_getc()) != '$') 9472d44f31SMarcel Moolenaar ; 9572d44f31SMarcel Moolenaar 9672d44f31SMarcel Moolenaar /* Read until a # or end of buffer is found. */ 9772d44f31SMarcel Moolenaar cksum = 0; 9872d44f31SMarcel Moolenaar gdb_rxsz = 0; 9972d44f31SMarcel Moolenaar while (gdb_rxsz < sizeof(gdb_rxbuf) - 1) { 100f346afc4SPoul-Henning Kamp c = gdb_getc(); 10172d44f31SMarcel Moolenaar if (c == '#') 10272d44f31SMarcel Moolenaar break; 10372d44f31SMarcel Moolenaar gdb_rxbuf[gdb_rxsz++] = c; 10472d44f31SMarcel Moolenaar cksum += c; 10572d44f31SMarcel Moolenaar } 10672d44f31SMarcel Moolenaar gdb_rxbuf[gdb_rxsz] = 0; 10772d44f31SMarcel Moolenaar cksum &= 0xff; 10872d44f31SMarcel Moolenaar 10972d44f31SMarcel Moolenaar /* Bail out on a buffer overflow. */ 11072d44f31SMarcel Moolenaar if (c != '#') { 11172d44f31SMarcel Moolenaar gdb_cur->gdb_putc('-'); 11272d44f31SMarcel Moolenaar return (ENOSPC); 11372d44f31SMarcel Moolenaar } 11472d44f31SMarcel Moolenaar 115f346afc4SPoul-Henning Kamp c = gdb_getc(); 11672d44f31SMarcel Moolenaar cksum -= (C2N(c) << 4) & 0xf0; 117f346afc4SPoul-Henning Kamp c = gdb_getc(); 11872d44f31SMarcel Moolenaar cksum -= C2N(c) & 0x0f; 11972d44f31SMarcel Moolenaar gdb_cur->gdb_putc((cksum == 0) ? '+' : '-'); 12072d44f31SMarcel Moolenaar if (cksum != 0) 12172d44f31SMarcel Moolenaar printf("GDB: packet `%s' has invalid checksum\n", 12272d44f31SMarcel Moolenaar gdb_rxbuf); 12372d44f31SMarcel Moolenaar } while (cksum != 0); 12472d44f31SMarcel Moolenaar 12572d44f31SMarcel Moolenaar gdb_rxp = gdb_rxbuf; 12672d44f31SMarcel Moolenaar return (0); 12772d44f31SMarcel Moolenaar } 12872d44f31SMarcel Moolenaar 12972d44f31SMarcel Moolenaar int 13072d44f31SMarcel Moolenaar gdb_rx_equal(const char *str) 13172d44f31SMarcel Moolenaar { 13272d44f31SMarcel Moolenaar int len; 13372d44f31SMarcel Moolenaar 13472d44f31SMarcel Moolenaar len = strlen(str); 13572d44f31SMarcel Moolenaar if (len > gdb_rxsz || strncmp(str, gdb_rxp, len) != 0) 13672d44f31SMarcel Moolenaar return (0); 13772d44f31SMarcel Moolenaar gdb_rxp += len; 13872d44f31SMarcel Moolenaar gdb_rxsz -= len; 13972d44f31SMarcel Moolenaar return (1); 14072d44f31SMarcel Moolenaar } 14172d44f31SMarcel Moolenaar 14272d44f31SMarcel Moolenaar int 14372d44f31SMarcel Moolenaar gdb_rx_mem(unsigned char *addr, size_t size) 14472d44f31SMarcel Moolenaar { 14501bd17ccSMarcel Moolenaar unsigned char *p; 14672d44f31SMarcel Moolenaar void *prev; 14772d44f31SMarcel Moolenaar jmp_buf jb; 14801bd17ccSMarcel Moolenaar size_t cnt; 14972d44f31SMarcel Moolenaar int ret; 15072d44f31SMarcel Moolenaar unsigned char c; 15172d44f31SMarcel Moolenaar 15272d44f31SMarcel Moolenaar if (size * 2 != gdb_rxsz) 15372d44f31SMarcel Moolenaar return (-1); 15472d44f31SMarcel Moolenaar 15572d44f31SMarcel Moolenaar prev = kdb_jmpbuf(jb); 15672d44f31SMarcel Moolenaar ret = setjmp(jb); 15772d44f31SMarcel Moolenaar if (ret == 0) { 15801bd17ccSMarcel Moolenaar p = addr; 15901bd17ccSMarcel Moolenaar cnt = size; 16001bd17ccSMarcel Moolenaar while (cnt-- > 0) { 16172d44f31SMarcel Moolenaar c = (C2N(gdb_rxp[0]) << 4) & 0xf0; 16272d44f31SMarcel Moolenaar c |= C2N(gdb_rxp[1]) & 0x0f; 16301bd17ccSMarcel Moolenaar *p++ = c; 16472d44f31SMarcel Moolenaar gdb_rxsz -= 2; 16572d44f31SMarcel Moolenaar gdb_rxp += 2; 16672d44f31SMarcel Moolenaar } 16701bd17ccSMarcel Moolenaar kdb_cpu_sync_icache(addr, size); 16872d44f31SMarcel Moolenaar } 16972d44f31SMarcel Moolenaar (void)kdb_jmpbuf(prev); 17072d44f31SMarcel Moolenaar return ((ret == 0) ? 1 : 0); 17172d44f31SMarcel Moolenaar } 17272d44f31SMarcel Moolenaar 17372d44f31SMarcel Moolenaar int 17472d44f31SMarcel Moolenaar gdb_rx_varhex(uintmax_t *vp) 17572d44f31SMarcel Moolenaar { 17672d44f31SMarcel Moolenaar uintmax_t v; 17772d44f31SMarcel Moolenaar int c, neg; 17872d44f31SMarcel Moolenaar 17972d44f31SMarcel Moolenaar c = gdb_rx_char(); 18072d44f31SMarcel Moolenaar neg = (c == '-') ? 1 : 0; 18172d44f31SMarcel Moolenaar if (neg == 1) 18272d44f31SMarcel Moolenaar c = gdb_rx_char(); 18372d44f31SMarcel Moolenaar if (!isxdigit(c)) { 18472d44f31SMarcel Moolenaar gdb_rxp -= ((c == -1) ? 0 : 1) + neg; 18572d44f31SMarcel Moolenaar gdb_rxsz += ((c == -1) ? 0 : 1) + neg; 18672d44f31SMarcel Moolenaar return (-1); 18772d44f31SMarcel Moolenaar } 18872d44f31SMarcel Moolenaar v = 0; 18972d44f31SMarcel Moolenaar do { 19072d44f31SMarcel Moolenaar v <<= 4; 19172d44f31SMarcel Moolenaar v += C2N(c); 19272d44f31SMarcel Moolenaar c = gdb_rx_char(); 19372d44f31SMarcel Moolenaar } while (isxdigit(c)); 19472d44f31SMarcel Moolenaar if (c != -1) { 19572d44f31SMarcel Moolenaar gdb_rxp--; 19672d44f31SMarcel Moolenaar gdb_rxsz++; 19772d44f31SMarcel Moolenaar } 19872d44f31SMarcel Moolenaar *vp = (neg) ? -v : v; 19972d44f31SMarcel Moolenaar return (0); 20072d44f31SMarcel Moolenaar } 20172d44f31SMarcel Moolenaar 20272d44f31SMarcel Moolenaar /* 20372d44f31SMarcel Moolenaar * Function to build and send a package. 20472d44f31SMarcel Moolenaar */ 20572d44f31SMarcel Moolenaar 20672d44f31SMarcel Moolenaar void 20772d44f31SMarcel Moolenaar gdb_tx_begin(char tp) 20872d44f31SMarcel Moolenaar { 20972d44f31SMarcel Moolenaar 21072d44f31SMarcel Moolenaar gdb_txp = gdb_txbuf; 21172d44f31SMarcel Moolenaar if (tp != '\0') 21272d44f31SMarcel Moolenaar gdb_tx_char(tp); 21372d44f31SMarcel Moolenaar } 21472d44f31SMarcel Moolenaar 21572d44f31SMarcel Moolenaar int 21672d44f31SMarcel Moolenaar gdb_tx_end(void) 21772d44f31SMarcel Moolenaar { 21872d44f31SMarcel Moolenaar const char *p; 21972d44f31SMarcel Moolenaar int runlen; 22072d44f31SMarcel Moolenaar unsigned char c, cksum; 22172d44f31SMarcel Moolenaar 22272d44f31SMarcel Moolenaar do { 22372d44f31SMarcel Moolenaar gdb_cur->gdb_putc('$'); 22472d44f31SMarcel Moolenaar 22572d44f31SMarcel Moolenaar cksum = 0; 22672d44f31SMarcel Moolenaar p = gdb_txbuf; 22772d44f31SMarcel Moolenaar while (p < gdb_txp) { 22872d44f31SMarcel Moolenaar /* Send a character and start run-length encoding. */ 22972d44f31SMarcel Moolenaar c = *p++; 23072d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 23172d44f31SMarcel Moolenaar cksum += c; 23272d44f31SMarcel Moolenaar runlen = 0; 23372d44f31SMarcel Moolenaar /* Determine run-length and update checksum. */ 23472d44f31SMarcel Moolenaar while (p < gdb_txp && *p == c) { 23572d44f31SMarcel Moolenaar runlen++; 23672d44f31SMarcel Moolenaar p++; 23772d44f31SMarcel Moolenaar } 23872d44f31SMarcel Moolenaar /* Emit the run-length encoded string. */ 23972d44f31SMarcel Moolenaar while (runlen >= 97) { 24072d44f31SMarcel Moolenaar gdb_cur->gdb_putc('*'); 24172d44f31SMarcel Moolenaar cksum += '*'; 24272d44f31SMarcel Moolenaar gdb_cur->gdb_putc(97+29); 24372d44f31SMarcel Moolenaar cksum += 97+29; 24472d44f31SMarcel Moolenaar runlen -= 97; 24572d44f31SMarcel Moolenaar if (runlen > 0) { 24672d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 24772d44f31SMarcel Moolenaar cksum += c; 24872d44f31SMarcel Moolenaar runlen--; 24972d44f31SMarcel Moolenaar } 25072d44f31SMarcel Moolenaar } 25172d44f31SMarcel Moolenaar if (runlen == 1) { 25272d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 25372d44f31SMarcel Moolenaar cksum += c; 25472d44f31SMarcel Moolenaar runlen--; 25572d44f31SMarcel Moolenaar } 25672d44f31SMarcel Moolenaar if (runlen == 0) 25772d44f31SMarcel Moolenaar continue; 25872d44f31SMarcel Moolenaar /* Don't emit '$', '#', '+' or '-'. */ 25972d44f31SMarcel Moolenaar if (runlen == 7) { 26072d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 26172d44f31SMarcel Moolenaar cksum += c; 26272d44f31SMarcel Moolenaar runlen--; 26372d44f31SMarcel Moolenaar } 26472d44f31SMarcel Moolenaar if (runlen == 6 || runlen == 14 || runlen == 16) { 26572d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 26672d44f31SMarcel Moolenaar cksum += c; 26772d44f31SMarcel Moolenaar runlen--; 26872d44f31SMarcel Moolenaar } 26972d44f31SMarcel Moolenaar gdb_cur->gdb_putc('*'); 27072d44f31SMarcel Moolenaar cksum += '*'; 27172d44f31SMarcel Moolenaar gdb_cur->gdb_putc(runlen+29); 27272d44f31SMarcel Moolenaar cksum += runlen+29; 27372d44f31SMarcel Moolenaar } 27472d44f31SMarcel Moolenaar 27572d44f31SMarcel Moolenaar gdb_cur->gdb_putc('#'); 27672d44f31SMarcel Moolenaar c = cksum >> 4; 27772d44f31SMarcel Moolenaar gdb_cur->gdb_putc(N2C(c)); 27872d44f31SMarcel Moolenaar c = cksum & 0x0f; 27972d44f31SMarcel Moolenaar gdb_cur->gdb_putc(N2C(c)); 28072d44f31SMarcel Moolenaar 281f346afc4SPoul-Henning Kamp c = gdb_getc(); 28272d44f31SMarcel Moolenaar } while (c != '+'); 28372d44f31SMarcel Moolenaar 28472d44f31SMarcel Moolenaar return (0); 28572d44f31SMarcel Moolenaar } 28672d44f31SMarcel Moolenaar 28772d44f31SMarcel Moolenaar int 28872d44f31SMarcel Moolenaar gdb_tx_mem(const unsigned char *addr, size_t size) 28972d44f31SMarcel Moolenaar { 29072d44f31SMarcel Moolenaar void *prev; 29172d44f31SMarcel Moolenaar jmp_buf jb; 29272d44f31SMarcel Moolenaar int ret; 29372d44f31SMarcel Moolenaar 29472d44f31SMarcel Moolenaar prev = kdb_jmpbuf(jb); 29572d44f31SMarcel Moolenaar ret = setjmp(jb); 29672d44f31SMarcel Moolenaar if (ret == 0) { 29772d44f31SMarcel Moolenaar while (size-- > 0) { 29872d44f31SMarcel Moolenaar *gdb_txp++ = N2C(*addr >> 4); 29972d44f31SMarcel Moolenaar *gdb_txp++ = N2C(*addr & 0x0f); 30072d44f31SMarcel Moolenaar addr++; 30172d44f31SMarcel Moolenaar } 30272d44f31SMarcel Moolenaar } 30372d44f31SMarcel Moolenaar (void)kdb_jmpbuf(prev); 30472d44f31SMarcel Moolenaar return ((ret == 0) ? 1 : 0); 30572d44f31SMarcel Moolenaar } 30672d44f31SMarcel Moolenaar 30772d44f31SMarcel Moolenaar void 30872d44f31SMarcel Moolenaar gdb_tx_reg(int regnum) 30972d44f31SMarcel Moolenaar { 31072d44f31SMarcel Moolenaar unsigned char *regp; 31172d44f31SMarcel Moolenaar size_t regsz; 31272d44f31SMarcel Moolenaar 31372d44f31SMarcel Moolenaar regp = gdb_cpu_getreg(regnum, ®sz); 31472d44f31SMarcel Moolenaar if (regp == NULL) { 31572d44f31SMarcel Moolenaar /* Register unavailable. */ 31672d44f31SMarcel Moolenaar while (regsz--) { 31772d44f31SMarcel Moolenaar gdb_tx_char('x'); 31872d44f31SMarcel Moolenaar gdb_tx_char('x'); 31972d44f31SMarcel Moolenaar } 32072d44f31SMarcel Moolenaar } else 32172d44f31SMarcel Moolenaar gdb_tx_mem(regp, regsz); 32272d44f31SMarcel Moolenaar } 323