1 /* $NetBSD: db_interface.c,v 1.63 2020/12/03 07:45:52 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Scott K. Stevens 5 * 6 * Mach Operating System 7 * Copyright (c) 1991,1990 Carnegie Mellon University 8 * All Rights Reserved. 9 * 10 * Permission to use, copy, modify and distribute this software and its 11 * documentation is hereby granted, provided that both the copyright 12 * notice and this permission notice appear in all copies of the 13 * software, derivative works or modified versions, and any portions 14 * thereof, and that both notices appear in supporting documentation. 15 * 16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 18 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19 * 20 * Carnegie Mellon requests users of this software to return to 21 * 22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23 * School of Computer Science 24 * Carnegie Mellon University 25 * Pittsburgh PA 15213-3890 26 * 27 * any improvements or extensions that they make and grant Carnegie the 28 * rights to redistribute these changes. 29 * 30 * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) 31 */ 32 33 /* 34 * Interface to new debugger. 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.63 2020/12/03 07:45:52 skrll Exp $"); 39 40 #include "opt_ddb.h" 41 #include "opt_kgdb.h" 42 #include "opt_multiprocessor.h" 43 44 #include <sys/param.h> 45 46 #include <sys/atomic.h> 47 #include <sys/exec.h> 48 #include <sys/intr.h> 49 #include <sys/proc.h> 50 #include <sys/reboot.h> 51 #include <sys/systm.h> /* just for boothowto */ 52 53 #include <uvm/uvm_extern.h> 54 55 #include <arm/arm32/db_machdep.h> 56 #include <arm/undefined.h> 57 #include <ddb/db_access.h> 58 #include <ddb/db_command.h> 59 #include <ddb/db_output.h> 60 #include <ddb/db_variables.h> 61 #include <ddb/db_sym.h> 62 #include <ddb/db_extern.h> 63 #include <ddb/db_interface.h> 64 #include <dev/cons.h> 65 66 #if defined(KGDB) || !defined(DDB) 67 #define db_printf printf 68 #endif 69 70 u_int db_fetch_reg(int, db_regs_t *); 71 72 int db_trapper(u_int, u_int, trapframe_t *, int); 73 74 int db_active = 0; 75 db_regs_t ddb_regs; /* register state */ 76 db_regs_t *ddb_regp; 77 78 #ifdef MULTIPROCESSOR 79 volatile struct cpu_info *db_onproc; 80 volatile struct cpu_info *db_newcpu; 81 #endif 82 83 84 85 86 #ifdef DDB 87 /* 88 * kdb_trap - field a TRACE or BPT trap 89 */ 90 int 91 kdb_trap(int type, db_regs_t *regs) 92 { 93 struct cpu_info * const ci = curcpu(); 94 db_regs_t dbreg; 95 int s; 96 97 switch (type) { 98 case T_BREAKPOINT: /* breakpoint */ 99 case -1: /* keyboard interrupt */ 100 break; 101 #ifdef MULTIPROCESSOR 102 case -2: 103 /* 104 * We called to enter ddb from another process but by the time 105 * we got here, no one was in ddb. So ignore the request. 106 */ 107 if (db_onproc == NULL) 108 return 1; 109 break; 110 #endif 111 default: 112 if (db_recover != 0) { 113 /* This will longjmp back into db_command_loop() */ 114 db_error("Faulted in DDB; continuing...\n"); 115 /*NOTREACHED*/ 116 } 117 } 118 119 /* Should switch to kdb`s own stack here. */ 120 121 #ifdef MULTIPROCESSOR 122 const bool is_mp_p = ncpu > 1; 123 if (is_mp_p) { 124 /* 125 * Try to take ownership of DDB. If we do, tell all other 126 * CPUs to enter DDB too. 127 */ 128 if (atomic_cas_ptr(&db_onproc, NULL, ci) == NULL) { 129 intr_ipi_send(NULL, IPI_DDB); 130 } 131 } 132 for (;;) { 133 if (is_mp_p) { 134 /* 135 * While we aren't the master, wait until the master 136 * gives control to us or exits. If it exited, we 137 * just exit too. Otherwise this cpu will enter DDB. 138 */ 139 membar_consumer(); 140 while (db_onproc != ci) { 141 if (db_onproc == NULL) 142 return 1; 143 #ifdef _ARM_ARCH_6 144 __asm __volatile("wfe"); 145 membar_consumer(); 146 #endif 147 if (db_onproc == ci) { 148 printf("%s: switching to %s\n", 149 __func__, ci->ci_cpuname); 150 } 151 } 152 } 153 #endif 154 155 s = splhigh(); 156 ci->ci_ddb_regs = &dbreg; 157 ddb_regp = &dbreg; 158 ddb_regs = *regs; 159 160 atomic_inc_32(&db_active); 161 cnpollc(true); 162 db_trap(type, 0/*code*/); 163 cnpollc(false); 164 atomic_dec_32(&db_active); 165 166 ci->ci_ddb_regs = NULL; 167 ddb_regp = &dbreg; 168 *regs = ddb_regs; 169 splx(s); 170 171 #ifdef MULTIPROCESSOR 172 if (is_mp_p && db_newcpu != NULL) { 173 db_onproc = db_newcpu; 174 db_newcpu = NULL; 175 dsb(ishst); 176 sev(); 177 continue; 178 } 179 break; 180 } 181 182 if (is_mp_p) { 183 /* 184 * We are exiting DDB so there is noone onproc. Tell 185 * the other CPUs to exit. 186 */ 187 db_onproc = NULL; 188 dsb(ishst); 189 sev(); 190 } 191 #endif 192 193 return 1; 194 } 195 #endif 196 197 int 198 db_validate_address(vaddr_t addr) 199 { 200 struct proc *p = curproc; 201 struct pmap *pmap; 202 203 if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap || 204 addr >= VM_MIN_KERNEL_ADDRESS 205 ) 206 pmap = pmap_kernel(); 207 else 208 pmap = p->p_vmspace->vm_map.pmap; 209 210 return pmap_extract(pmap, addr, NULL) == false; 211 } 212 213 /* 214 * Read bytes from kernel address space for debugger. 215 */ 216 void 217 db_read_bytes(vaddr_t addr, size_t size, char *data) 218 { 219 char *src = (char *)addr; 220 221 if (db_validate_address((u_int)src)) { 222 db_printf("address %p is invalid\n", src); 223 return; 224 } 225 226 if (size == 4 && (addr & 3) == 0 && ((uintptr_t)data & 3) == 0) { 227 *((int*)data) = *((int*)src); 228 return; 229 } 230 231 if (size == 2 && (addr & 1) == 0 && ((uintptr_t)data & 1) == 0) { 232 *((short*)data) = *((short*)src); 233 return; 234 } 235 236 while (size-- > 0) { 237 if (db_validate_address((u_int)src)) { 238 db_printf("address %p is invalid\n", src); 239 return; 240 } 241 *data++ = *src++; 242 } 243 } 244 245 static void 246 db_write_text(vaddr_t addr, size_t size, const char *data) 247 { 248 249 ktext_write((void *)addr, data, size); 250 } 251 252 /* 253 * Write bytes to kernel address space for debugger. 254 */ 255 void 256 db_write_bytes(vaddr_t addr, size_t size, const char *data) 257 { 258 extern char kernel_text[]; 259 extern char etext[]; 260 char *dst; 261 size_t loop; 262 263 /* If any part is in kernel text, use db_write_text() */ 264 if (addr >= (vaddr_t) kernel_text && addr < (vaddr_t) etext) { 265 db_write_text(addr, size, data); 266 return; 267 } 268 269 dst = (char *)addr; 270 if (db_validate_address((u_int)dst)) { 271 db_printf("address %p is invalid\n", dst); 272 return; 273 } 274 275 if (size == 4 && (addr & 3) == 0 && ((uintptr_t)data & 3) == 0) 276 *((int*)dst) = *((const int *)data); 277 else 278 if (size == 2 && (addr & 1) == 0 && ((uintptr_t)data & 1) == 0) 279 *((short*)dst) = *((const short *)data); 280 else { 281 loop = size; 282 while (loop-- > 0) { 283 if (db_validate_address((u_int)dst)) { 284 db_printf("address %p is invalid\n", dst); 285 return; 286 } 287 *dst++ = *data++; 288 } 289 } 290 291 /* make sure the caches and memory are in sync */ 292 cpu_icache_sync_range(addr, size); 293 294 /* In case the current page tables have been modified ... */ 295 cpu_tlb_flushID(); 296 cpu_cpwait(); 297 } 298 299 #ifdef DDB 300 void 301 cpu_Debugger(void) 302 { 303 #ifdef _ARM_ARCH_BE8 304 __asm(".word 0xffffffe7"); 305 #else 306 __asm(".word 0xe7ffffff"); 307 #endif 308 } 309 310 int 311 db_trapper(u_int addr, u_int inst, trapframe_t *frame, int fault_code) 312 { 313 314 if (fault_code == 0) { 315 if ((inst & ~INSN_COND_MASK) == (BKPT_INST & ~INSN_COND_MASK)) 316 kdb_trap(T_BREAKPOINT, frame); 317 else 318 kdb_trap(-1, frame); 319 } else 320 return 1; 321 return 0; 322 } 323 324 extern u_int esym; 325 extern u_int end; 326 327 static struct undefined_handler db_uh; 328 329 void 330 db_machine_init(void) 331 { 332 333 /* 334 * We get called before malloc() is available, so supply a static 335 * struct undefined_handler. 336 */ 337 db_uh.uh_handler = db_trapper; 338 install_coproc_handler_static(CORE_UNKNOWN_HANDLER, &db_uh); 339 } 340 #endif 341 342 u_int 343 db_fetch_reg(int reg, db_regs_t *regs) 344 { 345 346 switch (reg) { 347 case 0: 348 return regs->tf_r0; 349 case 1: 350 return regs->tf_r1; 351 case 2: 352 return regs->tf_r2; 353 case 3: 354 return regs->tf_r3; 355 case 4: 356 return regs->tf_r4; 357 case 5: 358 return regs->tf_r5; 359 case 6: 360 return regs->tf_r6; 361 case 7: 362 return regs->tf_r7; 363 case 8: 364 return regs->tf_r8; 365 case 9: 366 return regs->tf_r9; 367 case 10: 368 return regs->tf_r10; 369 case 11: 370 return regs->tf_r11; 371 case 12: 372 return regs->tf_r12; 373 case 13: 374 return regs->tf_svc_sp; 375 case 14: 376 return regs->tf_svc_lr; 377 case 15: 378 return regs->tf_pc; 379 default: 380 panic("db_fetch_reg: botch"); 381 } 382 } 383 384 u_int 385 branch_taken(u_int insn, u_int pc, db_regs_t *regs) 386 { 387 u_int addr, nregs; 388 389 switch ((insn >> 24) & 0xf) { 390 case 0xa: /* b ... */ 391 case 0xb: /* bl ... */ 392 addr = ((insn << 2) & 0x03ffffff); 393 if (addr & 0x02000000) 394 addr |= 0xfc000000; 395 return pc + 8 + addr; 396 case 0x7: /* ldr pc, [pc, reg, lsl #2] */ 397 addr = db_fetch_reg(insn & 0xf, regs); 398 addr = pc + 8 + (addr << 2); 399 db_read_bytes(addr, 4, (char *)&addr); 400 return addr; 401 case 0x5: /* ldr pc, [reg] */ 402 addr = db_fetch_reg((insn >> 16) & 0xf, regs); 403 db_read_bytes(addr, 4, (char *)&addr); 404 return addr; 405 case 0x1: /* mov pc, reg */ 406 addr = db_fetch_reg(insn & 0xf, regs); 407 return addr; 408 case 0x8: /* ldmxx reg, {..., pc} */ 409 case 0x9: 410 addr = db_fetch_reg((insn >> 16) & 0xf, regs); 411 nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555); 412 nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333); 413 nregs = (nregs + (nregs >> 4)) & 0x0f0f; 414 nregs = (nregs + (nregs >> 8)) & 0x001f; 415 switch ((insn >> 23) & 0x3) { 416 case 0x0: /* ldmda */ 417 addr = addr - 0; 418 break; 419 case 0x1: /* ldmia */ 420 addr = addr + 0 + ((nregs - 1) << 2); 421 break; 422 case 0x2: /* ldmdb */ 423 addr = addr - 4; 424 break; 425 case 0x3: /* ldmib */ 426 addr = addr + 4 + ((nregs - 1) << 2); 427 break; 428 } 429 db_read_bytes(addr, 4, (char *)&addr); 430 return addr; 431 default: 432 panic("branch_taken: botch"); 433 } 434 } 435