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 AUTHORS ``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 AUTHORS 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/kdb.h> 3372d44f31SMarcel Moolenaar #include <sys/kernel.h> 3472d44f31SMarcel Moolenaar #include <sys/pcpu.h> 3572d44f31SMarcel Moolenaar #include <sys/proc.h> 3672d44f31SMarcel Moolenaar #include <sys/reboot.h> 3772d44f31SMarcel Moolenaar 3872d44f31SMarcel Moolenaar #include <machine/gdb_machdep.h> 3972d44f31SMarcel Moolenaar #include <machine/kdb.h> 4072d44f31SMarcel Moolenaar 4172d44f31SMarcel Moolenaar #include <gdb/gdb.h> 4272d44f31SMarcel Moolenaar #include <gdb/gdb_int.h> 4372d44f31SMarcel Moolenaar 4472d44f31SMarcel Moolenaar static dbbe_init_f gdb_init; 4572d44f31SMarcel Moolenaar static dbbe_trap_f gdb_trap; 4672d44f31SMarcel Moolenaar 4772d44f31SMarcel Moolenaar KDB_BACKEND(gdb, gdb_init, NULL, gdb_trap); 4872d44f31SMarcel Moolenaar 49e8d86c0eSPoul-Henning Kamp static struct gdb_dbgport null_gdb_dbgport; 50e8d86c0eSPoul-Henning Kamp DATA_SET(gdb_dbgport_set, null_gdb_dbgport); 5172d44f31SMarcel Moolenaar SET_DECLARE(gdb_dbgport_set, struct gdb_dbgport); 5272d44f31SMarcel Moolenaar 5372d44f31SMarcel Moolenaar struct gdb_dbgport *gdb_cur = NULL; 547d0c6c9fSSam Leffler int gdb_listening = 0; 5572d44f31SMarcel Moolenaar 5672d44f31SMarcel Moolenaar static int 5772d44f31SMarcel Moolenaar gdb_init(void) 5872d44f31SMarcel Moolenaar { 5972d44f31SMarcel Moolenaar struct gdb_dbgport *dp, **iter; 6072d44f31SMarcel Moolenaar int cur_pri, pri; 6172d44f31SMarcel Moolenaar 6272d44f31SMarcel Moolenaar gdb_cur = NULL; 6372d44f31SMarcel Moolenaar cur_pri = -1; 6472d44f31SMarcel Moolenaar SET_FOREACH(iter, gdb_dbgport_set) { 6572d44f31SMarcel Moolenaar dp = *iter; 6672d44f31SMarcel Moolenaar pri = (dp->gdb_probe != NULL) ? dp->gdb_probe() : -1; 6772d44f31SMarcel Moolenaar dp->gdb_active = (pri >= 0) ? 0 : -1; 6872d44f31SMarcel Moolenaar if (pri > cur_pri) { 6972d44f31SMarcel Moolenaar cur_pri = pri; 7072d44f31SMarcel Moolenaar gdb_cur = dp; 7172d44f31SMarcel Moolenaar } 7272d44f31SMarcel Moolenaar } 7372d44f31SMarcel Moolenaar if (gdb_cur != NULL) { 7472d44f31SMarcel Moolenaar printf("GDB: debug ports:"); 7572d44f31SMarcel Moolenaar SET_FOREACH(iter, gdb_dbgport_set) { 7672d44f31SMarcel Moolenaar dp = *iter; 7772d44f31SMarcel Moolenaar if (dp->gdb_active == 0) 7872d44f31SMarcel Moolenaar printf(" %s", dp->gdb_name); 7972d44f31SMarcel Moolenaar } 8072d44f31SMarcel Moolenaar printf("\n"); 8172d44f31SMarcel Moolenaar } else 8272d44f31SMarcel Moolenaar printf("GDB: no debug ports present\n"); 8372d44f31SMarcel Moolenaar if (gdb_cur != NULL) { 8472d44f31SMarcel Moolenaar gdb_cur->gdb_init(); 8572d44f31SMarcel Moolenaar printf("GDB: current port: %s\n", gdb_cur->gdb_name); 8672d44f31SMarcel Moolenaar } 877d0c6c9fSSam Leffler if (gdb_cur != NULL) { 8872d44f31SMarcel Moolenaar cur_pri = (boothowto & RB_GDB) ? 2 : 0; 897d0c6c9fSSam Leffler gdb_consinit(); 907d0c6c9fSSam Leffler } else 9172d44f31SMarcel Moolenaar cur_pri = -1; 9272d44f31SMarcel Moolenaar return (cur_pri); 9372d44f31SMarcel Moolenaar } 9472d44f31SMarcel Moolenaar 9572d44f31SMarcel Moolenaar static int 9672d44f31SMarcel Moolenaar gdb_trap(int type, int code) 9772d44f31SMarcel Moolenaar { 98*3a5d3671SMatthew D Fleming jmp_buf jb; 9972d44f31SMarcel Moolenaar struct thread *thr_iter; 100*3a5d3671SMatthew D Fleming void *prev_jb; 101*3a5d3671SMatthew D Fleming 102*3a5d3671SMatthew D Fleming prev_jb = kdb_jmpbuf(jb); 103*3a5d3671SMatthew D Fleming if (setjmp(jb) != 0) { 104*3a5d3671SMatthew D Fleming printf("%s bailing, hopefully back to ddb!\n", __func__); 105*3a5d3671SMatthew D Fleming gdb_listening = 0; 106*3a5d3671SMatthew D Fleming (void)kdb_jmpbuf(prev_jb); 107*3a5d3671SMatthew D Fleming return (1); 108*3a5d3671SMatthew D Fleming } 10972d44f31SMarcel Moolenaar 1107d0c6c9fSSam Leffler gdb_listening = 0; 11172d44f31SMarcel Moolenaar /* 11272d44f31SMarcel Moolenaar * Send a T packet. We currently do not support watchpoints (the 11372d44f31SMarcel Moolenaar * awatch, rwatch or watch elements). 11472d44f31SMarcel Moolenaar */ 11572d44f31SMarcel Moolenaar gdb_tx_begin('T'); 11672d44f31SMarcel Moolenaar gdb_tx_hex(gdb_cpu_signal(type, code), 2); 11772d44f31SMarcel Moolenaar gdb_tx_varhex(GDB_REG_PC); 11872d44f31SMarcel Moolenaar gdb_tx_char(':'); 11972d44f31SMarcel Moolenaar gdb_tx_reg(GDB_REG_PC); 12072d44f31SMarcel Moolenaar gdb_tx_char(';'); 12172d44f31SMarcel Moolenaar gdb_tx_str("thread:"); 12272d44f31SMarcel Moolenaar gdb_tx_varhex((long)kdb_thread->td_tid); 12372d44f31SMarcel Moolenaar gdb_tx_char(';'); 12472d44f31SMarcel Moolenaar gdb_tx_end(); /* XXX check error condition. */ 12572d44f31SMarcel Moolenaar 12672d44f31SMarcel Moolenaar thr_iter = NULL; 12772d44f31SMarcel Moolenaar while (gdb_rx_begin() == 0) { 12803e62bf3SMarcel Moolenaar /* printf("GDB: got '%s'\n", gdb_rxp); */ 12972d44f31SMarcel Moolenaar switch (gdb_rx_char()) { 13072d44f31SMarcel Moolenaar case '?': /* Last signal. */ 13172d44f31SMarcel Moolenaar gdb_tx_begin('S'); 13272d44f31SMarcel Moolenaar gdb_tx_hex(gdb_cpu_signal(type, code), 2); 13372d44f31SMarcel Moolenaar gdb_tx_end(); 13472d44f31SMarcel Moolenaar break; 13572d44f31SMarcel Moolenaar case 'c': { /* Continue. */ 13672d44f31SMarcel Moolenaar uintmax_t addr; 137bcc5241cSMarcel Moolenaar register_t pc; 138bcc5241cSMarcel Moolenaar if (!gdb_rx_varhex(&addr)) { 139bcc5241cSMarcel Moolenaar pc = addr; 140bcc5241cSMarcel Moolenaar gdb_cpu_setreg(GDB_REG_PC, &pc); 141bcc5241cSMarcel Moolenaar } 14272d44f31SMarcel Moolenaar kdb_cpu_clear_singlestep(); 1437d0c6c9fSSam Leffler gdb_listening = 1; 14472d44f31SMarcel Moolenaar return (1); 14572d44f31SMarcel Moolenaar } 14672d44f31SMarcel Moolenaar case 'C': { /* Continue with signal. */ 14772d44f31SMarcel Moolenaar uintmax_t addr, sig; 148bcc5241cSMarcel Moolenaar register_t pc; 14972d44f31SMarcel Moolenaar if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' && 150bcc5241cSMarcel Moolenaar !gdb_rx_varhex(&addr)) { 151bcc5241cSMarcel Moolenaar pc = addr; 152bcc5241cSMarcel Moolenaar gdb_cpu_setreg(GDB_REG_PC, &pc); 153bcc5241cSMarcel Moolenaar } 15472d44f31SMarcel Moolenaar kdb_cpu_clear_singlestep(); 1557d0c6c9fSSam Leffler gdb_listening = 1; 15672d44f31SMarcel Moolenaar return (1); 15772d44f31SMarcel Moolenaar } 158d412b2deSPeter Grehan case 'D': { /* Detach */ 159d412b2deSPeter Grehan gdb_tx_ok(); 160d412b2deSPeter Grehan kdb_cpu_clear_singlestep(); 161d412b2deSPeter Grehan return (1); 162d412b2deSPeter Grehan } 16372d44f31SMarcel Moolenaar case 'g': { /* Read registers. */ 16472d44f31SMarcel Moolenaar size_t r; 16572d44f31SMarcel Moolenaar gdb_tx_begin(0); 16672d44f31SMarcel Moolenaar for (r = 0; r < GDB_NREGS; r++) 16772d44f31SMarcel Moolenaar gdb_tx_reg(r); 16872d44f31SMarcel Moolenaar gdb_tx_end(); 16972d44f31SMarcel Moolenaar break; 17072d44f31SMarcel Moolenaar } 17172d44f31SMarcel Moolenaar case 'G': /* Write registers. */ 17272d44f31SMarcel Moolenaar gdb_tx_err(0); 17372d44f31SMarcel Moolenaar break; 17472d44f31SMarcel Moolenaar case 'H': { /* Set thread. */ 17572d44f31SMarcel Moolenaar intmax_t tid; 17672d44f31SMarcel Moolenaar struct thread *thr; 17772d44f31SMarcel Moolenaar gdb_rx_char(); 1784af77eceSSam Leffler if (gdb_rx_varhex(&tid)) { 1794af77eceSSam Leffler gdb_tx_err(EINVAL); 1804af77eceSSam Leffler break; 1814af77eceSSam Leffler } 18272d44f31SMarcel Moolenaar if (tid > 0) { 18372d44f31SMarcel Moolenaar thr = kdb_thr_lookup(tid); 18472d44f31SMarcel Moolenaar if (thr == NULL) { 18572d44f31SMarcel Moolenaar gdb_tx_err(ENOENT); 18672d44f31SMarcel Moolenaar break; 18772d44f31SMarcel Moolenaar } 18872d44f31SMarcel Moolenaar kdb_thr_select(thr); 18972d44f31SMarcel Moolenaar } 19072d44f31SMarcel Moolenaar gdb_tx_ok(); 19172d44f31SMarcel Moolenaar break; 19272d44f31SMarcel Moolenaar } 19372d44f31SMarcel Moolenaar case 'k': /* Kill request. */ 19472d44f31SMarcel Moolenaar kdb_cpu_clear_singlestep(); 1957d0c6c9fSSam Leffler gdb_listening = 1; 19672d44f31SMarcel Moolenaar return (1); 19772d44f31SMarcel Moolenaar case 'm': { /* Read memory. */ 19872d44f31SMarcel Moolenaar uintmax_t addr, size; 19972d44f31SMarcel Moolenaar if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' || 20072d44f31SMarcel Moolenaar gdb_rx_varhex(&size)) { 20172d44f31SMarcel Moolenaar gdb_tx_err(EINVAL); 20272d44f31SMarcel Moolenaar break; 20372d44f31SMarcel Moolenaar } 20472d44f31SMarcel Moolenaar gdb_tx_begin(0); 20572d44f31SMarcel Moolenaar if (gdb_tx_mem((char *)(uintptr_t)addr, size)) 20672d44f31SMarcel Moolenaar gdb_tx_end(); 20772d44f31SMarcel Moolenaar else 20872d44f31SMarcel Moolenaar gdb_tx_err(EIO); 20972d44f31SMarcel Moolenaar break; 21072d44f31SMarcel Moolenaar } 21172d44f31SMarcel Moolenaar case 'M': { /* Write memory. */ 21272d44f31SMarcel Moolenaar uintmax_t addr, size; 21372d44f31SMarcel Moolenaar if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' || 21472d44f31SMarcel Moolenaar gdb_rx_varhex(&size) || gdb_rx_char() != ':') { 21572d44f31SMarcel Moolenaar gdb_tx_err(EINVAL); 21672d44f31SMarcel Moolenaar break; 21772d44f31SMarcel Moolenaar } 21872d44f31SMarcel Moolenaar if (gdb_rx_mem((char *)(uintptr_t)addr, size) == 0) 21972d44f31SMarcel Moolenaar gdb_tx_err(EIO); 22072d44f31SMarcel Moolenaar else 22172d44f31SMarcel Moolenaar gdb_tx_ok(); 22272d44f31SMarcel Moolenaar break; 22372d44f31SMarcel Moolenaar } 22472d44f31SMarcel Moolenaar case 'P': { /* Write register. */ 225bcc5241cSMarcel Moolenaar char *val; 226bcc5241cSMarcel Moolenaar uintmax_t reg; 227bcc5241cSMarcel Moolenaar val = gdb_rxp; 22872d44f31SMarcel Moolenaar if (gdb_rx_varhex(®) || gdb_rx_char() != '=' || 229bcc5241cSMarcel Moolenaar !gdb_rx_mem(val, gdb_cpu_regsz(reg))) { 23072d44f31SMarcel Moolenaar gdb_tx_err(EINVAL); 23172d44f31SMarcel Moolenaar break; 23272d44f31SMarcel Moolenaar } 23372d44f31SMarcel Moolenaar gdb_cpu_setreg(reg, val); 23472d44f31SMarcel Moolenaar gdb_tx_ok(); 23572d44f31SMarcel Moolenaar break; 23672d44f31SMarcel Moolenaar } 23772d44f31SMarcel Moolenaar case 'q': /* General query. */ 23872d44f31SMarcel Moolenaar if (gdb_rx_equal("fThreadInfo")) { 23972d44f31SMarcel Moolenaar thr_iter = kdb_thr_first(); 24072d44f31SMarcel Moolenaar gdb_tx_begin('m'); 24172d44f31SMarcel Moolenaar gdb_tx_hex((long)thr_iter->td_tid, 8); 24272d44f31SMarcel Moolenaar gdb_tx_end(); 24372d44f31SMarcel Moolenaar } else if (gdb_rx_equal("sThreadInfo")) { 24472d44f31SMarcel Moolenaar if (thr_iter == NULL) { 24572d44f31SMarcel Moolenaar gdb_tx_err(ENXIO); 24672d44f31SMarcel Moolenaar break; 24772d44f31SMarcel Moolenaar } 24872d44f31SMarcel Moolenaar thr_iter = kdb_thr_next(thr_iter); 24972d44f31SMarcel Moolenaar if (thr_iter != NULL) { 25072d44f31SMarcel Moolenaar gdb_tx_begin('m'); 25172d44f31SMarcel Moolenaar gdb_tx_hex((long)thr_iter->td_tid, 8); 25272d44f31SMarcel Moolenaar gdb_tx_end(); 25372d44f31SMarcel Moolenaar } else { 25472d44f31SMarcel Moolenaar gdb_tx_begin('l'); 25572d44f31SMarcel Moolenaar gdb_tx_end(); 25672d44f31SMarcel Moolenaar } 25772d44f31SMarcel Moolenaar } else if (!gdb_cpu_query()) 25872d44f31SMarcel Moolenaar gdb_tx_empty(); 25972d44f31SMarcel Moolenaar break; 26072d44f31SMarcel Moolenaar case 's': { /* Step. */ 26172d44f31SMarcel Moolenaar uintmax_t addr; 262bcc5241cSMarcel Moolenaar register_t pc; 263bcc5241cSMarcel Moolenaar if (!gdb_rx_varhex(&addr)) { 264bcc5241cSMarcel Moolenaar pc = addr; 265bcc5241cSMarcel Moolenaar gdb_cpu_setreg(GDB_REG_PC, &pc); 266bcc5241cSMarcel Moolenaar } 26772d44f31SMarcel Moolenaar kdb_cpu_set_singlestep(); 2687d0c6c9fSSam Leffler gdb_listening = 1; 26972d44f31SMarcel Moolenaar return (1); 27072d44f31SMarcel Moolenaar } 27172d44f31SMarcel Moolenaar case 'S': { /* Step with signal. */ 27272d44f31SMarcel Moolenaar uintmax_t addr, sig; 273bcc5241cSMarcel Moolenaar register_t pc; 27472d44f31SMarcel Moolenaar if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' && 275bcc5241cSMarcel Moolenaar !gdb_rx_varhex(&addr)) { 276bcc5241cSMarcel Moolenaar pc = addr; 277bcc5241cSMarcel Moolenaar gdb_cpu_setreg(GDB_REG_PC, &pc); 278bcc5241cSMarcel Moolenaar } 27972d44f31SMarcel Moolenaar kdb_cpu_set_singlestep(); 2807d0c6c9fSSam Leffler gdb_listening = 1; 28172d44f31SMarcel Moolenaar return (1); 28272d44f31SMarcel Moolenaar } 28372d44f31SMarcel Moolenaar case 'T': { /* Thread alive. */ 28472d44f31SMarcel Moolenaar intmax_t tid; 2854af77eceSSam Leffler if (gdb_rx_varhex(&tid)) { 2864af77eceSSam Leffler gdb_tx_err(EINVAL); 2874af77eceSSam Leffler break; 2884af77eceSSam Leffler } 28972d44f31SMarcel Moolenaar if (kdb_thr_lookup(tid) != NULL) 29072d44f31SMarcel Moolenaar gdb_tx_ok(); 29172d44f31SMarcel Moolenaar else 29272d44f31SMarcel Moolenaar gdb_tx_err(ENOENT); 29372d44f31SMarcel Moolenaar break; 29472d44f31SMarcel Moolenaar } 29572d44f31SMarcel Moolenaar case -1: 29672d44f31SMarcel Moolenaar /* Empty command. Treat as unknown command. */ 29772d44f31SMarcel Moolenaar /* FALLTHROUGH */ 29872d44f31SMarcel Moolenaar default: 29972d44f31SMarcel Moolenaar /* Unknown command. Send empty response. */ 30072d44f31SMarcel Moolenaar gdb_tx_empty(); 30172d44f31SMarcel Moolenaar break; 30272d44f31SMarcel Moolenaar } 30372d44f31SMarcel Moolenaar } 304*3a5d3671SMatthew D Fleming (void)kdb_jmpbuf(prev_jb); 30572d44f31SMarcel Moolenaar return (0); 30672d44f31SMarcel Moolenaar } 307