gdb_main.c revision 158949
1208099Sdelphij/*- 2208099Sdelphij * Copyright (c) 2004 Marcel Moolenaar 3208099Sdelphij * All rights reserved. 4208099Sdelphij * 5208099Sdelphij * Redistribution and use in source and binary forms, with or without 6208099Sdelphij * modification, are permitted provided that the following conditions 7208099Sdelphij * are met: 8208099Sdelphij * 9208099Sdelphij * 1. Redistributions of source code must retain the above copyright 10208099Sdelphij * notice, this list of conditions and the following disclaimer. 11208099Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 12208099Sdelphij * notice, this list of conditions and the following disclaimer in the 13208099Sdelphij * documentation and/or other materials provided with the distribution. 14208099Sdelphij * 15208099Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16208099Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17208099Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18208099Sdelphij * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19208099Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20208099Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21208099Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22208099Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23208099Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24208099Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25208099Sdelphij */ 26208099Sdelphij 27208099Sdelphij#include <sys/cdefs.h> 28208099Sdelphij__FBSDID("$FreeBSD: head/sys/gdb/gdb_main.c 158949 2006-05-26 11:52:59Z phk $"); 29208099Sdelphij 30208099Sdelphij#include <sys/param.h> 31208099Sdelphij#include <sys/systm.h> 32208099Sdelphij#include <sys/kdb.h> 33208099Sdelphij#include <sys/kernel.h> 34208099Sdelphij#include <sys/pcpu.h> 35208099Sdelphij#include <sys/proc.h> 36208099Sdelphij#include <sys/reboot.h> 37208099Sdelphij 38208099Sdelphij#include <machine/gdb_machdep.h> 39208099Sdelphij#include <machine/kdb.h> 40208099Sdelphij 41208099Sdelphij#include <gdb/gdb.h> 42208099Sdelphij#include <gdb/gdb_int.h> 43208099Sdelphij 44208099Sdelphijstatic dbbe_init_f gdb_init; 45208099Sdelphijstatic dbbe_trap_f gdb_trap; 46208099Sdelphij 47208099SdelphijKDB_BACKEND(gdb, gdb_init, NULL, gdb_trap); 48208099Sdelphij 49208099Sdelphijstatic struct gdb_dbgport null_gdb_dbgport; 50208099SdelphijDATA_SET(gdb_dbgport_set, null_gdb_dbgport); 51208099SdelphijSET_DECLARE(gdb_dbgport_set, struct gdb_dbgport); 52208099Sdelphij 53208099Sdelphijstruct gdb_dbgport *gdb_cur = NULL; 54208099Sdelphijint gdb_listening = 0; 55208099Sdelphij 56208099Sdelphijstatic int 57208099Sdelphijgdb_init(void) 58208099Sdelphij{ 59208099Sdelphij struct gdb_dbgport *dp, **iter; 60208099Sdelphij int cur_pri, pri; 61208099Sdelphij 62208099Sdelphij gdb_cur = NULL; 63208099Sdelphij cur_pri = -1; 64208099Sdelphij SET_FOREACH(iter, gdb_dbgport_set) { 65208099Sdelphij dp = *iter; 66208099Sdelphij pri = (dp->gdb_probe != NULL) ? dp->gdb_probe() : -1; 67208099Sdelphij dp->gdb_active = (pri >= 0) ? 0 : -1; 68208099Sdelphij if (pri > cur_pri) { 69208099Sdelphij cur_pri = pri; 70208099Sdelphij gdb_cur = dp; 71208099Sdelphij } 72208099Sdelphij } 73208099Sdelphij if (gdb_cur != NULL) { 74208099Sdelphij printf("GDB: debug ports:"); 75208099Sdelphij SET_FOREACH(iter, gdb_dbgport_set) { 76208099Sdelphij dp = *iter; 77208099Sdelphij if (dp->gdb_active == 0) 78208099Sdelphij printf(" %s", dp->gdb_name); 79208099Sdelphij } 80208099Sdelphij printf("\n"); 81208099Sdelphij } else 82208099Sdelphij printf("GDB: no debug ports present\n"); 83208099Sdelphij if (gdb_cur != NULL) { 84208099Sdelphij gdb_cur->gdb_init(); 85208099Sdelphij printf("GDB: current port: %s\n", gdb_cur->gdb_name); 86208099Sdelphij } 87208099Sdelphij if (gdb_cur != NULL) { 88208099Sdelphij cur_pri = (boothowto & RB_GDB) ? 2 : 0; 89208099Sdelphij gdb_consinit(); 90208099Sdelphij } else 91208099Sdelphij cur_pri = -1; 92208099Sdelphij return (cur_pri); 93208099Sdelphij} 94208099Sdelphij 95208099Sdelphijstatic int 96208099Sdelphijgdb_trap(int type, int code) 97208099Sdelphij{ 98208099Sdelphij struct thread *thr_iter; 99208099Sdelphij 100208099Sdelphij gdb_listening = 0; 101292588Sdelphij /* 102292588Sdelphij * Send a T packet. We currently do not support watchpoints (the 103292588Sdelphij * awatch, rwatch or watch elements). 104292588Sdelphij */ 105292588Sdelphij gdb_tx_begin('T'); 106292588Sdelphij gdb_tx_hex(gdb_cpu_signal(type, code), 2); 107292588Sdelphij gdb_tx_varhex(GDB_REG_PC); 108292588Sdelphij gdb_tx_char(':'); 109208099Sdelphij gdb_tx_reg(GDB_REG_PC); 110208099Sdelphij gdb_tx_char(';'); 111292588Sdelphij gdb_tx_str("thread:"); 112208099Sdelphij gdb_tx_varhex((long)kdb_thread->td_tid); 113292588Sdelphij gdb_tx_char(';'); 114208099Sdelphij gdb_tx_end(); /* XXX check error condition. */ 115208099Sdelphij 116208099Sdelphij thr_iter = NULL; 117208099Sdelphij while (gdb_rx_begin() == 0) { 118208099Sdelphij /* printf("GDB: got '%s'\n", gdb_rxp); */ 119208099Sdelphij switch (gdb_rx_char()) { 120208099Sdelphij case '?': /* Last signal. */ 121208099Sdelphij gdb_tx_begin('S'); 122208099Sdelphij gdb_tx_hex(gdb_cpu_signal(type, code), 2); 123208099Sdelphij gdb_tx_end(); 124208099Sdelphij break; 125208099Sdelphij case 'c': { /* Continue. */ 126208099Sdelphij uintmax_t addr; 127208099Sdelphij register_t pc; 128208099Sdelphij if (!gdb_rx_varhex(&addr)) { 129208099Sdelphij pc = addr; 130208099Sdelphij gdb_cpu_setreg(GDB_REG_PC, &pc); 131208099Sdelphij } 132208099Sdelphij kdb_cpu_clear_singlestep(); 133208099Sdelphij gdb_listening = 1; 134208099Sdelphij return (1); 135208099Sdelphij } 136292588Sdelphij case 'C': { /* Continue with signal. */ 137208099Sdelphij uintmax_t addr, sig; 138208099Sdelphij register_t pc; 139208099Sdelphij if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' && 140208099Sdelphij !gdb_rx_varhex(&addr)) { 141208099Sdelphij pc = addr; 142208099Sdelphij gdb_cpu_setreg(GDB_REG_PC, &pc); 143208099Sdelphij } 144208099Sdelphij kdb_cpu_clear_singlestep(); 145208099Sdelphij gdb_listening = 1; 146208099Sdelphij return (1); 147208099Sdelphij } 148208099Sdelphij case 'g': { /* Read registers. */ 149208099Sdelphij size_t r; 150208099Sdelphij gdb_tx_begin(0); 151208099Sdelphij for (r = 0; r < GDB_NREGS; r++) 152208099Sdelphij gdb_tx_reg(r); 153208099Sdelphij gdb_tx_end(); 154208099Sdelphij break; 155208099Sdelphij } 156208099Sdelphij case 'G': /* Write registers. */ 157208099Sdelphij gdb_tx_err(0); 158208099Sdelphij break; 159208099Sdelphij case 'H': { /* Set thread. */ 160208099Sdelphij intmax_t tid; 161208099Sdelphij struct thread *thr; 162208099Sdelphij gdb_rx_char(); 163208099Sdelphij if (gdb_rx_varhex(&tid)) { 164208099Sdelphij gdb_tx_err(EINVAL); 165208099Sdelphij break; 166208099Sdelphij } 167208099Sdelphij if (tid > 0) { 168208099Sdelphij thr = kdb_thr_lookup(tid); 169292588Sdelphij if (thr == NULL) { 170208099Sdelphij gdb_tx_err(ENOENT); 171208099Sdelphij break; 172208099Sdelphij } 173292588Sdelphij kdb_thr_select(thr); 174292588Sdelphij } 175292588Sdelphij gdb_tx_ok(); 176292588Sdelphij break; 177292588Sdelphij } 178292588Sdelphij case 'k': /* Kill request. */ 179208099Sdelphij kdb_cpu_clear_singlestep(); 180208099Sdelphij gdb_listening = 1; 181208099Sdelphij return (1); 182208099Sdelphij case 'm': { /* Read memory. */ 183208099Sdelphij uintmax_t addr, size; 184208099Sdelphij if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' || 185208099Sdelphij gdb_rx_varhex(&size)) { 186208099Sdelphij gdb_tx_err(EINVAL); 187208099Sdelphij break; 188208099Sdelphij } 189208099Sdelphij gdb_tx_begin(0); 190208099Sdelphij if (gdb_tx_mem((char *)(uintptr_t)addr, size)) 191208099Sdelphij gdb_tx_end(); 192208099Sdelphij else 193208099Sdelphij gdb_tx_err(EIO); 194208099Sdelphij break; 195208099Sdelphij } 196208099Sdelphij case 'M': { /* Write memory. */ 197208099Sdelphij uintmax_t addr, size; 198208099Sdelphij if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' || 199208099Sdelphij gdb_rx_varhex(&size) || gdb_rx_char() != ':') { 200208099Sdelphij gdb_tx_err(EINVAL); 201208099Sdelphij break; 202208099Sdelphij } 203208099Sdelphij if (gdb_rx_mem((char *)(uintptr_t)addr, size) == 0) 204292588Sdelphij gdb_tx_err(EIO); 205208099Sdelphij else 206208099Sdelphij gdb_tx_ok(); 207 break; 208 } 209 case 'P': { /* Write register. */ 210 char *val; 211 uintmax_t reg; 212 val = gdb_rxp; 213 if (gdb_rx_varhex(®) || gdb_rx_char() != '=' || 214 !gdb_rx_mem(val, gdb_cpu_regsz(reg))) { 215 gdb_tx_err(EINVAL); 216 break; 217 } 218 gdb_cpu_setreg(reg, val); 219 gdb_tx_ok(); 220 break; 221 } 222 case 'q': /* General query. */ 223 if (gdb_rx_equal("fThreadInfo")) { 224 thr_iter = kdb_thr_first(); 225 gdb_tx_begin('m'); 226 gdb_tx_hex((long)thr_iter->td_tid, 8); 227 gdb_tx_end(); 228 } else if (gdb_rx_equal("sThreadInfo")) { 229 if (thr_iter == NULL) { 230 gdb_tx_err(ENXIO); 231 break; 232 } 233 thr_iter = kdb_thr_next(thr_iter); 234 if (thr_iter != NULL) { 235 gdb_tx_begin('m'); 236 gdb_tx_hex((long)thr_iter->td_tid, 8); 237 gdb_tx_end(); 238 } else { 239 gdb_tx_begin('l'); 240 gdb_tx_end(); 241 } 242 } else if (!gdb_cpu_query()) 243 gdb_tx_empty(); 244 break; 245 case 's': { /* Step. */ 246 uintmax_t addr; 247 register_t pc; 248 if (!gdb_rx_varhex(&addr)) { 249 pc = addr; 250 gdb_cpu_setreg(GDB_REG_PC, &pc); 251 } 252 kdb_cpu_set_singlestep(); 253 gdb_listening = 1; 254 return (1); 255 } 256 case 'S': { /* Step with signal. */ 257 uintmax_t addr, sig; 258 register_t pc; 259 if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' && 260 !gdb_rx_varhex(&addr)) { 261 pc = addr; 262 gdb_cpu_setreg(GDB_REG_PC, &pc); 263 } 264 kdb_cpu_set_singlestep(); 265 gdb_listening = 1; 266 return (1); 267 } 268 case 'T': { /* Thread alive. */ 269 intmax_t tid; 270 if (gdb_rx_varhex(&tid)) { 271 gdb_tx_err(EINVAL); 272 break; 273 } 274 if (kdb_thr_lookup(tid) != NULL) 275 gdb_tx_ok(); 276 else 277 gdb_tx_err(ENOENT); 278 break; 279 } 280 case -1: 281 /* Empty command. Treat as unknown command. */ 282 /* FALLTHROUGH */ 283 default: 284 /* Unknown command. Send empty response. */ 285 gdb_tx_empty(); 286 break; 287 } 288 } 289 return (0); 290} 291