1 /* $NetBSD: db_interface.c,v 1.98 2023/10/26 10:41:03 andvar Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1991,1990 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 * 28 * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) 29 */ 30 31 /* 32 * Interface to new debugger. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.98 2023/10/26 10:41:03 andvar Exp $"); 37 38 #ifdef _KERNEL_OPT 39 #include "opt_ddb.h" 40 #include "opt_kgdb.h" 41 #include "opt_multiprocessor.h" 42 #endif 43 44 #include <sys/param.h> 45 #include <sys/proc.h> 46 #include <sys/cpu.h> 47 #include <sys/reboot.h> 48 #include <sys/systm.h> 49 #include <sys/lwp.h> 50 51 #include <dev/cons.h> 52 53 #include <uvm/uvm.h> 54 55 #include <machine/db_machdep.h> 56 #include <machine/locore.h> 57 58 #include <ddb/db_access.h> 59 #include <ddb/db_active.h> 60 #include <ddb/ddbvar.h> 61 62 #if defined(DDB) || defined(_KMEMUSER) 63 #include <ddb/db_user.h> 64 #include <ddb/db_command.h> 65 #include <ddb/db_sym.h> 66 #include <ddb/db_variables.h> 67 #include <ddb/db_extern.h> 68 #include <ddb/db_output.h> 69 #include <ddb/db_interface.h> 70 #endif 71 #ifdef KGDB 72 #include <ddb/db_interface.h> 73 #endif 74 75 #include <machine/instr.h> 76 #if defined(_KERNEL) 77 #include <machine/promlib.h> 78 #endif 79 #include <machine/ctlreg.h> 80 #include <machine/pmap.h> 81 82 #if defined(_KERNEL) 83 #include <sparc/sparc/asm.h> 84 85 #include "fb.h" 86 87 /* 88 * Read bytes from kernel address space for debugger. 89 */ 90 void 91 db_read_bytes(vaddr_t addr, size_t size, char *data) 92 { 93 char *src; 94 95 src = (char *)addr; 96 while (size-- > 0) 97 *data++ = *src++; 98 } 99 100 /* 101 * Write bytes to kernel address space for debugger. 102 */ 103 void 104 db_write_bytes(vaddr_t addr, size_t size, const char *data) 105 { 106 char *dst; 107 108 dst = (char *)addr; 109 while (size-- > 0) { 110 if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS) && (dst < etext)) 111 pmap_writetext(dst, *data); 112 else 113 *dst = *data; 114 dst++, data++; 115 } 116 117 } 118 #endif 119 120 #if defined(DDB) 121 122 /* 123 * Data and functions used by DDB only. 124 */ 125 126 void 127 cpu_Debugger(void) 128 { 129 __asm("ta 0x81"); 130 sparc_noop(); /* Force this function to allocate a stack frame */ 131 } 132 133 #endif /* DDB */ 134 135 #if defined(DDB) || defined(_KMEMUSER) 136 137 int db_active = 0; 138 139 #ifdef _KERNEL 140 void kdb_kbd_trap(struct trapframe *); 141 void db_prom_cmd(db_expr_t, bool, db_expr_t, const char *); 142 void db_page_cmd(db_expr_t, bool, db_expr_t, const char *); 143 void db_proc_cmd(db_expr_t, bool, db_expr_t, const char *); 144 void db_dump_pcb(db_expr_t, bool, db_expr_t, const char *); 145 #endif 146 #ifdef MULTIPROCESSOR 147 void db_cpu_cmd(db_expr_t, bool, db_expr_t, const char *); 148 void db_xcall_cmd(db_expr_t, bool, db_expr_t, const char *); 149 #endif 150 151 #ifdef _KERNEL 152 /* 153 * Received keyboard interrupt sequence. 154 */ 155 void 156 kdb_kbd_trap(struct trapframe *tf) 157 { 158 if (db_active == 0 && (boothowto & RB_KDB)) { 159 printf("\n\nkernel: keyboard interrupt\n"); 160 kdb_trap(-1, tf); 161 } 162 } 163 #endif 164 165 /* struct cpu_info of CPU being investigated */ 166 struct cpu_info *ddb_cpuinfo; 167 168 #ifdef MULTIPROCESSOR 169 170 #define NOCPU -1 171 172 static int db_suspend_others(void); 173 static void db_resume_others(void); 174 void ddb_suspend(struct trapframe *); 175 176 /* from cpu.c */ 177 void mp_pause_cpus_ddb(void); 178 void mp_resume_cpus_ddb(void); 179 180 __cpu_simple_lock_t db_lock; 181 int ddb_cpu = NOCPU; 182 183 static int 184 db_suspend_others(void) 185 { 186 int cpu_me = cpu_number(); 187 int win; 188 189 __cpu_simple_lock(&db_lock); 190 if (ddb_cpu == NOCPU) 191 ddb_cpu = cpu_me; 192 win = (ddb_cpu == cpu_me); 193 __cpu_simple_unlock(&db_lock); 194 195 if (win) 196 mp_pause_cpus_ddb(); 197 198 return win; 199 } 200 201 static void 202 db_resume_others(void) 203 { 204 205 mp_resume_cpus_ddb(); 206 207 __cpu_simple_lock(&db_lock); 208 ddb_cpu = NOCPU; 209 __cpu_simple_unlock(&db_lock); 210 } 211 212 void 213 ddb_suspend(struct trapframe *tf) 214 { 215 volatile db_regs_t dbregs; 216 217 /* Initialise local dbregs storage from trap frame */ 218 dbregs.db_tf = *tf; 219 dbregs.db_fr = *(struct frame *)tf->tf_out[6]; 220 221 cpuinfo.ci_ddb_regs = &dbregs; 222 while (cpuinfo.flags & CPUFLG_PAUSED) /*void*/; 223 cpuinfo.ci_ddb_regs = NULL; 224 } 225 #endif /* MULTIPROCESSOR */ 226 227 #if defined(DDB) || defined(KGDB) 228 /* 229 * kdb_trap - field a TRACE or BPT trap 230 */ 231 int 232 kdb_trap(int type, struct trapframe *tf) 233 { 234 db_regs_t dbregs; 235 int s; 236 237 #if NFB > 0 238 fb_unblank(); 239 #endif 240 241 switch (type) { 242 case T_BREAKPOINT: /* breakpoint */ 243 case -1: /* keyboard interrupt */ 244 break; 245 default: 246 if (!db_onpanic && db_recover==0) 247 return (0); 248 249 printf("kernel: %s trap\n", trap_type[type & 0xff]); 250 if (db_recover != 0) { 251 db_error("Faulted in DDB; continuing...\n"); 252 /*NOTREACHED*/ 253 } 254 } 255 256 #ifdef MULTIPROCESSOR 257 if (!db_suspend_others()) { 258 ddb_suspend(tf); 259 return 1; 260 } 261 #endif 262 /* Initialise local dbregs storage from trap frame */ 263 dbregs.db_tf = *tf; 264 dbregs.db_fr = *(struct frame *)tf->tf_out[6]; 265 266 /* Setup current CPU & reg pointers */ 267 ddb_cpuinfo = curcpu(); 268 curcpu()->ci_ddb_regs = ddb_regp = &dbregs; 269 270 /* Should switch to kdb`s own stack here. */ 271 272 s = splhigh(); 273 db_active++; 274 cnpollc(true); 275 db_trap(type, 0/*code*/); 276 cnpollc(false); 277 db_active--; 278 splx(s); 279 280 /* Update trap frame from local dbregs storage */ 281 *(struct frame *)tf->tf_out[6] = dbregs.db_fr; 282 *tf = dbregs.db_tf; 283 curcpu()->ci_ddb_regs = ddb_regp = 0; 284 ddb_cpuinfo = NULL; 285 286 #ifdef MULTIPROCESSOR 287 db_resume_others(); 288 #endif 289 290 return (1); 291 } 292 #endif /* DDB || KGDB */ 293 294 #ifdef _KERNEL 295 void 296 db_proc_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 297 { 298 struct lwp *l; 299 struct proc *p; 300 301 l = curlwp; 302 if (have_addr) 303 l = (struct lwp *) addr; 304 305 if (l == NULL) { 306 db_printf("no current process\n"); 307 return; 308 } 309 310 p = l->l_proc; 311 312 db_printf("LWP %p: ", l); 313 db_printf("PID:%d.%d CPU:%d stat:%d vmspace:%p", p->p_pid, 314 l->l_lid, l->l_cpu->ci_cpuid, l->l_stat, p->p_vmspace); 315 if (!P_ZOMBIE(p)) 316 db_printf(" ctx: %p cpuset %x", 317 p->p_vmspace->vm_map.pmap->pm_ctx, 318 p->p_vmspace->vm_map.pmap->pm_cpuset); 319 db_printf("\npmap:%p wchan:%p pri:%d epri:%d\n", 320 p->p_vmspace->vm_map.pmap, 321 l->l_wchan, l->l_priority, lwp_eprio(l)); 322 db_printf("maxsaddr:%p ssiz:%d pg or %llxB\n", 323 p->p_vmspace->vm_maxsaddr, p->p_vmspace->vm_ssize, 324 (unsigned long long)ctob(p->p_vmspace->vm_ssize)); 325 db_printf("profile timer: %lld sec %ld nsec\n", 326 p->p_stats->p_timer[ITIMER_PROF].it_value.tv_sec, 327 p->p_stats->p_timer[ITIMER_PROF].it_value.tv_nsec); 328 db_printf("pcb: %p\n", lwp_getpcb(l)); 329 return; 330 } 331 332 void 333 db_dump_pcb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 334 { 335 struct pcb *pcb; 336 char bits[64]; 337 int i; 338 339 if (have_addr) 340 pcb = (struct pcb *) addr; 341 else 342 pcb = curcpu()->curpcb; 343 344 snprintb(bits, sizeof(bits), PSR_BITS, pcb->pcb_psr); 345 db_printf("pcb@%p sp:%p pc:%p psr:%s onfault:%p\nfull windows:\n", 346 pcb, (void *)(long)pcb->pcb_sp, (void *)(long)pcb->pcb_pc, 347 bits, (void *)pcb->pcb_onfault); 348 349 for (i=0; i<pcb->pcb_nsaved; i++) { 350 db_printf("win %d: at %llx local, in\n", i, 351 (unsigned long long)pcb->pcb_rw[i+1].rw_in[6]); 352 db_printf("%16llx %16llx %16llx %16llx\n", 353 (unsigned long long)pcb->pcb_rw[i].rw_local[0], 354 (unsigned long long)pcb->pcb_rw[i].rw_local[1], 355 (unsigned long long)pcb->pcb_rw[i].rw_local[2], 356 (unsigned long long)pcb->pcb_rw[i].rw_local[3]); 357 db_printf("%16llx %16llx %16llx %16llx\n", 358 (unsigned long long)pcb->pcb_rw[i].rw_local[4], 359 (unsigned long long)pcb->pcb_rw[i].rw_local[5], 360 (unsigned long long)pcb->pcb_rw[i].rw_local[6], 361 (unsigned long long)pcb->pcb_rw[i].rw_local[7]); 362 db_printf("%16llx %16llx %16llx %16llx\n", 363 (unsigned long long)pcb->pcb_rw[i].rw_in[0], 364 (unsigned long long)pcb->pcb_rw[i].rw_in[1], 365 (unsigned long long)pcb->pcb_rw[i].rw_in[2], 366 (unsigned long long)pcb->pcb_rw[i].rw_in[3]); 367 db_printf("%16llx %16llx %16llx %16llx\n", 368 (unsigned long long)pcb->pcb_rw[i].rw_in[4], 369 (unsigned long long)pcb->pcb_rw[i].rw_in[5], 370 (unsigned long long)pcb->pcb_rw[i].rw_in[6], 371 (unsigned long long)pcb->pcb_rw[i].rw_in[7]); 372 } 373 } 374 375 void 376 db_prom_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 377 { 378 379 prom_abort(); 380 } 381 382 void 383 db_page_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 384 { 385 386 if (!have_addr) { 387 db_printf("Need paddr for page\n"); 388 return; 389 } 390 391 db_printf("pa %llx pg %p\n", (unsigned long long)addr, 392 PHYS_TO_VM_PAGE(addr)); 393 } 394 #endif /* _KERNEL */ 395 396 #if defined(MULTIPROCESSOR) 397 398 void 399 db_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 400 { 401 struct cpu_info *ci; 402 if (!have_addr) { 403 cpu_debug_dump(); 404 return; 405 } 406 407 if ((addr < 0) || (addr >= sparc_ncpus)) { 408 db_printf("%ld: CPU out of range\n", addr); 409 return; 410 } 411 ci = cpus[addr]; 412 if (ci == NULL) { 413 db_printf("CPU %ld not configured\n", addr); 414 return; 415 } 416 if (ci != curcpu()) { 417 if (!(ci->flags & CPUFLG_PAUSED)) { 418 db_printf("CPU %ld not paused\n", addr); 419 return; 420 } 421 } 422 if (ci->ci_ddb_regs == 0) { 423 db_printf("CPU %ld has no saved regs\n", addr); 424 return; 425 } 426 db_printf("using CPU %ld", addr); 427 ddb_regp = __UNVOLATILE(ci->ci_ddb_regs); 428 ddb_cpuinfo = ci; 429 } 430 431 void 432 db_xcall_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 433 { 434 cpu_xcall_dump(); 435 } 436 437 #endif /* MULTIPROCESSOR */ 438 439 const struct db_command db_machine_command_table[] = { 440 #ifdef _KERNEL 441 { DDB_ADD_CMD("prom", db_prom_cmd, 0, 442 "Enter the Sun PROM monitor.",NULL,NULL) }, 443 { DDB_ADD_CMD("page", db_page_cmd, 0, 444 "Display the address of a struct vm_page given a physical address", 445 "pa", " pa:\tphysical address to look up") }, 446 { DDB_ADD_CMD("proc", db_proc_cmd, 0, 447 "Display some information about an LWP", 448 "[addr]"," addr:\tstruct lwp address (curlwp otherwise)") }, 449 { DDB_ADD_CMD("pcb", db_dump_pcb, 0, 450 "Display information about a struct pcb", 451 "[address]", 452 " address:\tthe struct pcb to print (curpcb otherwise)") }, 453 #endif 454 #ifdef MULTIPROCESSOR 455 { DDB_ADD_CMD("cpu", db_cpu_cmd, 0, 456 "switch to another cpu's registers", "cpu-no", NULL) }, 457 { DDB_ADD_CMD("xcall", db_xcall_cmd, 0, 458 "show xcall information on all cpus", NULL, NULL) }, 459 #endif 460 { DDB_END_CMD }, 461 }; 462 #endif /* DDB || _KMEMUSER */ 463 464 /* 465 * support for SOFTWARE_SSTEP: 466 * return the next pc if the given branch is taken. 467 * 468 * note: in the case of conditional branches with annul, 469 * this actually returns the next pc in the "not taken" path, 470 * but in that case next_instr_address() will return the 471 * next pc in the "taken" path. so even tho the breakpoints 472 * are backwards, everything will still work, and the logic is 473 * much simpler this way. 474 */ 475 db_addr_t 476 db_branch_taken(int inst, db_addr_t pc, db_regs_t *regs) 477 { 478 union instr insn; 479 db_addr_t npc = ddb_regp->db_tf.tf_npc; 480 481 insn.i_int = inst; 482 483 /* 484 * if this is not an annulled conditional branch, the next pc is "npc". 485 */ 486 487 if (insn.i_any.i_op != IOP_OP2 || insn.i_branch.i_annul != 1) 488 return npc; 489 490 switch (insn.i_op2.i_op2) { 491 case IOP2_Bicc: 492 case IOP2_FBfcc: 493 case IOP2_BPcc: 494 case IOP2_FBPfcc: 495 case IOP2_CBccc: 496 /* branch on some condition-code */ 497 switch (insn.i_branch.i_cond) 498 { 499 case Icc_A: /* always */ 500 return pc + ((inst << 10) >> 8); 501 502 default: /* all other conditions */ 503 return npc + 4; 504 } 505 506 case IOP2_BPr: 507 /* branch on register, always conditional */ 508 return npc + 4; 509 510 default: 511 /* not a branch */ 512 #ifdef _KERNEL 513 panic("branch_taken() on non-branch"); 514 #else 515 printf("branch_taken() on non-branch\n"); 516 return 0; 517 #endif 518 } 519 } 520 521 bool 522 db_inst_branch(int inst) 523 { 524 union instr insn; 525 526 insn.i_int = inst; 527 528 if (insn.i_any.i_op != IOP_OP2) 529 return false; 530 531 switch (insn.i_op2.i_op2) { 532 case IOP2_BPcc: 533 case IOP2_Bicc: 534 case IOP2_BPr: 535 case IOP2_FBPfcc: 536 case IOP2_FBfcc: 537 case IOP2_CBccc: 538 return true; 539 540 default: 541 return false; 542 } 543 } 544 545 546 bool 547 db_inst_call(int inst) 548 { 549 union instr insn; 550 551 insn.i_int = inst; 552 553 switch (insn.i_any.i_op) { 554 case IOP_CALL: 555 return true; 556 557 case IOP_reg: 558 return (insn.i_op3.i_op3 == IOP3_JMPL) && !db_inst_return(inst); 559 560 default: 561 return false; 562 } 563 } 564 565 566 bool 567 db_inst_unconditional_flow_transfer(int inst) 568 { 569 union instr insn; 570 571 insn.i_int = inst; 572 573 if (db_inst_call(inst)) 574 return true; 575 576 if (insn.i_any.i_op != IOP_OP2) 577 return false; 578 579 switch (insn.i_op2.i_op2) 580 { 581 case IOP2_BPcc: 582 case IOP2_Bicc: 583 case IOP2_FBPfcc: 584 case IOP2_FBfcc: 585 case IOP2_CBccc: 586 return insn.i_branch.i_cond == Icc_A; 587 588 default: 589 return false; 590 } 591 } 592 593 594 bool 595 db_inst_return(int inst) 596 { 597 598 return (inst == I_JMPLri(I_G0, I_O7, 8) || /* ret */ 599 inst == I_JMPLri(I_G0, I_I7, 8)); /* retl */ 600 } 601 602 bool 603 db_inst_trap_return(int inst) 604 { 605 union instr insn; 606 607 insn.i_int = inst; 608 609 return (insn.i_any.i_op == IOP_reg && 610 insn.i_op3.i_op3 == IOP3_RETT); 611 } 612 613 614 int 615 db_inst_load(int inst) 616 { 617 union instr insn; 618 619 insn.i_int = inst; 620 621 if (insn.i_any.i_op != IOP_mem) 622 return 0; 623 624 switch (insn.i_op3.i_op3) { 625 case IOP3_LD: 626 case IOP3_LDUB: 627 case IOP3_LDUH: 628 case IOP3_LDD: 629 case IOP3_LDSB: 630 case IOP3_LDSH: 631 case IOP3_LDSTUB: 632 case IOP3_SWAP: 633 case IOP3_LDA: 634 case IOP3_LDUBA: 635 case IOP3_LDUHA: 636 case IOP3_LDDA: 637 case IOP3_LDSBA: 638 case IOP3_LDSHA: 639 case IOP3_LDSTUBA: 640 case IOP3_SWAPA: 641 case IOP3_LDF: 642 case IOP3_LDFSR: 643 case IOP3_LDDF: 644 case IOP3_LFC: 645 case IOP3_LDCSR: 646 case IOP3_LDDC: 647 return 1; 648 649 default: 650 return 0; 651 } 652 } 653 654 int 655 db_inst_store(int inst) 656 { 657 union instr insn; 658 659 insn.i_int = inst; 660 661 if (insn.i_any.i_op != IOP_mem) 662 return 0; 663 664 switch (insn.i_op3.i_op3) { 665 case IOP3_ST: 666 case IOP3_STB: 667 case IOP3_STH: 668 case IOP3_STD: 669 case IOP3_LDSTUB: 670 case IOP3_SWAP: 671 case IOP3_STA: 672 case IOP3_STBA: 673 case IOP3_STHA: 674 case IOP3_STDA: 675 case IOP3_LDSTUBA: 676 case IOP3_SWAPA: 677 case IOP3_STF: 678 case IOP3_STFSR: 679 case IOP3_STDFQ: 680 case IOP3_STDF: 681 case IOP3_STC: 682 case IOP3_STCSR: 683 case IOP3_STDCQ: 684 case IOP3_STDC: 685 return 1; 686 687 default: 688 return 0; 689 } 690 } 691