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