gdb_main.c revision 234196
1139778Simp/*- 2131899Smarcel * Copyright (c) 2004 Marcel Moolenaar 3131899Smarcel * All rights reserved. 4131899Smarcel * 5131899Smarcel * Redistribution and use in source and binary forms, with or without 6131899Smarcel * modification, are permitted provided that the following conditions 7131899Smarcel * are met: 8131899Smarcel * 9131899Smarcel * 1. Redistributions of source code must retain the above copyright 10131899Smarcel * notice, this list of conditions and the following disclaimer. 11131899Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12131899Smarcel * notice, this list of conditions and the following disclaimer in the 13131899Smarcel * documentation and/or other materials provided with the distribution. 14131899Smarcel * 15131899Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16131899Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17131899Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18131899Smarcel * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19131899Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20131899Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21131899Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22131899Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23131899Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24131899Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25131899Smarcel */ 26131899Smarcel 27131899Smarcel#include <sys/cdefs.h> 28131899Smarcel__FBSDID("$FreeBSD: head/sys/gdb/gdb_main.c 234196 2012-04-12 21:34:58Z jhb $"); 29131899Smarcel 30131899Smarcel#include <sys/param.h> 31131899Smarcel#include <sys/systm.h> 32131899Smarcel#include <sys/kdb.h> 33131899Smarcel#include <sys/kernel.h> 34131899Smarcel#include <sys/pcpu.h> 35131899Smarcel#include <sys/proc.h> 36131899Smarcel#include <sys/reboot.h> 37131899Smarcel 38131899Smarcel#include <machine/gdb_machdep.h> 39131899Smarcel#include <machine/kdb.h> 40131899Smarcel 41131899Smarcel#include <gdb/gdb.h> 42131899Smarcel#include <gdb/gdb_int.h> 43131899Smarcel 44131899Smarcelstatic dbbe_init_f gdb_init; 45131899Smarcelstatic dbbe_trap_f gdb_trap; 46131899Smarcel 47131899SmarcelKDB_BACKEND(gdb, gdb_init, NULL, NULL, gdb_trap); 48131899Smarcel 49158949Sphkstatic struct gdb_dbgport null_gdb_dbgport; 50158949SphkDATA_SET(gdb_dbgport_set, null_gdb_dbgport); 51131899SmarcelSET_DECLARE(gdb_dbgport_set, struct gdb_dbgport); 52131899Smarcel 53131899Smarcelstruct gdb_dbgport *gdb_cur = NULL; 54157059Ssamint gdb_listening = 0; 55131899Smarcel 56131899Smarcelstatic int 57131899Smarcelgdb_init(void) 58131899Smarcel{ 59131899Smarcel struct gdb_dbgport *dp, **iter; 60131899Smarcel int cur_pri, pri; 61131899Smarcel 62131899Smarcel gdb_cur = NULL; 63131899Smarcel cur_pri = -1; 64131899Smarcel SET_FOREACH(iter, gdb_dbgport_set) { 65131899Smarcel dp = *iter; 66131899Smarcel pri = (dp->gdb_probe != NULL) ? dp->gdb_probe() : -1; 67131899Smarcel dp->gdb_active = (pri >= 0) ? 0 : -1; 68131899Smarcel if (pri > cur_pri) { 69131899Smarcel cur_pri = pri; 70131899Smarcel gdb_cur = dp; 71131899Smarcel } 72131899Smarcel } 73131899Smarcel if (gdb_cur != NULL) { 74131899Smarcel printf("GDB: debug ports:"); 75131899Smarcel SET_FOREACH(iter, gdb_dbgport_set) { 76131899Smarcel dp = *iter; 77131899Smarcel if (dp->gdb_active == 0) 78131899Smarcel printf(" %s", dp->gdb_name); 79131899Smarcel } 80131899Smarcel printf("\n"); 81131899Smarcel } else 82131899Smarcel printf("GDB: no debug ports present\n"); 83131899Smarcel if (gdb_cur != NULL) { 84131899Smarcel gdb_cur->gdb_init(); 85131899Smarcel printf("GDB: current port: %s\n", gdb_cur->gdb_name); 86131899Smarcel } 87157059Ssam if (gdb_cur != NULL) { 88131899Smarcel cur_pri = (boothowto & RB_GDB) ? 2 : 0; 89157059Ssam gdb_consinit(); 90157059Ssam } else 91131899Smarcel cur_pri = -1; 92131899Smarcel return (cur_pri); 93131899Smarcel} 94131899Smarcel 95131899Smarcelstatic int 96131899Smarcelgdb_trap(int type, int code) 97131899Smarcel{ 98131899Smarcel jmp_buf jb; 99131899Smarcel struct thread *thr_iter; 100157059Ssam void *prev_jb; 101131899Smarcel 102131899Smarcel prev_jb = kdb_jmpbuf(jb); 103131899Smarcel if (setjmp(jb) != 0) { 104131899Smarcel printf("%s bailing, hopefully back to ddb!\n", __func__); 105131899Smarcel gdb_listening = 0; 106131899Smarcel (void)kdb_jmpbuf(prev_jb); 107131899Smarcel return (1); 108131899Smarcel } 109131899Smarcel 110131899Smarcel gdb_listening = 0; 111131899Smarcel /* 112131899Smarcel * Send a T packet. We currently do not support watchpoints (the 113131899Smarcel * awatch, rwatch or watch elements). 114131899Smarcel */ 115131899Smarcel gdb_tx_begin('T'); 116131899Smarcel gdb_tx_hex(gdb_cpu_signal(type, code), 2); 117131899Smarcel gdb_tx_varhex(GDB_REG_PC); 118133446Smarcel gdb_tx_char(':'); 119131899Smarcel gdb_tx_reg(GDB_REG_PC); 120131899Smarcel gdb_tx_char(';'); 121131899Smarcel gdb_tx_str("thread:"); 122131899Smarcel gdb_tx_varhex((long)kdb_thread->td_tid); 123131899Smarcel gdb_tx_char(';'); 124131899Smarcel gdb_tx_end(); /* XXX check error condition. */ 125131899Smarcel 126131899Smarcel thr_iter = NULL; 127138253Smarcel while (gdb_rx_begin() == 0) { 128138253Smarcel /* printf("GDB: got '%s'\n", gdb_rxp); */ 129138253Smarcel switch (gdb_rx_char()) { 130138253Smarcel case '?': /* Last signal. */ 131138253Smarcel gdb_tx_begin('S'); 132131899Smarcel gdb_tx_hex(gdb_cpu_signal(type, code), 2); 133157059Ssam gdb_tx_end(); 134131899Smarcel break; 135131899Smarcel case 'c': { /* Continue. */ 136131899Smarcel uintmax_t addr; 137131899Smarcel register_t pc; 138138253Smarcel if (!gdb_rx_varhex(&addr)) { 139131899Smarcel pc = addr; 140138253Smarcel gdb_cpu_setreg(GDB_REG_PC, &pc); 141138253Smarcel } 142138253Smarcel kdb_cpu_clear_singlestep(); 143138253Smarcel gdb_listening = 1; 144131899Smarcel return (1); 145157059Ssam } 146131899Smarcel case 'C': { /* Continue with signal. */ 147131899Smarcel uintmax_t addr, sig; 148131899Smarcel register_t pc; 149131899Smarcel if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' && 150131899Smarcel !gdb_rx_varhex(&addr)) { 151131899Smarcel pc = addr; 152131899Smarcel gdb_cpu_setreg(GDB_REG_PC, &pc); 153131899Smarcel } 154131899Smarcel kdb_cpu_clear_singlestep(); 155131899Smarcel gdb_listening = 1; 156131899Smarcel return (1); 157131899Smarcel } 158131899Smarcel case 'D': { /* Detach */ 159131899Smarcel gdb_tx_ok(); 160131899Smarcel kdb_cpu_clear_singlestep(); 161131899Smarcel return (1); 162131899Smarcel } 163144245Ssam case 'g': { /* Read registers. */ 164144245Ssam size_t r; 165144245Ssam gdb_tx_begin(0); 166144245Ssam for (r = 0; r < GDB_NREGS; r++) 167131899Smarcel gdb_tx_reg(r); 168131899Smarcel gdb_tx_end(); 169131899Smarcel break; 170131899Smarcel } 171131899Smarcel case 'G': /* Write registers. */ 172131899Smarcel gdb_tx_err(0); 173131899Smarcel break; 174131899Smarcel case 'H': { /* Set thread. */ 175131899Smarcel intmax_t tid; 176131899Smarcel struct thread *thr; 177131899Smarcel gdb_rx_char(); 178131899Smarcel if (gdb_rx_varhex(&tid)) { 179131899Smarcel gdb_tx_err(EINVAL); 180157059Ssam break; 181131899Smarcel } 182131899Smarcel if (tid > 0) { 183131899Smarcel thr = kdb_thr_lookup(tid); 184131899Smarcel if (thr == NULL) { 185131899Smarcel gdb_tx_err(ENOENT); 186131899Smarcel break; 187131899Smarcel } 188131899Smarcel kdb_thr_select(thr); 189131899Smarcel } 190131899Smarcel gdb_tx_ok(); 191131899Smarcel break; 192131899Smarcel } 193131899Smarcel case 'k': /* Kill request. */ 194131899Smarcel kdb_cpu_clear_singlestep(); 195131899Smarcel gdb_listening = 1; 196131899Smarcel return (1); 197131899Smarcel case 'm': { /* Read memory. */ 198131899Smarcel uintmax_t addr, size; 199131899Smarcel if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' || 200131899Smarcel gdb_rx_varhex(&size)) { 201131899Smarcel gdb_tx_err(EINVAL); 202131899Smarcel break; 203131899Smarcel } 204131899Smarcel gdb_tx_begin(0); 205131899Smarcel if (gdb_tx_mem((char *)(uintptr_t)addr, size)) 206131899Smarcel gdb_tx_end(); 207131899Smarcel else 208131899Smarcel gdb_tx_err(EIO); 209131899Smarcel break; 210138253Smarcel } 211138253Smarcel case 'M': { /* Write memory. */ 212138253Smarcel uintmax_t addr, size; 213131899Smarcel if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' || 214138253Smarcel gdb_rx_varhex(&size) || gdb_rx_char() != ':') { 215131899Smarcel gdb_tx_err(EINVAL); 216131899Smarcel break; 217131899Smarcel } 218131899Smarcel if (gdb_rx_mem((char *)(uintptr_t)addr, size) == 0) 219131899Smarcel gdb_tx_err(EIO); 220131899Smarcel else 221131899Smarcel gdb_tx_ok(); 222131899Smarcel break; 223131899Smarcel } 224131899Smarcel case 'P': { /* Write register. */ 225131899Smarcel char *val; 226131899Smarcel uintmax_t reg; 227131899Smarcel val = gdb_rxp; 228131899Smarcel if (gdb_rx_varhex(®) || gdb_rx_char() != '=' || 229131899Smarcel !gdb_rx_mem(val, gdb_cpu_regsz(reg))) { 230131899Smarcel gdb_tx_err(EINVAL); 231131899Smarcel break; 232131899Smarcel } 233131899Smarcel gdb_cpu_setreg(reg, val); 234131899Smarcel gdb_tx_ok(); 235131899Smarcel break; 236131899Smarcel } 237131899Smarcel case 'q': /* General query. */ 238131899Smarcel if (gdb_rx_equal("fThreadInfo")) { 239131899Smarcel thr_iter = kdb_thr_first(); 240131899Smarcel gdb_tx_begin('m'); 241131899Smarcel gdb_tx_hex((long)thr_iter->td_tid, 8); 242131899Smarcel gdb_tx_end(); 243131899Smarcel } else if (gdb_rx_equal("sThreadInfo")) { 244131899Smarcel if (thr_iter == NULL) { 245131899Smarcel gdb_tx_err(ENXIO); 246131899Smarcel break; 247138253Smarcel } 248138253Smarcel thr_iter = kdb_thr_next(thr_iter); 249138253Smarcel if (thr_iter != NULL) { 250138253Smarcel gdb_tx_begin('m'); 251138253Smarcel gdb_tx_hex((long)thr_iter->td_tid, 8); 252131899Smarcel gdb_tx_end(); 253157059Ssam } else { 254131899Smarcel gdb_tx_begin('l'); 255131899Smarcel gdb_tx_end(); 256131899Smarcel } 257131899Smarcel } else if (!gdb_cpu_query()) 258138253Smarcel gdb_tx_empty(); 259131899Smarcel break; 260138253Smarcel case 's': { /* Step. */ 261138253Smarcel uintmax_t addr; 262138253Smarcel register_t pc; 263138253Smarcel if (!gdb_rx_varhex(&addr)) { 264131899Smarcel pc = addr; 265157059Ssam gdb_cpu_setreg(GDB_REG_PC, &pc); 266131899Smarcel } 267131899Smarcel kdb_cpu_set_singlestep(); 268131899Smarcel gdb_listening = 1; 269131899Smarcel return (1); 270144245Ssam } 271144245Ssam case 'S': { /* Step with signal. */ 272144245Ssam uintmax_t addr, sig; 273144245Ssam register_t pc; 274131899Smarcel if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' && 275131899Smarcel !gdb_rx_varhex(&addr)) { 276131899Smarcel pc = addr; 277131899Smarcel gdb_cpu_setreg(GDB_REG_PC, &pc); 278131899Smarcel } 279131899Smarcel kdb_cpu_set_singlestep(); 280131899Smarcel gdb_listening = 1; 281131899Smarcel return (1); 282131899Smarcel } 283131899Smarcel case 'T': { /* Thread alive. */ 284131899Smarcel intmax_t tid; 285131899Smarcel if (gdb_rx_varhex(&tid)) { 286131899Smarcel gdb_tx_err(EINVAL); 287131899Smarcel break; 288131899Smarcel } 289131899Smarcel if (kdb_thr_lookup(tid) != NULL) 290131899Smarcel gdb_tx_ok(); 291 else 292 gdb_tx_err(ENOENT); 293 break; 294 } 295 case -1: 296 /* Empty command. Treat as unknown command. */ 297 /* FALLTHROUGH */ 298 default: 299 /* Unknown command. Send empty response. */ 300 gdb_tx_empty(); 301 break; 302 } 303 } 304 (void)kdb_jmpbuf(prev_jb); 305 return (0); 306} 307