1fa521b03SWarner Losh /*- 2*497b6b2aSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*497b6b2aSPedro F. Giffuni * 472d44f31SMarcel Moolenaar * Copyright (c) 2004 Marcel Moolenaar 572d44f31SMarcel Moolenaar * All rights reserved. 672d44f31SMarcel Moolenaar * 772d44f31SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 872d44f31SMarcel Moolenaar * modification, are permitted provided that the following conditions 972d44f31SMarcel Moolenaar * are met: 1072d44f31SMarcel Moolenaar * 1172d44f31SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 1272d44f31SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 1372d44f31SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 1472d44f31SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 1572d44f31SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 1672d44f31SMarcel Moolenaar * 1772d44f31SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1872d44f31SMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1972d44f31SMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2072d44f31SMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2172d44f31SMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2272d44f31SMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2372d44f31SMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2472d44f31SMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2572d44f31SMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2672d44f31SMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2772d44f31SMarcel Moolenaar */ 2872d44f31SMarcel Moolenaar 2972d44f31SMarcel Moolenaar #include <sys/cdefs.h> 3072d44f31SMarcel Moolenaar __FBSDID("$FreeBSD$"); 3172d44f31SMarcel Moolenaar 3272d44f31SMarcel Moolenaar #include <sys/param.h> 3372d44f31SMarcel Moolenaar #include <sys/systm.h> 3472d44f31SMarcel Moolenaar #include <sys/ctype.h> 3572d44f31SMarcel Moolenaar #include <sys/kdb.h> 3627ecc2adSBenno Rice #include <sys/libkern.h> 373a5d3671SMatthew D Fleming #include <sys/ttydefaults.h> 3872d44f31SMarcel Moolenaar 3972d44f31SMarcel Moolenaar #include <machine/gdb_machdep.h> 4001bd17ccSMarcel Moolenaar #include <machine/kdb.h> 4172d44f31SMarcel Moolenaar 4272d44f31SMarcel Moolenaar #include <gdb/gdb.h> 4372d44f31SMarcel Moolenaar #include <gdb/gdb_int.h> 4472d44f31SMarcel Moolenaar 4572d44f31SMarcel Moolenaar static char gdb_rxbuf[GDB_BUFSZ]; 4672d44f31SMarcel Moolenaar char *gdb_rxp = NULL; 4772d44f31SMarcel Moolenaar size_t gdb_rxsz = 0; 4872d44f31SMarcel Moolenaar static char gdb_txbuf[GDB_BUFSZ]; 4972d44f31SMarcel Moolenaar char *gdb_txp = NULL; /* Used in inline functions. */ 5072d44f31SMarcel Moolenaar 5172d44f31SMarcel Moolenaar #define C2N(c) (((c) < 'A') ? (c) - '0' : \ 5272d44f31SMarcel Moolenaar 10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a')) 5372d44f31SMarcel Moolenaar #define N2C(n) (((n) < 10) ? (n) + '0' : (n) + 'a' - 10) 5472d44f31SMarcel Moolenaar 5572d44f31SMarcel Moolenaar /* 56f346afc4SPoul-Henning Kamp * Get a single character 57f346afc4SPoul-Henning Kamp */ 58f346afc4SPoul-Henning Kamp 59f346afc4SPoul-Henning Kamp static int 60f346afc4SPoul-Henning Kamp gdb_getc(void) 61f346afc4SPoul-Henning Kamp { 62f346afc4SPoul-Henning Kamp int c; 63f346afc4SPoul-Henning Kamp 64f346afc4SPoul-Henning Kamp do 65f346afc4SPoul-Henning Kamp c = gdb_cur->gdb_getc(); 66f346afc4SPoul-Henning Kamp while (c == -1); 673a5d3671SMatthew D Fleming 683a5d3671SMatthew D Fleming if (c == CTRL('C')) { 693a5d3671SMatthew D Fleming printf("Received ^C; trying to switch back to ddb.\n"); 703a5d3671SMatthew D Fleming 713a5d3671SMatthew D Fleming if (kdb_dbbe_select("ddb") != 0) 723a5d3671SMatthew D Fleming printf("The ddb backend could not be selected.\n"); 733a5d3671SMatthew D Fleming else { 743a5d3671SMatthew D Fleming printf("using longjmp, hope it works!\n"); 753a5d3671SMatthew D Fleming kdb_reenter(); 763a5d3671SMatthew D Fleming } 773a5d3671SMatthew D Fleming } 78f346afc4SPoul-Henning Kamp return (c); 79f346afc4SPoul-Henning Kamp } 80f346afc4SPoul-Henning Kamp 81f346afc4SPoul-Henning Kamp /* 8272d44f31SMarcel Moolenaar * Functions to receive and extract from a packet. 8372d44f31SMarcel Moolenaar */ 8472d44f31SMarcel Moolenaar 8572d44f31SMarcel Moolenaar int 8672d44f31SMarcel Moolenaar gdb_rx_begin(void) 8772d44f31SMarcel Moolenaar { 8872d44f31SMarcel Moolenaar int c, cksum; 8972d44f31SMarcel Moolenaar 9072d44f31SMarcel Moolenaar gdb_rxp = NULL; 9172d44f31SMarcel Moolenaar do { 9272d44f31SMarcel Moolenaar /* 9372d44f31SMarcel Moolenaar * Wait for the start character, ignore all others. 9472d44f31SMarcel Moolenaar * XXX needs a timeout. 9572d44f31SMarcel Moolenaar */ 96f346afc4SPoul-Henning Kamp while ((c = gdb_getc()) != '$') 9772d44f31SMarcel Moolenaar ; 9872d44f31SMarcel Moolenaar 9972d44f31SMarcel Moolenaar /* Read until a # or end of buffer is found. */ 10072d44f31SMarcel Moolenaar cksum = 0; 10172d44f31SMarcel Moolenaar gdb_rxsz = 0; 10272d44f31SMarcel Moolenaar while (gdb_rxsz < sizeof(gdb_rxbuf) - 1) { 103f346afc4SPoul-Henning Kamp c = gdb_getc(); 10472d44f31SMarcel Moolenaar if (c == '#') 10572d44f31SMarcel Moolenaar break; 10672d44f31SMarcel Moolenaar gdb_rxbuf[gdb_rxsz++] = c; 10772d44f31SMarcel Moolenaar cksum += c; 10872d44f31SMarcel Moolenaar } 10972d44f31SMarcel Moolenaar gdb_rxbuf[gdb_rxsz] = 0; 11072d44f31SMarcel Moolenaar cksum &= 0xff; 11172d44f31SMarcel Moolenaar 11272d44f31SMarcel Moolenaar /* Bail out on a buffer overflow. */ 11372d44f31SMarcel Moolenaar if (c != '#') { 11472d44f31SMarcel Moolenaar gdb_cur->gdb_putc('-'); 11572d44f31SMarcel Moolenaar return (ENOSPC); 11672d44f31SMarcel Moolenaar } 11772d44f31SMarcel Moolenaar 118f346afc4SPoul-Henning Kamp c = gdb_getc(); 11972d44f31SMarcel Moolenaar cksum -= (C2N(c) << 4) & 0xf0; 120f346afc4SPoul-Henning Kamp c = gdb_getc(); 12172d44f31SMarcel Moolenaar cksum -= C2N(c) & 0x0f; 12272d44f31SMarcel Moolenaar gdb_cur->gdb_putc((cksum == 0) ? '+' : '-'); 12372d44f31SMarcel Moolenaar if (cksum != 0) 12472d44f31SMarcel Moolenaar printf("GDB: packet `%s' has invalid checksum\n", 12572d44f31SMarcel Moolenaar gdb_rxbuf); 12672d44f31SMarcel Moolenaar } while (cksum != 0); 12772d44f31SMarcel Moolenaar 12872d44f31SMarcel Moolenaar gdb_rxp = gdb_rxbuf; 12972d44f31SMarcel Moolenaar return (0); 13072d44f31SMarcel Moolenaar } 13172d44f31SMarcel Moolenaar 13272d44f31SMarcel Moolenaar int 13372d44f31SMarcel Moolenaar gdb_rx_equal(const char *str) 13472d44f31SMarcel Moolenaar { 13572d44f31SMarcel Moolenaar int len; 13672d44f31SMarcel Moolenaar 13772d44f31SMarcel Moolenaar len = strlen(str); 13872d44f31SMarcel Moolenaar if (len > gdb_rxsz || strncmp(str, gdb_rxp, len) != 0) 13972d44f31SMarcel Moolenaar return (0); 14072d44f31SMarcel Moolenaar gdb_rxp += len; 14172d44f31SMarcel Moolenaar gdb_rxsz -= len; 14272d44f31SMarcel Moolenaar return (1); 14372d44f31SMarcel Moolenaar } 14472d44f31SMarcel Moolenaar 14572d44f31SMarcel Moolenaar int 14672d44f31SMarcel Moolenaar gdb_rx_mem(unsigned char *addr, size_t size) 14772d44f31SMarcel Moolenaar { 14801bd17ccSMarcel Moolenaar unsigned char *p; 14972d44f31SMarcel Moolenaar void *prev; 15072d44f31SMarcel Moolenaar jmp_buf jb; 15101bd17ccSMarcel Moolenaar size_t cnt; 15272d44f31SMarcel Moolenaar int ret; 15372d44f31SMarcel Moolenaar unsigned char c; 15472d44f31SMarcel Moolenaar 15572d44f31SMarcel Moolenaar if (size * 2 != gdb_rxsz) 15672d44f31SMarcel Moolenaar return (-1); 15772d44f31SMarcel Moolenaar 15872d44f31SMarcel Moolenaar prev = kdb_jmpbuf(jb); 15972d44f31SMarcel Moolenaar ret = setjmp(jb); 16072d44f31SMarcel Moolenaar if (ret == 0) { 16101bd17ccSMarcel Moolenaar p = addr; 16201bd17ccSMarcel Moolenaar cnt = size; 16301bd17ccSMarcel Moolenaar while (cnt-- > 0) { 16472d44f31SMarcel Moolenaar c = (C2N(gdb_rxp[0]) << 4) & 0xf0; 16572d44f31SMarcel Moolenaar c |= C2N(gdb_rxp[1]) & 0x0f; 16601bd17ccSMarcel Moolenaar *p++ = c; 16772d44f31SMarcel Moolenaar gdb_rxsz -= 2; 16872d44f31SMarcel Moolenaar gdb_rxp += 2; 16972d44f31SMarcel Moolenaar } 17001bd17ccSMarcel Moolenaar kdb_cpu_sync_icache(addr, size); 17172d44f31SMarcel Moolenaar } 17272d44f31SMarcel Moolenaar (void)kdb_jmpbuf(prev); 17372d44f31SMarcel Moolenaar return ((ret == 0) ? 1 : 0); 17472d44f31SMarcel Moolenaar } 17572d44f31SMarcel Moolenaar 17672d44f31SMarcel Moolenaar int 17772d44f31SMarcel Moolenaar gdb_rx_varhex(uintmax_t *vp) 17872d44f31SMarcel Moolenaar { 17972d44f31SMarcel Moolenaar uintmax_t v; 18072d44f31SMarcel Moolenaar int c, neg; 18172d44f31SMarcel Moolenaar 18272d44f31SMarcel Moolenaar c = gdb_rx_char(); 18372d44f31SMarcel Moolenaar neg = (c == '-') ? 1 : 0; 18472d44f31SMarcel Moolenaar if (neg == 1) 18572d44f31SMarcel Moolenaar c = gdb_rx_char(); 18672d44f31SMarcel Moolenaar if (!isxdigit(c)) { 18772d44f31SMarcel Moolenaar gdb_rxp -= ((c == -1) ? 0 : 1) + neg; 18872d44f31SMarcel Moolenaar gdb_rxsz += ((c == -1) ? 0 : 1) + neg; 18972d44f31SMarcel Moolenaar return (-1); 19072d44f31SMarcel Moolenaar } 19172d44f31SMarcel Moolenaar v = 0; 19272d44f31SMarcel Moolenaar do { 19372d44f31SMarcel Moolenaar v <<= 4; 19472d44f31SMarcel Moolenaar v += C2N(c); 19572d44f31SMarcel Moolenaar c = gdb_rx_char(); 19672d44f31SMarcel Moolenaar } while (isxdigit(c)); 19772d44f31SMarcel Moolenaar if (c != -1) { 19872d44f31SMarcel Moolenaar gdb_rxp--; 19972d44f31SMarcel Moolenaar gdb_rxsz++; 20072d44f31SMarcel Moolenaar } 20172d44f31SMarcel Moolenaar *vp = (neg) ? -v : v; 20272d44f31SMarcel Moolenaar return (0); 20372d44f31SMarcel Moolenaar } 20472d44f31SMarcel Moolenaar 20572d44f31SMarcel Moolenaar /* 20672d44f31SMarcel Moolenaar * Function to build and send a package. 20772d44f31SMarcel Moolenaar */ 20872d44f31SMarcel Moolenaar 20972d44f31SMarcel Moolenaar void 21072d44f31SMarcel Moolenaar gdb_tx_begin(char tp) 21172d44f31SMarcel Moolenaar { 21272d44f31SMarcel Moolenaar 21372d44f31SMarcel Moolenaar gdb_txp = gdb_txbuf; 21472d44f31SMarcel Moolenaar if (tp != '\0') 21572d44f31SMarcel Moolenaar gdb_tx_char(tp); 21672d44f31SMarcel Moolenaar } 21772d44f31SMarcel Moolenaar 21872d44f31SMarcel Moolenaar int 21972d44f31SMarcel Moolenaar gdb_tx_end(void) 22072d44f31SMarcel Moolenaar { 22172d44f31SMarcel Moolenaar const char *p; 22272d44f31SMarcel Moolenaar int runlen; 22372d44f31SMarcel Moolenaar unsigned char c, cksum; 22472d44f31SMarcel Moolenaar 22572d44f31SMarcel Moolenaar do { 22672d44f31SMarcel Moolenaar gdb_cur->gdb_putc('$'); 22772d44f31SMarcel Moolenaar 22872d44f31SMarcel Moolenaar cksum = 0; 22972d44f31SMarcel Moolenaar p = gdb_txbuf; 23072d44f31SMarcel Moolenaar while (p < gdb_txp) { 23172d44f31SMarcel Moolenaar /* Send a character and start run-length encoding. */ 23272d44f31SMarcel Moolenaar c = *p++; 23372d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 23472d44f31SMarcel Moolenaar cksum += c; 23572d44f31SMarcel Moolenaar runlen = 0; 23672d44f31SMarcel Moolenaar /* Determine run-length and update checksum. */ 23772d44f31SMarcel Moolenaar while (p < gdb_txp && *p == c) { 23872d44f31SMarcel Moolenaar runlen++; 23972d44f31SMarcel Moolenaar p++; 24072d44f31SMarcel Moolenaar } 24172d44f31SMarcel Moolenaar /* Emit the run-length encoded string. */ 24272d44f31SMarcel Moolenaar while (runlen >= 97) { 24372d44f31SMarcel Moolenaar gdb_cur->gdb_putc('*'); 24472d44f31SMarcel Moolenaar cksum += '*'; 24572d44f31SMarcel Moolenaar gdb_cur->gdb_putc(97+29); 24672d44f31SMarcel Moolenaar cksum += 97+29; 24772d44f31SMarcel Moolenaar runlen -= 97; 24872d44f31SMarcel Moolenaar if (runlen > 0) { 24972d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 25072d44f31SMarcel Moolenaar cksum += c; 25172d44f31SMarcel Moolenaar runlen--; 25272d44f31SMarcel Moolenaar } 25372d44f31SMarcel Moolenaar } 25472d44f31SMarcel Moolenaar if (runlen == 1) { 25572d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 25672d44f31SMarcel Moolenaar cksum += c; 25772d44f31SMarcel Moolenaar runlen--; 25872d44f31SMarcel Moolenaar } 25972d44f31SMarcel Moolenaar if (runlen == 0) 26072d44f31SMarcel Moolenaar continue; 26172d44f31SMarcel Moolenaar /* Don't emit '$', '#', '+' or '-'. */ 26272d44f31SMarcel Moolenaar if (runlen == 7) { 26372d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 26472d44f31SMarcel Moolenaar cksum += c; 26572d44f31SMarcel Moolenaar runlen--; 26672d44f31SMarcel Moolenaar } 26772d44f31SMarcel Moolenaar if (runlen == 6 || runlen == 14 || runlen == 16) { 26872d44f31SMarcel Moolenaar gdb_cur->gdb_putc(c); 26972d44f31SMarcel Moolenaar cksum += c; 27072d44f31SMarcel Moolenaar runlen--; 27172d44f31SMarcel Moolenaar } 27272d44f31SMarcel Moolenaar gdb_cur->gdb_putc('*'); 27372d44f31SMarcel Moolenaar cksum += '*'; 27472d44f31SMarcel Moolenaar gdb_cur->gdb_putc(runlen+29); 27572d44f31SMarcel Moolenaar cksum += runlen+29; 27672d44f31SMarcel Moolenaar } 27772d44f31SMarcel Moolenaar 27872d44f31SMarcel Moolenaar gdb_cur->gdb_putc('#'); 27972d44f31SMarcel Moolenaar c = cksum >> 4; 28072d44f31SMarcel Moolenaar gdb_cur->gdb_putc(N2C(c)); 28172d44f31SMarcel Moolenaar c = cksum & 0x0f; 28272d44f31SMarcel Moolenaar gdb_cur->gdb_putc(N2C(c)); 28372d44f31SMarcel Moolenaar 284f346afc4SPoul-Henning Kamp c = gdb_getc(); 28572d44f31SMarcel Moolenaar } while (c != '+'); 28672d44f31SMarcel Moolenaar 28772d44f31SMarcel Moolenaar return (0); 28872d44f31SMarcel Moolenaar } 28972d44f31SMarcel Moolenaar 29072d44f31SMarcel Moolenaar int 29172d44f31SMarcel Moolenaar gdb_tx_mem(const unsigned char *addr, size_t size) 29272d44f31SMarcel Moolenaar { 29372d44f31SMarcel Moolenaar void *prev; 29472d44f31SMarcel Moolenaar jmp_buf jb; 29572d44f31SMarcel Moolenaar int ret; 29672d44f31SMarcel Moolenaar 29772d44f31SMarcel Moolenaar prev = kdb_jmpbuf(jb); 29872d44f31SMarcel Moolenaar ret = setjmp(jb); 29972d44f31SMarcel Moolenaar if (ret == 0) { 30072d44f31SMarcel Moolenaar while (size-- > 0) { 30172d44f31SMarcel Moolenaar *gdb_txp++ = N2C(*addr >> 4); 30272d44f31SMarcel Moolenaar *gdb_txp++ = N2C(*addr & 0x0f); 30372d44f31SMarcel Moolenaar addr++; 30472d44f31SMarcel Moolenaar } 30572d44f31SMarcel Moolenaar } 30672d44f31SMarcel Moolenaar (void)kdb_jmpbuf(prev); 30772d44f31SMarcel Moolenaar return ((ret == 0) ? 1 : 0); 30872d44f31SMarcel Moolenaar } 30972d44f31SMarcel Moolenaar 31072d44f31SMarcel Moolenaar void 31172d44f31SMarcel Moolenaar gdb_tx_reg(int regnum) 31272d44f31SMarcel Moolenaar { 31372d44f31SMarcel Moolenaar unsigned char *regp; 31472d44f31SMarcel Moolenaar size_t regsz; 31572d44f31SMarcel Moolenaar 31672d44f31SMarcel Moolenaar regp = gdb_cpu_getreg(regnum, ®sz); 31772d44f31SMarcel Moolenaar if (regp == NULL) { 31872d44f31SMarcel Moolenaar /* Register unavailable. */ 31972d44f31SMarcel Moolenaar while (regsz--) { 32072d44f31SMarcel Moolenaar gdb_tx_char('x'); 32172d44f31SMarcel Moolenaar gdb_tx_char('x'); 32272d44f31SMarcel Moolenaar } 32372d44f31SMarcel Moolenaar } else 32472d44f31SMarcel Moolenaar gdb_tx_mem(regp, regsz); 32572d44f31SMarcel Moolenaar } 32627ecc2adSBenno Rice 32727ecc2adSBenno Rice /* Read binary data up until the end of the packet or until we have datalen decoded bytes */ 32827ecc2adSBenno Rice int 32927ecc2adSBenno Rice gdb_rx_bindata(unsigned char *data, size_t datalen, size_t *amt) 33027ecc2adSBenno Rice { 33127ecc2adSBenno Rice int c; 33227ecc2adSBenno Rice 33327ecc2adSBenno Rice *amt = 0; 33427ecc2adSBenno Rice 33527ecc2adSBenno Rice while (*amt < datalen) { 33627ecc2adSBenno Rice c = gdb_rx_char(); 33727ecc2adSBenno Rice /* End of packet? */ 33827ecc2adSBenno Rice if (c == -1) 33927ecc2adSBenno Rice break; 34027ecc2adSBenno Rice /* Escaped character up next */ 34127ecc2adSBenno Rice if (c == '}') { 34227ecc2adSBenno Rice /* Truncated packet? Bail out */ 34327ecc2adSBenno Rice if ((c = gdb_rx_char()) == -1) 34427ecc2adSBenno Rice return (1); 34527ecc2adSBenno Rice c ^= 0x20; 34627ecc2adSBenno Rice } 34727ecc2adSBenno Rice *(data++) = c & 0xff; 34827ecc2adSBenno Rice (*amt)++; 34927ecc2adSBenno Rice } 35027ecc2adSBenno Rice 35127ecc2adSBenno Rice return (0); 35227ecc2adSBenno Rice } 35327ecc2adSBenno Rice 35427ecc2adSBenno Rice int 35527ecc2adSBenno Rice gdb_search_mem(const unsigned char *addr, size_t size, const unsigned char *pat, size_t patlen, const unsigned char **found) 35627ecc2adSBenno Rice { 35727ecc2adSBenno Rice void *prev; 35827ecc2adSBenno Rice jmp_buf jb; 35927ecc2adSBenno Rice int ret; 36027ecc2adSBenno Rice 36127ecc2adSBenno Rice prev = kdb_jmpbuf(jb); 36227ecc2adSBenno Rice ret = setjmp(jb); 36327ecc2adSBenno Rice if (ret == 0) 36427ecc2adSBenno Rice *found = memmem(addr, size, pat, patlen); 36527ecc2adSBenno Rice 36627ecc2adSBenno Rice (void)kdb_jmpbuf(prev); 36727ecc2adSBenno Rice return ((ret == 0) ? 1 : 0); 36827ecc2adSBenno Rice } 369