Home | History | Annotate | Line # | Download | only in alpha
      1 /* $NetBSD: db_interface.c,v 1.46 2026/11/10 03:43:25 thorpej Exp $ */
      2 
      3 /*
      4  * Mach Operating System
      5  * Copyright (c) 1992,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  *	db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
     29  */
     30 
     31 /*
     32  * Parts of this file are derived from Mach 3:
     33  *
     34  *	File: alpha_instruction.c
     35  *	Author: Alessandro Forin, Carnegie Mellon University
     36  *	Date:	6/92
     37  */
     38 
     39 /*
     40  * Interface to DDB.
     41  *
     42  * Modified for NetBSD/alpha by:
     43  *
     44  *	Christopher G. Demetriou, Carnegie Mellon University
     45  *
     46  *	Jason R. Thorpe, Numerical Aerospace Simulation Facility,
     47  *	NASA Ames Research Center
     48  */
     49 
     50 #ifdef _KERNEL_OPT
     51 #include "opt_ddb.h"
     52 #include "opt_multiprocessor.h"
     53 #endif
     54 
     55 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     56 
     57 __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.46 2026/11/10 03:43:25 thorpej Exp $");
     58 
     59 #include <sys/param.h>
     60 #include <sys/proc.h>
     61 #include <sys/reboot.h>
     62 #include <sys/systm.h>
     63 
     64 #include <dev/cons.h>
     65 
     66 #include <machine/alpha.h>
     67 #include <machine/db_machdep.h>
     68 #include <machine/pal.h>
     69 #include <machine/prom.h>
     70 
     71 #include <machine/alpha_instruction.h>
     72 
     73 #include <ddb/db_user.h>
     74 #include <ddb/db_sym.h>
     75 #include <ddb/db_command.h>
     76 #include <ddb/db_extern.h>
     77 #include <ddb/db_access.h>
     78 #include <ddb/db_active.h>
     79 #include <ddb/db_output.h>
     80 #include <ddb/db_variables.h>
     81 #include <ddb/db_interface.h>
     82 
     83 #if 0
     84 extern char *trap_type[];
     85 extern int trap_types;
     86 #endif
     87 
     88 db_regs_t *ddb_regp;
     89 
     90 #if defined(MULTIPROCESSOR)
     91 void	db_mach_cpu(db_expr_t, bool, db_expr_t, const char *);
     92 #endif
     93 
     94 const struct db_command db_machine_command_table[] = {
     95 #if defined(MULTIPROCESSOR)
     96 	{ DDB_ADD_CMD("cpu",	db_mach_cpu,	0,
     97 	  "switch to another cpu", "cpu-no", NULL) },
     98 #endif
     99 	{ DDB_END_CMD },
    100 };
    101 
    102 static int db_alpha_regop(const struct db_variable *, db_expr_t *, int);
    103 
    104 #define	dbreg(xx)	((long *)(xx))
    105 
    106 #define	DBREG(n, r)						\
    107 	{	.name = __STRING(n),				\
    108 		.valuep = ((long *)(r)),			\
    109 		.fcn = db_alpha_regop,				\
    110 		.modif = NULL, }
    111 
    112 const struct db_variable db_regs[] = {
    113 	DBREG(v0,	FRAME_V0),
    114 	DBREG(t0,	FRAME_T0),
    115 	DBREG(t1,	FRAME_T1),
    116 	DBREG(t2,	FRAME_T2),
    117 	DBREG(t3,	FRAME_T3),
    118 	DBREG(t4,	FRAME_T4),
    119 	DBREG(t5,	FRAME_T5),
    120 	DBREG(t6,	FRAME_T6),
    121 	DBREG(t7,	FRAME_T7),
    122 	DBREG(s0,	FRAME_S0),
    123 	DBREG(s1,	FRAME_S1),
    124 	DBREG(s2,	FRAME_S2),
    125 	DBREG(s3,	FRAME_S3),
    126 	DBREG(s4,	FRAME_S4),
    127 	DBREG(s5,	FRAME_S5),
    128 	DBREG(s6,	FRAME_S6),
    129 	DBREG(a0,	FRAME_A0),
    130 	DBREG(a1,	FRAME_A1),
    131 	DBREG(a2,	FRAME_A2),
    132 	DBREG(a3,	FRAME_A3),
    133 	DBREG(a4,	FRAME_A4),
    134 	DBREG(a5,	FRAME_A5),
    135 	DBREG(t8,	FRAME_T8),
    136 	DBREG(t9,	FRAME_T9),
    137 	DBREG(t10,	FRAME_T10),
    138 	DBREG(t11,	FRAME_T11),
    139 	DBREG(ra,	FRAME_RA),
    140 	DBREG(t12,	FRAME_T12),
    141 	DBREG(at,	FRAME_AT),
    142 	DBREG(gp,	FRAME_GP),
    143 	DBREG(sp,	FRAME_SP),
    144 	DBREG(pc,	FRAME_PC),
    145 	DBREG(ps,	FRAME_PS),
    146 	DBREG(ai,	FRAME_T11),
    147 	DBREG(pv,	FRAME_T12),
    148 };
    149 const struct db_variable * const db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
    150 
    151 #undef DBREG
    152 
    153 static int
    154 db_alpha_regop(const struct db_variable *vp, db_expr_t *val, int opcode)
    155 {
    156 	unsigned long *tfaddr;
    157 	unsigned long zeroval = 0;
    158 	struct trapframe *f = NULL;
    159 
    160 #ifdef _KERNEL			/* XXX ?? */
    161 	if (vp->modif != NULL && *vp->modif == 'u') {
    162 		if (curlwp != NULL)
    163 			f = curlwp->l_md.md_tf;
    164 	} else
    165 #endif /* _KERNEL */
    166 		f = DDB_REGS;
    167 	tfaddr = f == NULL ? &zeroval : &f->tf_regs[(u_long)vp->valuep];
    168 	switch (opcode) {
    169 	case DB_VAR_GET:
    170 		*val = *tfaddr;
    171 		break;
    172 
    173 	case DB_VAR_SET:
    174 		*tfaddr = *val;
    175 		break;
    176 
    177 	default:
    178 #ifdef _KERNEL
    179 		panic("db_alpha_regop: unknown op %d", opcode);
    180 #endif
    181 		break;
    182 	}
    183 
    184 	return (0);
    185 }
    186 
    187 #ifdef _KERNEL
    188 /*
    189  * ddb_trap - field a kernel trap
    190  */
    191 int
    192 ddb_trap(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long entry, db_regs_t *regs)
    193 {
    194 	struct cpu_info *ci = curcpu();
    195 	unsigned long psl;
    196 
    197 	if (entry != ALPHA_KENTRY_IF ||
    198 	    (a0 != ALPHA_IF_CODE_BPT && a0 != ALPHA_IF_CODE_BUGCHK)) {
    199 		if (db_recover != 0) {
    200 			/* This will longjmp back into db_command_loop() */
    201 			db_error("Caught exception in ddb.\n");
    202 			/* NOTREACHED */
    203 		}
    204 
    205 		/*
    206 		 * Tell caller "We did NOT handle the trap."
    207 		 * Caller should panic, or whatever.
    208 		 */
    209 		return (0);
    210 	}
    211 
    212 	/*
    213 	 * alpha_debug() switches us to the debugger stack.
    214 	 */
    215 
    216 	/* Our register state is simply the trapframe. */
    217 	ddb_regp = ci->ci_db_regs = regs;
    218 
    219 	/*
    220 	 * Use SWPIPL directly; we want to avoid processing
    221 	 * software interrupts when we go back.  Soft ints
    222 	 * will be caught later, so not to worry.
    223 	 */
    224 	psl = alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
    225 
    226 	db_active++;
    227 	cnpollc(true);		/* Set polling mode, unblank video */
    228 
    229 	db_trap(entry, a0);	/* Where the work happens */
    230 
    231 	cnpollc(false);		/* Resume interrupt mode */
    232 	db_active--;
    233 
    234 	alpha_pal_swpipl(psl);
    235 
    236 	ddb_regp = ci->ci_db_regs = NULL;
    237 
    238 	/*
    239 	 * Tell caller "We HAVE handled the trap."
    240 	 */
    241 	return (1);
    242 }
    243 
    244 /*
    245  * Read bytes from kernel address space for debugger.
    246  */
    247 void
    248 db_read_bytes(vaddr_t addr, register size_t size, register char *data)
    249 {
    250 	register char	*src;
    251 
    252 	src = (char *)addr;
    253 	while (size-- > 0)
    254 		*data++ = *src++;
    255 }
    256 
    257 /*
    258  * Write bytes to kernel address space for debugger.
    259  */
    260 void
    261 db_write_bytes(vaddr_t addr, register size_t size, register const char *data)
    262 {
    263 	register char	*dst;
    264 
    265 	dst = (char *)addr;
    266 	while (size-- > 0)
    267 		*dst++ = *data++;
    268 	alpha_pal_imb();
    269 }
    270 
    271 void
    272 cpu_Debugger(void)
    273 {
    274 
    275 	__asm volatile("call_pal 0x81");		/* bugchk */
    276 }
    277 #endif /* _KERNEL */
    278 
    279 /*
    280  * Alpha-specific ddb commands:
    281  *
    282  *	cpu		tell DDB to use register state from the
    283  *			CPU specified (MULTIPROCESSOR)
    284  */
    285 
    286 #if defined(MULTIPROCESSOR)
    287 void
    288 db_mach_cpu(db_expr_t addr, bool have_addr, db_expr_t count, const char * modif)
    289 {
    290 	struct cpu_info *ci;
    291 
    292 	if (!have_addr) {
    293 		cpu_debug_dump();
    294 		return;
    295 	}
    296 
    297 	if (addr < 0 || addr >= ALPHA_MAXPROCS) {
    298 		db_printf("CPU %ld out of range\n", addr);
    299 		return;
    300 	}
    301 
    302 	ci = cpu_info[addr];
    303 	if (ci == NULL) {
    304 		db_printf("CPU %ld is not configured\n", addr);
    305 		return;
    306 	}
    307 
    308 	if (ci != curcpu()) {
    309 		if ((ci->ci_flags & CPUF_PAUSED) == 0) {
    310 			db_printf("CPU %ld not paused\n", addr);
    311 			return;
    312 		}
    313 	}
    314 
    315 	if (ci->ci_db_regs == NULL) {
    316 		db_printf("CPU %ld has no register state\n", addr);
    317 		return;
    318 	}
    319 
    320 	db_printf("Using CPU %ld\n", addr);
    321 	ddb_regp = ci->ci_db_regs;
    322 }
    323 #endif /* MULTIPROCESSOR */
    324 
    325 /*
    326  * Map Alpha register numbers to trapframe/db_regs_t offsets.
    327  */
    328 static int reg_to_frame[32] = {
    329 	FRAME_V0,
    330 	FRAME_T0,
    331 	FRAME_T1,
    332 	FRAME_T2,
    333 	FRAME_T3,
    334 	FRAME_T4,
    335 	FRAME_T5,
    336 	FRAME_T6,
    337 	FRAME_T7,
    338 
    339 	FRAME_S0,
    340 	FRAME_S1,
    341 	FRAME_S2,
    342 	FRAME_S3,
    343 	FRAME_S4,
    344 	FRAME_S5,
    345 	FRAME_S6,
    346 
    347 	FRAME_A0,
    348 	FRAME_A1,
    349 	FRAME_A2,
    350 	FRAME_A3,
    351 	FRAME_A4,
    352 	FRAME_A5,
    353 
    354 	FRAME_T8,
    355 	FRAME_T9,
    356 	FRAME_T10,
    357 	FRAME_T11,
    358 	FRAME_RA,
    359 	FRAME_T12,
    360 	FRAME_AT,
    361 	FRAME_GP,
    362 	FRAME_SP,
    363 	-1,		/* zero */
    364 };
    365 
    366 u_long
    367 db_register_value(db_regs_t *regs, int regno)
    368 {
    369 
    370 	if (regno > 31 || regno < 0) {
    371 		db_printf(" **** STRANGE REGISTER NUMBER %d **** ", regno);
    372 		return (0);
    373 	}
    374 
    375 	if (regno == 31)
    376 		return (0);
    377 
    378 	return (regs->tf_regs[reg_to_frame[regno]]);
    379 }
    380 
    381 #ifdef _KERNEL
    382 /*
    383  * Support functions for software single-step.
    384  */
    385 
    386 bool
    387 db_inst_call(int ins)
    388 {
    389 	alpha_instruction insn;
    390 
    391 	insn.bits = ins;
    392 	return ((insn.branch_format.opcode == op_bsr) ||
    393 	    ((insn.jump_format.opcode == op_j) &&
    394 	     (insn.jump_format.action & 1)));
    395 }
    396 
    397 bool
    398 db_inst_return(int ins)
    399 {
    400 	alpha_instruction insn;
    401 
    402 	insn.bits = ins;
    403 	return ((insn.jump_format.opcode == op_j) &&
    404 	    (insn.jump_format.action == op_ret));
    405 }
    406 
    407 bool
    408 db_inst_trap_return(int ins)
    409 {
    410 	alpha_instruction insn;
    411 
    412 	insn.bits = ins;
    413 	return ((insn.pal_format.opcode == op_pal) &&
    414 	    (insn.pal_format.function == PAL_OSF1_rti));
    415 }
    416 
    417 bool
    418 db_inst_branch(int ins)
    419 {
    420 	alpha_instruction insn;
    421 
    422 	insn.bits = ins;
    423 	switch (insn.branch_format.opcode) {
    424 	case op_j:
    425 	case op_br:
    426 	case op_fbeq:
    427 	case op_fblt:
    428 	case op_fble:
    429 	case op_fbne:
    430 	case op_fbge:
    431 	case op_fbgt:
    432 	case op_blbc:
    433 	case op_beq:
    434 	case op_blt:
    435 	case op_ble:
    436 	case op_blbs:
    437 	case op_bne:
    438 	case op_bge:
    439 	case op_bgt:
    440 		return (true);
    441 	}
    442 
    443 	return (false);
    444 }
    445 
    446 bool
    447 db_inst_unconditional_flow_transfer(int ins)
    448 {
    449 	alpha_instruction insn;
    450 
    451 	insn.bits = ins;
    452 	switch (insn.branch_format.opcode) {
    453 	case op_j:
    454 	case op_br:
    455 		return (true);
    456 
    457 	case op_pal:
    458 		switch (insn.pal_format.function) {
    459 		case PAL_OSF1_retsys:
    460 		case PAL_OSF1_rti:
    461 		case PAL_OSF1_callsys:
    462 			return (true);
    463 		}
    464 	}
    465 
    466 	return (false);
    467 }
    468 
    469 #if 0
    470 bool
    471 db_inst_spill(int ins, int regn)
    472 {
    473 	alpha_instruction insn;
    474 
    475 	insn.bits = ins;
    476 	return ((insn.mem_format.opcode == op_stq) &&
    477 	    (insn.mem_format.rd == regn));
    478 }
    479 #endif
    480 
    481 bool
    482 db_inst_load(int ins)
    483 {
    484 	alpha_instruction insn;
    485 
    486 	insn.bits = ins;
    487 
    488 	/* Loads. */
    489 	if (insn.mem_format.opcode == op_ldbu ||
    490 	    insn.mem_format.opcode == op_ldq_u ||
    491 	    insn.mem_format.opcode == op_ldwu)
    492 		return (true);
    493 	if ((insn.mem_format.opcode >= op_ldf) &&
    494 	    (insn.mem_format.opcode <= op_ldt))
    495 		return (true);
    496 	if ((insn.mem_format.opcode >= op_ldl) &&
    497 	    (insn.mem_format.opcode <= op_ldq_l))
    498 		return (true);
    499 
    500 	/* Prefetches. */
    501 	if (insn.mem_format.opcode == op_special) {
    502 		/* Note: MB is treated as a store. */
    503 		if ((insn.mem_format.displacement == (short)op_fetch) ||
    504 		    (insn.mem_format.displacement == (short)op_fetch_m))
    505 			return (true);
    506 	}
    507 
    508 	return (false);
    509 }
    510 
    511 bool
    512 db_inst_store(int ins)
    513 {
    514 	alpha_instruction insn;
    515 
    516 	insn.bits = ins;
    517 
    518 	/* Stores. */
    519 	if (insn.mem_format.opcode == op_stw ||
    520 	    insn.mem_format.opcode == op_stb ||
    521 	    insn.mem_format.opcode == op_stq_u)
    522 		return (true);
    523 	if ((insn.mem_format.opcode >= op_stf) &&
    524 	    (insn.mem_format.opcode <= op_stt))
    525 		return (true);
    526 	if ((insn.mem_format.opcode >= op_stl) &&
    527 	    (insn.mem_format.opcode <= op_stq_c))
    528 		return (true);
    529 
    530 	/* Barriers. */
    531 	if (insn.mem_format.opcode == op_special) {
    532 		if (insn.mem_format.displacement == op_mb)
    533 			return (true);
    534 	}
    535 
    536 	return (false);
    537 }
    538 
    539 db_addr_t
    540 db_branch_taken(int ins, db_addr_t pc, db_regs_t *regs)
    541 {
    542 	long signed_immediate;
    543 	alpha_instruction insn;
    544 	db_addr_t newpc;
    545 
    546 	insn.bits = ins;
    547 	switch (insn.branch_format.opcode) {
    548 	/*
    549 	 * Jump format: target PC is (contents of instruction's "RB") & ~3.
    550 	 */
    551 	case op_j:
    552 		newpc = db_register_value(regs, insn.jump_format.rb) & ~3;
    553 		break;
    554 
    555 	/*
    556 	 * Branch format: target PC is
    557 	 *	(new PC) + (4 * sign-ext(displacement)).
    558 	 */
    559 	case op_br:
    560 	case op_fbeq:
    561 	case op_fblt:
    562 	case op_fble:
    563 	case op_bsr:
    564 	case op_fbne:
    565 	case op_fbge:
    566 	case op_fbgt:
    567 	case op_blbc:
    568 	case op_beq:
    569 	case op_blt:
    570 	case op_ble:
    571 	case op_blbs:
    572 	case op_bne:
    573 	case op_bge:
    574 	case op_bgt:
    575 		signed_immediate = insn.branch_format.displacement;
    576 		newpc = (pc + 4) + (signed_immediate << 2);
    577 		break;
    578 
    579 	default:
    580 		printf("DDB: db_inst_branch_taken on non-branch!\n");
    581 		newpc = pc;	/* XXX */
    582 	}
    583 
    584 	return (newpc);
    585 }
    586 #endif /* _KERNEL */
    587 
    588 unsigned long
    589 db_alpha_read_saved_reg(unsigned long *regp)
    590 {
    591 	unsigned long reg;
    592 
    593 	db_read_bytes((db_addr_t)regp, sizeof(reg), (char *)&reg);
    594 	return reg;
    595 }
    596 
    597 unsigned long
    598 db_alpha_tf_reg(struct trapframe *tf, unsigned int regno)
    599 {
    600 	return db_alpha_read_saved_reg(&tf->tf_regs[regno]);
    601 }
    602 
    603 /*
    604  * Alpha special symbol handling.
    605  */
    606 db_alpha_nlist db_alpha_nl[] = {
    607 	DB_ALPHA_SYM(SYM_XentArith, XentArith),
    608 	DB_ALPHA_SYM(SYM_XentIF, XentIF),
    609 	DB_ALPHA_SYM(SYM_XentInt, XentInt),
    610 	DB_ALPHA_SYM(SYM_XentMM, XentMM),
    611 	DB_ALPHA_SYM(SYM_XentSys, XentSys),
    612 	DB_ALPHA_SYM(SYM_XentUna, XentUna),
    613 	DB_ALPHA_SYM(SYM_XentRestart, XentRestart),
    614 	DB_ALPHA_SYM(SYM_exception_return, exception_return),
    615 	DB_ALPHA_SYM(SYM_alpha_kthread_backstop, alpha_kthread_backstop),
    616 #ifndef _KERNEL
    617 	DB_ALPHA_SYM(SYM_dumppcb, dumppcb),
    618 #endif /* _KERNEL */
    619 	DB_ALPHA_SYM_EOL
    620 };
    621 
    622 static int
    623 db_alpha_nlist_lookup(db_addr_t addr)
    624 {
    625 	int i;
    626 
    627 	for (i = 0; i < SYM___eol; i++) {
    628 		if (db_alpha_nl[i].n_value == addr) {
    629 			return i;
    630 		}
    631 	}
    632 	return -1;
    633 }
    634 
    635 bool
    636 db_alpha_sym_is_trap(db_addr_t addr)
    637 {
    638 	int i = db_alpha_nlist_lookup(addr);
    639 	return i >= SYM_XentArith && i <= SYM_exception_return;
    640 }
    641 
    642 bool
    643 db_alpha_sym_is_backstop(db_addr_t addr)
    644 {
    645 	return db_alpha_nlist_lookup(addr) == SYM_alpha_kthread_backstop;
    646 }
    647 
    648 bool
    649 db_alpha_sym_is_syscall(db_addr_t addr)
    650 {
    651 	return db_alpha_nlist_lookup(addr) == SYM_XentSys;
    652 }
    653 
    654 const char *
    655 db_alpha_trapsym_description(db_addr_t addr)
    656 {
    657 	static const char * const trap_descriptions[] = {
    658 	[SYM_XentArith]		=	"arithmetic trap",
    659 	[SYM_XentIF]		=	"instruction fault",
    660 	[SYM_XentInt]		=	"interrupt",
    661 	[SYM_XentMM]		=	"memory management fault",
    662 	[SYM_XentSys]		=	"syscall",
    663 	[SYM_XentUna]		=	"unaligned access fault",
    664 	[SYM_XentRestart]	=	"console restart",
    665 	[SYM_exception_return]	=	"(exception return)",
    666 	};
    667 
    668 	int i = db_alpha_nlist_lookup(addr);
    669 	if (i >= SYM_XentArith && i <= SYM_exception_return) {
    670 		return trap_descriptions[i];
    671 	}
    672 	return "??? trap ???";
    673 }
    674