1 /* $OpenBSD: db_interface.c,v 1.30 2024/11/07 16:02:29 miod Exp $ */ 2 /* $NetBSD: db_interface.c,v 1.8 1999/10/12 17:08:57 jdolecek Exp $ */ 3 4 /* 5 * Mach Operating System 6 * Copyright (c) 1992,1991,1990 Carnegie Mellon University 7 * All Rights Reserved. 8 * 9 * Permission to use, copy, modify and distribute this software and its 10 * documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS ``AS IS'' 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 * 29 * db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) 30 */ 31 32 /* 33 * Parts of this file are derived from Mach 3: 34 * 35 * File: alpha_instruction.c 36 * Author: Alessandro Forin, Carnegie Mellon University 37 * Date: 6/92 38 */ 39 40 /* 41 * Interface to DDB. 42 * 43 * Modified for NetBSD/alpha by: 44 * 45 * Christopher G. Demetriou, Carnegie Mellon University 46 * 47 * Jason R. Thorpe, Numerical Aerospace Simulation Facility, 48 * NASA Ames Research Center 49 */ 50 51 #include <sys/param.h> 52 #include <sys/proc.h> 53 #include <sys/reboot.h> 54 #include <sys/systm.h> 55 56 #include <uvm/uvm_extern.h> 57 58 #include <dev/cons.h> 59 60 #include <machine/db_machdep.h> 61 #include <machine/pal.h> 62 #include <machine/prom.h> 63 64 #include <alpha/alpha/db_instruction.h> 65 66 #include <ddb/db_sym.h> 67 #include <ddb/db_command.h> 68 #include <ddb/db_extern.h> 69 #include <ddb/db_access.h> 70 #include <ddb/db_output.h> 71 #include <ddb/db_variables.h> 72 #include <ddb/db_interface.h> 73 74 75 extern label_t *db_recover; 76 77 #if 0 78 extern char *trap_type[]; 79 extern int trap_types; 80 #endif 81 82 db_regs_t ddb_regs; 83 84 #if defined(MULTIPROCESSOR) 85 void db_mach_cpu(db_expr_t, int, db_expr_t, char *); 86 #endif 87 88 const struct db_command db_machine_command_table[] = { 89 #if defined(MULTIPROCESSOR) 90 { "ddbcpu", db_mach_cpu, 0, NULL }, 91 #endif 92 { NULL, NULL, 0, NULL } 93 }; 94 95 struct db_variable db_regs[] = { 96 { "v0", &ddb_regs.tf_regs[FRAME_V0], FCN_NULL }, 97 { "t0", &ddb_regs.tf_regs[FRAME_T0], FCN_NULL }, 98 { "t1", &ddb_regs.tf_regs[FRAME_T1], FCN_NULL }, 99 { "t2", &ddb_regs.tf_regs[FRAME_T2], FCN_NULL }, 100 { "t3", &ddb_regs.tf_regs[FRAME_T3], FCN_NULL }, 101 { "t4", &ddb_regs.tf_regs[FRAME_T4], FCN_NULL }, 102 { "t5", &ddb_regs.tf_regs[FRAME_T5], FCN_NULL }, 103 { "t6", &ddb_regs.tf_regs[FRAME_T6], FCN_NULL }, 104 { "t7", &ddb_regs.tf_regs[FRAME_T7], FCN_NULL }, 105 { "s0", &ddb_regs.tf_regs[FRAME_S0], FCN_NULL }, 106 { "s1", &ddb_regs.tf_regs[FRAME_S1], FCN_NULL }, 107 { "s2", &ddb_regs.tf_regs[FRAME_S2], FCN_NULL }, 108 { "s3", &ddb_regs.tf_regs[FRAME_S3], FCN_NULL }, 109 { "s4", &ddb_regs.tf_regs[FRAME_S4], FCN_NULL }, 110 { "s5", &ddb_regs.tf_regs[FRAME_S5], FCN_NULL }, 111 { "s6", &ddb_regs.tf_regs[FRAME_S6], FCN_NULL }, 112 { "a0", &ddb_regs.tf_regs[FRAME_A0], FCN_NULL }, 113 { "a1", &ddb_regs.tf_regs[FRAME_A1], FCN_NULL }, 114 { "a2", &ddb_regs.tf_regs[FRAME_A2], FCN_NULL }, 115 { "a3", &ddb_regs.tf_regs[FRAME_A3], FCN_NULL }, 116 { "a4", &ddb_regs.tf_regs[FRAME_A4], FCN_NULL }, 117 { "a5", &ddb_regs.tf_regs[FRAME_A5], FCN_NULL }, 118 { "t8", &ddb_regs.tf_regs[FRAME_T8], FCN_NULL }, 119 { "t9", &ddb_regs.tf_regs[FRAME_T9], FCN_NULL }, 120 { "t10", &ddb_regs.tf_regs[FRAME_T10], FCN_NULL }, 121 { "t11", &ddb_regs.tf_regs[FRAME_T11], FCN_NULL }, 122 { "ra", &ddb_regs.tf_regs[FRAME_RA], FCN_NULL }, 123 { "t12", &ddb_regs.tf_regs[FRAME_T12], FCN_NULL }, 124 { "at", &ddb_regs.tf_regs[FRAME_AT], FCN_NULL }, 125 { "gp", &ddb_regs.tf_regs[FRAME_GP], FCN_NULL }, 126 { "sp", &ddb_regs.tf_regs[FRAME_SP], FCN_NULL }, 127 { "pc", &ddb_regs.tf_regs[FRAME_PC], FCN_NULL }, 128 { "ps", &ddb_regs.tf_regs[FRAME_PS], FCN_NULL }, 129 { "ai", &ddb_regs.tf_regs[FRAME_T11], FCN_NULL }, 130 { "pv", &ddb_regs.tf_regs[FRAME_T12], FCN_NULL }, 131 }; 132 struct db_variable *db_eregs = db_regs + nitems(db_regs); 133 134 /* 135 * ddb_trap - field a kernel trap 136 */ 137 int 138 ddb_trap(a0, a1, a2, entry, regs) 139 unsigned long a0, a1, a2, entry; 140 db_regs_t *regs; 141 { 142 struct cpu_info *ci = curcpu(); 143 int s; 144 145 if (entry != ALPHA_KENTRY_IF || 146 (a0 != ALPHA_IF_CODE_BPT && a0 != ALPHA_IF_CODE_BUGCHK)) { 147 if (db_recover != 0) { 148 /* This will longjmp back into db_command_loop() */ 149 db_error("Caught exception in ddb.\n"); 150 /* NOTREACHED */ 151 } 152 153 /* 154 * Tell caller "We did NOT handle the trap." 155 * Caller should panic, or whatever. 156 */ 157 return (0); 158 } 159 160 /* 161 * alpha_debug() switches us to the debugger stack. 162 */ 163 164 ci->ci_db_regs = regs; 165 ddb_regs = *regs; 166 167 s = splhigh(); 168 169 db_active++; 170 cnpollc(1); /* Set polling mode, unblank video */ 171 172 db_trap(entry, a0); /* Where the work happens */ 173 174 cnpollc(0); /* Resume interrupt mode */ 175 db_active--; 176 177 splx(s); 178 179 *regs = ddb_regs; 180 181 /* 182 * Tell caller "We HAVE handled the trap." 183 */ 184 return (1); 185 } 186 187 /* 188 * Read bytes from kernel address space for debugger. 189 */ 190 void 191 db_read_bytes(addr, size, datap) 192 vaddr_t addr; 193 register size_t size; 194 register void *datap; 195 { 196 register char *data = datap, *src; 197 198 src = (char *)addr; 199 while (size-- > 0) 200 *data++ = *src++; 201 } 202 203 /* 204 * Write bytes to kernel address space for debugger. 205 */ 206 void 207 db_write_bytes(addr, size, datap) 208 vaddr_t addr; 209 register size_t size; 210 register void *datap; 211 { 212 register char *data = datap, *dst; 213 214 dst = (char *)addr; 215 while (size-- > 0) 216 *dst++ = *data++; 217 alpha_pal_imb(); 218 } 219 220 void 221 db_enter() 222 { 223 224 __asm volatile("call_pal 0x81"); /* bugchk */ 225 } 226 227 /* 228 * Map Alpha register numbers to trapframe/db_regs_t offsets. 229 */ 230 static int reg_to_frame[32] = { 231 FRAME_V0, 232 FRAME_T0, 233 FRAME_T1, 234 FRAME_T2, 235 FRAME_T3, 236 FRAME_T4, 237 FRAME_T5, 238 FRAME_T6, 239 FRAME_T7, 240 241 FRAME_S0, 242 FRAME_S1, 243 FRAME_S2, 244 FRAME_S3, 245 FRAME_S4, 246 FRAME_S5, 247 FRAME_S6, 248 249 FRAME_A0, 250 FRAME_A1, 251 FRAME_A2, 252 FRAME_A3, 253 FRAME_A4, 254 FRAME_A5, 255 256 FRAME_T8, 257 FRAME_T9, 258 FRAME_T10, 259 FRAME_T11, 260 FRAME_RA, 261 FRAME_T12, 262 FRAME_AT, 263 FRAME_GP, 264 FRAME_SP, 265 -1, /* zero */ 266 }; 267 268 u_long 269 db_register_value(regs, regno) 270 db_regs_t *regs; 271 int regno; 272 { 273 274 if (regno > 31 || regno < 0) { 275 db_printf(" **** STRANGE REGISTER NUMBER %d **** ", regno); 276 return (0); 277 } 278 279 if (regno == 31) 280 return (0); 281 282 return (regs->tf_regs[reg_to_frame[regno]]); 283 } 284 285 /* 286 * Support functions for software single-step. 287 */ 288 289 int 290 db_inst_call(int ins) 291 { 292 alpha_instruction insn; 293 294 insn.bits = ins; 295 return ((insn.branch_format.opcode == op_bsr) || 296 ((insn.jump_format.opcode == op_j) && 297 (insn.jump_format.action & 1))); 298 } 299 300 int 301 db_inst_return(int ins) 302 { 303 alpha_instruction insn; 304 305 insn.bits = ins; 306 return ((insn.jump_format.opcode == op_j) && 307 (insn.jump_format.action == op_ret)); 308 } 309 310 int 311 db_inst_trap_return(int ins) 312 { 313 alpha_instruction insn; 314 315 insn.bits = ins; 316 return ((insn.pal_format.opcode == op_pal) && 317 (insn.pal_format.function == PAL_OSF1_rti)); 318 } 319 320 int 321 db_inst_branch(int ins) 322 { 323 alpha_instruction insn; 324 325 insn.bits = ins; 326 switch (insn.branch_format.opcode) { 327 case op_j: 328 case op_br: 329 case op_fbeq: 330 case op_fblt: 331 case op_fble: 332 case op_fbne: 333 case op_fbge: 334 case op_fbgt: 335 case op_blbc: 336 case op_beq: 337 case op_blt: 338 case op_ble: 339 case op_blbs: 340 case op_bne: 341 case op_bge: 342 case op_bgt: 343 return 1; 344 } 345 346 return 0; 347 } 348 349 int 350 db_inst_unconditional_flow_transfer(int ins) 351 { 352 alpha_instruction insn; 353 354 insn.bits = ins; 355 switch (insn.branch_format.opcode) { 356 case op_j: 357 case op_br: 358 return 1; 359 360 case op_pal: 361 switch (insn.pal_format.function) { 362 case PAL_OSF1_retsys: 363 case PAL_OSF1_rti: 364 case PAL_OSF1_callsys: 365 return 1; 366 } 367 } 368 369 return 0; 370 } 371 372 int 373 db_inst_load(int ins) 374 { 375 alpha_instruction insn; 376 377 insn.bits = ins; 378 379 /* Loads. */ 380 if (insn.mem_format.opcode == op_ldbu || 381 insn.mem_format.opcode == op_ldq_u || 382 insn.mem_format.opcode == op_ldwu) 383 return 1; 384 if ((insn.mem_format.opcode >= op_ldf) && 385 (insn.mem_format.opcode <= op_ldt)) 386 return 1; 387 if ((insn.mem_format.opcode >= op_ldl) && 388 (insn.mem_format.opcode <= op_ldq_l)) 389 return 1; 390 391 /* Prefetches. */ 392 if (insn.mem_format.opcode == op_special) { 393 /* Note: MB is treated as a store. */ 394 if ((insn.mem_format.displacement == (short)op_fetch) || 395 (insn.mem_format.displacement == (short)op_fetch_m)) 396 return 1; 397 } 398 399 return 0; 400 } 401 402 vaddr_t 403 db_branch_taken(ins, pc, regs) 404 int ins; 405 vaddr_t pc; 406 db_regs_t *regs; 407 { 408 long signed_immediate; 409 alpha_instruction insn; 410 vaddr_t newpc; 411 412 insn.bits = ins; 413 switch (insn.branch_format.opcode) { 414 /* 415 * Jump format: target PC is (contents of instruction's "RB") & ~3. 416 */ 417 case op_j: 418 newpc = db_register_value(regs, insn.jump_format.rb) & ~3; 419 break; 420 421 /* 422 * Branch format: target PC is 423 * (new PC) + (4 * sign-ext(displacement)). 424 */ 425 case op_br: 426 case op_fbeq: 427 case op_fblt: 428 case op_fble: 429 case op_bsr: 430 case op_fbne: 431 case op_fbge: 432 case op_fbgt: 433 case op_blbc: 434 case op_beq: 435 case op_blt: 436 case op_ble: 437 case op_blbs: 438 case op_bne: 439 case op_bge: 440 case op_bgt: 441 signed_immediate = insn.branch_format.displacement; 442 newpc = (pc + 4) + (signed_immediate << 2); 443 break; 444 445 default: 446 printf("DDB: db_inst_branch_taken on non-branch!\n"); 447 newpc = pc; /* XXX */ 448 } 449 450 return (newpc); 451 } 452 453 /* 454 * Validate an address for use as a breakpoint. We cannot let some 455 * addresses have breakpoints as the ddb code itself uses that codepath. 456 * Recursion and kernel stack space exhaustion will follow. 457 */ 458 int 459 db_valid_breakpoint(addr) 460 vaddr_t addr; 461 { 462 const char *name; 463 db_expr_t offset; 464 465 db_find_sym_and_offset(addr, &name, &offset); 466 if (name && strcmp(name, "alpha_pal_swpipl") == 0) 467 return (0); 468 return (1); 469 } 470 471 vaddr_t 472 next_instr_address(pc, branch) 473 vaddr_t pc; 474 int branch; 475 { 476 if (!branch) 477 return (pc + sizeof(int)); 478 return (branch_taken(*(u_int *)pc, pc, getreg_val, &ddb_regs)); 479 } 480 481 #if defined(MULTIPROCESSOR) 482 void 483 db_mach_cpu(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 484 { 485 struct cpu_info *ci; 486 CPU_INFO_ITERATOR cii; 487 488 if (have_addr == 0) { 489 db_printf("addr dev id flg mtx ipis " 490 "curproc fpcurproc\n"); 491 CPU_INFO_FOREACH(cii, ci) 492 db_printf("%p %-5s %02lu %03lx %03d %04lx %p %p\n", 493 ci, ci->ci_dev->dv_xname, ci->ci_cpuid, 494 ci->ci_flags, ci->ci_mutex_level, ci->ci_ipis, 495 ci->ci_curproc, ci->ci_fpcurproc); 496 return; 497 } 498 499 if (addr < 0 || addr >= ALPHA_MAXPROCS) { 500 db_printf("CPU %ld out of range\n", addr); 501 return; 502 } 503 504 ci = cpu_info[addr]; 505 if (ci == NULL) { 506 db_printf("CPU %ld is not configured\n", addr); 507 return; 508 } 509 510 if (ci != curcpu()) { 511 if ((ci->ci_flags & CPUF_PAUSED) == 0) { 512 db_printf("CPU %ld not paused\n", addr); 513 return; 514 } 515 } 516 517 if (ci->ci_db_regs == NULL) { 518 db_printf("CPU %ld has no register state\n", addr); 519 return; 520 } 521 522 db_printf("Using CPU %ld\n", addr); 523 ddb_regs = *ci->ci_db_regs; /* struct copy */ 524 } 525 #endif /* MULTIPROCESSOR */ 526 527 void 528 db_machine_init() 529 { 530 } 531