1 /* $NetBSD: db_machdep.c,v 1.62 2026/02/24 00:28:19 mrg Exp $ */ 2 3 /* 4 * :set tabs=4 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 (at) 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 * db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) 31 * 32 * VAX enhancements by cmcmanis (at) mcmanis.com no rights reserved :-) 33 * 34 */ 35 36 /* 37 * Interface to new debugger. 38 * Taken from i386 port and modified for vax. 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.62 2026/02/24 00:28:19 mrg Exp $"); 43 44 #include "opt_multiprocessor.h" 45 46 #include <sys/param.h> 47 #include <sys/systm.h> /* just for boothowto --eichin */ 48 #include <sys/cpu.h> 49 #include <sys/device.h> 50 #include <sys/intr.h> 51 #include <sys/proc.h> 52 #include <sys/reboot.h> 53 54 #include <dev/cons.h> 55 56 #include <machine/db_machdep.h> 57 #include <machine/trap.h> 58 #include <machine/frame.h> 59 #include <machine/rpb.h> 60 #include <vax/vax/gencons.h> 61 62 #include <ddb/db_active.h> 63 #include <ddb/db_sym.h> 64 #include <ddb/db_command.h> 65 #include <ddb/db_output.h> 66 #include <ddb/db_extern.h> 67 #include <ddb/db_access.h> 68 #include <ddb/db_interface.h> 69 #include <ddb/db_variables.h> 70 #include <ddb/db_proc.h> 71 72 #include "ioconf.h" 73 74 db_regs_t ddb_regs; 75 76 void kdbprinttrap(int, int); 77 78 int db_active = 0; 79 80 static int splsave; /* IPL before entering debugger */ 81 82 #ifdef MULTIPROCESSOR 83 static struct cpu_info *stopcpu; 84 /* 85 * Only the master CPU is allowed to enter DDB, but the correct frames 86 * must still be there. Keep the state-machine here. 87 */ 88 static int 89 pause_cpus(void) 90 { 91 volatile struct cpu_info *ci = curcpu(); 92 93 if (stopcpu == NULL) { 94 stopcpu = curcpu(); 95 cpu_send_ipi(IPI_DEST_ALL, IPI_DDB); 96 } 97 if ((ci->ci_flags & CI_MASTERCPU) == 0) { 98 ci->ci_flags |= CI_STOPPED; 99 while (ci->ci_flags & CI_STOPPED) 100 ; 101 return 1; 102 } else 103 return 0; 104 } 105 106 static void 107 resume_cpus(void) 108 { 109 struct cpu_info *ci; 110 int i; 111 112 stopcpu = NULL; 113 for (i = 0; i < cpu_cd.cd_ndevs; i++) { 114 if ((ci = device_lookup_private(&cpu_cd, i)) == NULL) 115 continue; 116 ci->ci_flags &= ~CI_STOPPED; 117 } 118 } 119 #endif 120 /* 121 * VAX Call frame on the stack, this from 122 * "Computer Programming and Architecture, The VAX-11" 123 * Henry Levy & Richard Eckhouse Jr. 124 * ISBN 0-932376-07-X 125 */ 126 typedef struct __vax_frame { 127 u_int vax_cond; /* condition handler */ 128 u_int vax_psw:16; /* 16 bit processor status word */ 129 u_int vax_regs:12; /* Register save mask. */ 130 u_int vax_zero:1; /* Always zero */ 131 u_int vax_calls:1; /* True if CALLS, false if CALLG */ 132 u_int vax_spa:2; /* Stack pointer alignment */ 133 u_int *vax_ap; /* argument pointer */ 134 struct __vax_frame *vax_fp; /* frame pointer of previous frame */ 135 u_int vax_pc; /* program counter */ 136 u_int vax_args[1]; /* 0 or more arguments */ 137 } VAX_CALLFRAME; 138 139 /* 140 * DDB is called by either <ESC> - D on keyboard, via a TRACE or 141 * BPT trap or from kernel, normally as a result of a panic. 142 * If it is the result of a panic, set the ddb register frame to 143 * contain the registers when panic was called. (easy to debug). 144 */ 145 void 146 kdb_trap(struct trapframe *tf) 147 { 148 int s; 149 #ifdef MULTIPROCESSOR 150 struct cpu_info *ci = curcpu(); 151 #endif 152 153 switch (tf->tf_trap) { 154 case T_BPTFLT: /* breakpoint */ 155 case T_TRCTRAP: /* single_step */ 156 break; 157 158 /* XXX todo: should be migrated to use VAX_CALLFRAME at some point */ 159 case T_KDBTRAP: 160 #ifndef MULTIPROCESSOR /* No fancy panic stack conversion here */ 161 if (panicstr) { 162 struct callsframe *pf, *df; 163 164 df = (void *)tf->tf_fp; /* start of debug's calls */ 165 pf = (void *)df->ca_fp; /* start of panic's calls */ 166 memcpy(&ddb_regs.tf_r0, &pf->ca_argno, sizeof(int) * 12); 167 ddb_regs.tf_fp = pf->ca_fp; 168 ddb_regs.tf_pc = pf->ca_pc; 169 ddb_regs.tf_ap = pf->ca_ap; 170 ddb_regs.tf_sp = (unsigned)pf; 171 ddb_regs.tf_psl = tf->tf_psl & ~0x1fffe0; 172 ddb_regs.tf_psl |= pf->ca_maskpsw & 0xffe0; 173 ddb_regs.tf_psl |= (splsave << 16); 174 } 175 #endif 176 break; 177 178 default: 179 if ((boothowto & RB_KDB) == 0) 180 return; 181 182 kdbprinttrap(tf->tf_trap, tf->tf_code); 183 if (db_recover != 0) { 184 db_error("Faulted in DDB; continuing...\n"); 185 /*NOTREACHED*/ 186 } 187 } 188 189 #ifdef MULTIPROCESSOR 190 ci->ci_ddb_regs = tf; 191 if (pause_cpus()) 192 return; 193 #endif 194 #ifndef MULTIPROCESSOR 195 if (!panicstr) 196 memcpy(&ddb_regs, tf, sizeof(struct trapframe)); 197 #else 198 memcpy(&ddb_regs, stopcpu->ci_ddb_regs, sizeof(struct trapframe)); 199 printf("stopped on CPU %d\n", stopcpu->ci_cpuid); 200 #endif 201 202 /* XXX Should switch to interrupt stack here, if needed. */ 203 204 s = splhigh(); 205 db_active++; 206 cnpollc(true); 207 db_trap(tf->tf_trap, tf->tf_code); 208 cnpollc(false); 209 db_active--; 210 splx(s); 211 212 #ifndef MULTIPROCESSOR 213 if (!panicstr) 214 memcpy(tf, &ddb_regs, sizeof(struct trapframe)); 215 #else 216 memcpy(stopcpu->ci_ddb_regs, &ddb_regs, sizeof(struct trapframe)); 217 #endif 218 tf->tf_sp = mfpr(PR_USP); 219 #ifdef MULTIPROCESSOR 220 rpb.wait = 0; 221 resume_cpus(); 222 #endif 223 } 224 225 extern const char * const traptypes[]; 226 extern int no_traps; 227 228 /* 229 * Print trap reason. 230 */ 231 void 232 kdbprinttrap(int type, int code) 233 { 234 db_printf("kernel: "); 235 if (type >= no_traps || type < 0) 236 db_printf("type %d", type); 237 else 238 db_printf("%s", traptypes[type]); 239 db_printf(" trap, code=%x\n", code); 240 } 241 242 /* 243 * Check whether an address is accessible. 244 */ 245 bool 246 db_validate_address(vaddr_t addr) 247 { 248 struct proc *p = curproc; 249 struct pmap *pmap; 250 251 if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap || 252 addr >= VM_MIN_KERNEL_ADDRESS) 253 pmap = pmap_kernel(); 254 else 255 pmap = p->p_vmspace->vm_map.pmap; 256 257 return (pmap_extract(pmap, addr, NULL)); 258 } 259 260 /* 261 * Read bytes from kernel address space for debugger. 262 */ 263 void 264 db_read_bytes(vaddr_t addr, size_t size, char *data) 265 { 266 if (!db_validate_address(addr)) { 267 db_printf("address 0x%lx is inaccessible\n", addr); 268 db_error(NULL); 269 /*NOTREACHED*/ 270 } 271 272 memcpy(data, (void *)addr, size); 273 } 274 275 /* 276 * Write bytes to kernel address space for debugger. 277 */ 278 void 279 db_write_bytes(vaddr_t addr, size_t size, const char *data) 280 { 281 if (!db_validate_address(addr)) { 282 db_printf("address 0x%lx is inaccessible\n", addr); 283 db_error(NULL); 284 /*NOTREACHED*/ 285 } 286 287 memcpy((void *)addr, data, size); 288 } 289 290 void 291 Debugger(void) 292 { 293 splsave = splx(0xe); /* XXX WRONG (this can lower IPL) */ 294 setsoftddb(); /* beg for debugger */ 295 splx(splsave); 296 } 297 298 /* 299 * Machine register set. 300 */ 301 const struct db_variable db_regs[] = { 302 {"r0", &ddb_regs.tf_r0, FCN_NULL}, 303 {"r1", &ddb_regs.tf_r1, FCN_NULL}, 304 {"r2", &ddb_regs.tf_r2, FCN_NULL}, 305 {"r3", &ddb_regs.tf_r3, FCN_NULL}, 306 {"r4", &ddb_regs.tf_r4, FCN_NULL}, 307 {"r5", &ddb_regs.tf_r5, FCN_NULL}, 308 {"r6", &ddb_regs.tf_r6, FCN_NULL}, 309 {"r7", &ddb_regs.tf_r7, FCN_NULL}, 310 {"r8", &ddb_regs.tf_r8, FCN_NULL}, 311 {"r9", &ddb_regs.tf_r9, FCN_NULL}, 312 {"r10", &ddb_regs.tf_r10, FCN_NULL}, 313 {"r11", &ddb_regs.tf_r11, FCN_NULL}, 314 {"ap", &ddb_regs.tf_ap, FCN_NULL}, 315 {"fp", &ddb_regs.tf_fp, FCN_NULL}, 316 {"sp", &ddb_regs.tf_sp, FCN_NULL}, 317 {"pc", &ddb_regs.tf_pc, FCN_NULL}, 318 {"psl", &ddb_regs.tf_psl, FCN_NULL}, 319 }; 320 const struct db_variable * const db_eregs = db_regs + __arraycount(db_regs); 321 322 #define IN_USERLAND(x) (((u_int)(x) & 0x80000000) == 0) 323 324 /* 325 * Dump a stack traceback. Takes two arguments: 326 * fp - CALL FRAME pointer 327 * pr - printf-like function pointer for output 328 */ 329 static void 330 db_dump_stack(VAX_CALLFRAME *fp, void (*pr)(const char *, ...)) 331 { 332 u_int nargs, arg_base; 333 VAX_CALLFRAME *tmp_frame; 334 db_expr_t diff; 335 db_sym_t sym; 336 const char *symname; 337 extern int sret; 338 extern unsigned int etext; 339 340 (*pr)("Stack traceback:\n"); 341 if (IN_USERLAND(fp)) { 342 (*pr)("\t Process is executing in user space.\n"); 343 return; 344 } 345 346 if (!db_validate_address((vaddr_t)fp)) { 347 (*pr)("\t frame 0x%x inaccessible.\n", fp); 348 return; 349 } 350 351 while (!IN_USERLAND(fp->vax_fp) && 352 db_validate_address((vaddr_t)fp->vax_fp)) { 353 #define VAX_NUMARGS(x) ((x) & 0xff) 354 u_int pc = fp->vax_pc; 355 356 /* 357 * Figure out the arguments by using a bit of subtlety. 358 * As the argument pointer may have been used as a temporary 359 * by the callee ... recreate what it would have pointed to 360 * as follows: 361 * The vax_regs value is a 12 bit bitmask of the registers 362 * that were saved on the stack, corresponding to R0 to R11. 363 * By counting those bits, we get a value for arg_base so that 364 * args[arg_base] points to the longword that identifies the 365 * number of arguments. 366 * arg_base+1 - arg_base+n are the argument pointers/contents. 367 */ 368 369 /* 370 * If this was due to a trap/fault, pull the correct pc 371 * out of the trap frame. 372 */ 373 if (pc == (u_int) &sret && fp->vax_fp != 0) { 374 struct trapframe *tf; 375 376 /* Count saved register bits */ 377 arg_base = popcount(fp->vax_regs); 378 379 tf = (struct trapframe *) &fp->vax_args[arg_base + 2]; 380 if (!db_validate_address((vaddr_t)tf)) { 381 (*pr)("0x%lx: trap frame inaccessible.\n", tf); 382 return; 383 } 384 385 (*pr)("0x%lx: trap type=0x%lx code=0x%lx pc=0x%lx " 386 "psl=0x%lx\n", tf, tf->tf_trap, tf->tf_code, 387 tf->tf_pc, tf->tf_psl); 388 pc = tf->tf_pc; 389 } 390 391 diff = INT_MAX; 392 symname = NULL; 393 if (pc >= VM_MIN_KERNEL_ADDRESS && pc < (u_int) &etext) { 394 sym = db_search_symbol(pc, DB_STGY_ANY, &diff); 395 db_symbol_values(sym, &symname, 0); 396 } 397 if (symname != NULL) 398 (*pr)("0x%lx: %s+0x%lx(", fp, symname, diff); 399 else 400 (*pr)("0x%lx: %#x(", fp, pc); 401 402 /* First get the frame that called this function ... */ 403 tmp_frame = fp->vax_fp; 404 405 if (!tmp_frame->vax_calls) { 406 (*pr)("(Found CALLG, giving up)\n"); 407 return; 408 } 409 410 /* Count saved register bits */ 411 arg_base = popcount(tmp_frame->vax_regs); 412 413 /* number of arguments is then pointed to by vax_args[arg_base] */ 414 nargs = VAX_NUMARGS(tmp_frame->vax_args[arg_base]); 415 if (nargs) { 416 nargs--; /* reduce by one for formatting niceties */ 417 arg_base++; /* skip past the actual number of arguments */ 418 while (nargs--) 419 (*pr)("%#x,", tmp_frame->vax_args[arg_base++]); 420 421 /* now print out the last arg with closing brace and \n */ 422 (*pr)("%#x)\n", tmp_frame->vax_args[arg_base]); 423 } else 424 (*pr)("void)\n"); 425 /* move to the next frame */ 426 fp = fp->vax_fp; 427 } 428 } 429 430 static void 431 db_trace_process(struct lwp *l, struct proc *p, void (*pr)(const char *, ...)) 432 { 433 struct pcb *pcb; 434 435 KASSERT(l != NULL); 436 KASSERT(p != NULL); 437 438 if (!db_validate_address((vaddr_t)l)) { 439 (*pr)("LWP at %p inaccessible\n", l); 440 return; 441 } 442 443 if (!db_validate_address((vaddr_t)p)) { 444 (*pr)("Process at %p inaccessible\n", p); 445 return; 446 } 447 448 pcb = lwp_getpcb(l); 449 if (!db_validate_address((vaddr_t)pcb)) { 450 (*pr)("PCB at %p inaccessible\n", pcb); 451 return; 452 } 453 454 (*pr)("Process %d.%d\n", p->p_pid, l->l_lid); 455 (*pr)("\t PCB contents:\n"); 456 (*pr)(" KSP = 0x%x\n", (unsigned int)(pcb->KSP)); 457 (*pr)(" ESP = 0x%x\n", (unsigned int)(pcb->ESP)); 458 (*pr)(" SSP = 0x%x\n", (unsigned int)(pcb->SSP)); 459 (*pr)(" USP = 0x%x\n", (unsigned int)(pcb->USP)); 460 (*pr)(" R[00] = 0x%08x R[06] = 0x%08x\n", 461 (unsigned int)(pcb->R[0]), (unsigned int)(pcb->R[6])); 462 (*pr)(" R[01] = 0x%08x R[07] = 0x%08x\n", 463 (unsigned int)(pcb->R[1]), (unsigned int)(pcb->R[7])); 464 (*pr)(" R[02] = 0x%08x R[08] = 0x%08x\n", 465 (unsigned int)(pcb->R[2]), (unsigned int)(pcb->R[8])); 466 (*pr)(" R[03] = 0x%08x R[09] = 0x%08x\n", 467 (unsigned int)(pcb->R[3]), (unsigned int)(pcb->R[9])); 468 (*pr)(" R[04] = 0x%08x R[10] = 0x%08x\n", 469 (unsigned int)(pcb->R[4]), (unsigned int)(pcb->R[10])); 470 (*pr)(" R[05] = 0x%08x R[11] = 0x%08x\n", 471 (unsigned int)(pcb->R[5]), (unsigned int)(pcb->R[11])); 472 (*pr)(" AP = 0x%x\n", (unsigned int)(pcb->AP)); 473 (*pr)(" FP = 0x%x\n", (unsigned int)(pcb->FP)); 474 (*pr)(" PC = 0x%x\n", (unsigned int)(pcb->PC)); 475 (*pr)(" PSL = 0x%x\n", (unsigned int)(pcb->PSL)); 476 (*pr)(" Trap frame pointer: 0x%x\n", l->l_md.md_utf); 477 478 db_dump_stack((VAX_CALLFRAME *)(pcb->FP), pr); 479 480 return; 481 } 482 483 /* 484 * Implement the trace command which has the form: 485 * 486 * trace <-- Trace panic (same as before) 487 * trace 0x88888 <-- Trace frame whose address is 888888 488 * trace/t <-- Trace current process (0 if no current proc) 489 * trace/t 0tnn <-- Trace process nn (0t for decimal) 490 */ 491 void 492 db_stack_trace_print( 493 db_expr_t addr, /* Address parameter */ 494 bool have_addr, /* True if addr is valid */ 495 db_expr_t count, /* Optional count */ 496 const char *modif, /* pointer to flag modifier 't' */ 497 void (*pr)(const char *, ...)) /* Print function */ 498 { 499 struct lwp *l = curlwp; 500 struct proc *p = l->l_proc; 501 int trace_proc; 502 int trace_lwp; 503 const char *s; 504 505 /* Check to see if we're tracing a process or lwp */ 506 trace_proc = 0; 507 s = modif; 508 do { 509 switch (*s) { 510 case 't': 511 trace_proc++; 512 break; 513 514 case 'a': 515 trace_lwp++; 516 break; 517 } 518 } while (*s++ && !(trace_proc || trace_lwp)); 519 520 /* 521 * If we're here because of a panic, we'll always have an address of a 522 * frame. 523 * 524 * If the user typed an address, it can be one of the following: 525 * - the address of a struct lwp 526 * - the address of a struct proc 527 * - a PID, hex or decimal 528 * - the address of a frame 529 */ 530 if (have_addr) { 531 if (trace_lwp) { 532 l = (struct lwp *)addr; 533 p = l->l_proc; 534 db_trace_process(l, p, pr); 535 return; 536 } else if (trace_proc) { 537 p = db_proc_find((int)addr); 538 539 /* 540 * Try to be helpful by looking at it as if it were 541 * decimal. 542 */ 543 if (p == NULL) { 544 u_int tpid = 0; 545 u_int foo = addr; 546 547 while (foo != 0) { 548 int digit = (foo >> 28) & 0xf; 549 if (digit > 9) { 550 tpid = -1; 551 break; 552 } 553 tpid = tpid * 10 + digit; 554 foo = foo << 4; 555 } 556 p = db_proc_find(tpid); 557 } 558 559 /* Not a PID. If accessible, assume it's an address. */ 560 if (p == NULL) { 561 if (db_validate_address(addr)) { 562 p = (struct proc *)addr; 563 } else { 564 (*pr)("\t No such process.\n"); 565 return; 566 } 567 } 568 569 db_trace_process(p->p_lwps.lh_first, p, pr); 570 return; 571 } else { 572 db_dump_stack((VAX_CALLFRAME *)addr, pr); 573 return; 574 } 575 } else { 576 /* We got no address. Grab stuff from ddb_regs. */ 577 if (panicstr) 578 db_dump_stack((VAX_CALLFRAME *)ddb_regs.tf_fp, pr); 579 else 580 (*pr)("\t trace what?\n"); 581 } 582 } 583 584 static int ddbescape = 0; 585 586 int 587 kdbrint(int tkn) 588 { 589 if (ddbescape && ((tkn & 0x7f) == 'D')) { 590 setsoftddb(); 591 ddbescape = 0; 592 return 1; 593 } 594 595 if ((ddbescape == 0) && ((tkn & 0x7f) == 27)) { 596 ddbescape = 1; 597 return 1; 598 } 599 600 if (ddbescape) { 601 ddbescape = 0; 602 return 2; 603 } 604 605 ddbescape = 0; 606 return 0; 607 } 608 609 #ifdef MULTIPROCESSOR 610 611 static void 612 db_mach_cpu(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 613 { 614 struct cpu_info *ci; 615 616 if ((addr < 0) || (addr >= cpu_cd.cd_ndevs)) 617 return db_printf("%ld: CPU out of range\n", addr); 618 if ((ci = device_lookup_private(&cpu_cd, addr)) == NULL) 619 return db_printf("%ld: CPU not configured\n", addr); 620 621 if ((ci != curcpu()) && ((ci->ci_flags & CI_STOPPED) == 0)) 622 return db_printf("CPU %ld not stopped???\n", addr); 623 624 memcpy(stopcpu->ci_ddb_regs, &ddb_regs, sizeof(struct trapframe)); 625 stopcpu = ci; 626 memcpy(&ddb_regs, stopcpu->ci_ddb_regs, sizeof(struct trapframe)); 627 db_printf("using CPU %ld", addr); 628 if (ci->ci_curlwp) 629 db_printf(" in proc %d.%d (%s)\n", 630 ci->ci_curlwp->l_proc->p_pid, 631 ci->ci_curlwp->l_lid, 632 ci->ci_curlwp->l_proc->p_comm); 633 } 634 #endif 635 636 const struct db_command db_machine_command_table[] = { 637 #ifdef MULTIPROCESSOR 638 { DDB_ADD_CMD("cpu", db_mach_cpu, 0, 639 "switch to another cpu", "cpu-no", NULL) }, 640 #endif 641 { DDB_END_CMD }, 642 }; 643