1 /* $NetBSD: db_interface.c,v 1.17 2002/05/13 20:30:08 matt 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@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 #include "opt_ddb.h" 51 #include "opt_multiprocessor.h" 52 53 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 54 55 __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.17 2002/05/13 20:30:08 matt Exp $"); 56 57 #include <sys/param.h> 58 #include <sys/proc.h> 59 #include <sys/reboot.h> 60 #include <sys/systm.h> 61 62 #include <uvm/uvm_extern.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 <alpha/alpha/db_instruction.h> 72 73 #include <ddb/db_sym.h> 74 #include <ddb/db_command.h> 75 #include <ddb/db_extern.h> 76 #include <ddb/db_access.h> 77 #include <ddb/db_output.h> 78 #include <ddb/db_variables.h> 79 #include <ddb/db_interface.h> 80 81 82 #if 0 83 extern char *trap_type[]; 84 extern int trap_types; 85 #endif 86 87 int db_active = 0; 88 89 db_regs_t *ddb_regp; 90 91 #if defined(MULTIPROCESSOR) 92 void db_mach_cpu __P((db_expr_t, int, db_expr_t, char *)); 93 #endif 94 95 const struct db_command db_machine_command_table[] = { 96 #if defined(MULTIPROCESSOR) 97 { "cpu", db_mach_cpu, 0, 0 }, 98 #endif 99 { (char *)0, }, 100 }; 101 102 static int db_alpha_regop __P((const struct db_variable *, db_expr_t *, int)); 103 104 #define dbreg(xx) ((long *)(xx)) 105 106 const struct db_variable db_regs[] = { 107 { "v0", dbreg(FRAME_V0), db_alpha_regop }, 108 { "t0", dbreg(FRAME_T0), db_alpha_regop }, 109 { "t1", dbreg(FRAME_T1), db_alpha_regop }, 110 { "t2", dbreg(FRAME_T2), db_alpha_regop }, 111 { "t3", dbreg(FRAME_T3), db_alpha_regop }, 112 { "t4", dbreg(FRAME_T4), db_alpha_regop }, 113 { "t5", dbreg(FRAME_T5), db_alpha_regop }, 114 { "t6", dbreg(FRAME_T6), db_alpha_regop }, 115 { "t7", dbreg(FRAME_T7), db_alpha_regop }, 116 { "s0", dbreg(FRAME_S0), db_alpha_regop }, 117 { "s1", dbreg(FRAME_S1), db_alpha_regop }, 118 { "s2", dbreg(FRAME_S2), db_alpha_regop }, 119 { "s3", dbreg(FRAME_S3), db_alpha_regop }, 120 { "s4", dbreg(FRAME_S4), db_alpha_regop }, 121 { "s5", dbreg(FRAME_S5), db_alpha_regop }, 122 { "s6", dbreg(FRAME_S6), db_alpha_regop }, 123 { "a0", dbreg(FRAME_A0), db_alpha_regop }, 124 { "a1", dbreg(FRAME_A1), db_alpha_regop }, 125 { "a2", dbreg(FRAME_A2), db_alpha_regop }, 126 { "a3", dbreg(FRAME_A3), db_alpha_regop }, 127 { "a4", dbreg(FRAME_A4), db_alpha_regop }, 128 { "a5", dbreg(FRAME_A5), db_alpha_regop }, 129 { "t8", dbreg(FRAME_T8), db_alpha_regop }, 130 { "t9", dbreg(FRAME_T9), db_alpha_regop }, 131 { "t10", dbreg(FRAME_T10), db_alpha_regop }, 132 { "t11", dbreg(FRAME_T11), db_alpha_regop }, 133 { "ra", dbreg(FRAME_RA), db_alpha_regop }, 134 { "t12", dbreg(FRAME_T12), db_alpha_regop }, 135 { "at", dbreg(FRAME_AT), db_alpha_regop }, 136 { "gp", dbreg(FRAME_GP), db_alpha_regop }, 137 { "sp", dbreg(FRAME_SP), db_alpha_regop }, 138 { "pc", dbreg(FRAME_PC), db_alpha_regop }, 139 { "ps", dbreg(FRAME_PS), db_alpha_regop }, 140 { "ai", dbreg(FRAME_T11), db_alpha_regop }, 141 { "pv", dbreg(FRAME_T12), db_alpha_regop }, 142 }; 143 const struct db_variable * const db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); 144 145 static int 146 db_alpha_regop(const struct db_variable *vp, db_expr_t *val, int opcode) 147 { 148 unsigned long *tfaddr; 149 unsigned long zeroval = 0; 150 struct trapframe *f = NULL; 151 152 if (vp->modif != NULL && *vp->modif == 'u') { 153 if (curproc != NULL) 154 f = curproc->p_md.md_tf; 155 } else f = DDB_REGS; 156 tfaddr = f == NULL ? &zeroval : &f->tf_regs[(u_long)vp->valuep]; 157 switch (opcode) { 158 case DB_VAR_GET: 159 *val = *tfaddr; 160 break; 161 162 case DB_VAR_SET: 163 *tfaddr = *val; 164 break; 165 166 default: 167 panic("db_alpha_regop: unknown op %d", opcode); 168 } 169 170 return (0); 171 } 172 173 /* 174 * ddb_trap - field a kernel trap 175 */ 176 int 177 ddb_trap(a0, a1, a2, entry, regs) 178 unsigned long a0, a1, a2, entry; 179 db_regs_t *regs; 180 { 181 struct cpu_info *ci = curcpu(); 182 int s; 183 184 if (entry != ALPHA_KENTRY_IF || 185 (a0 != ALPHA_IF_CODE_BPT && a0 != ALPHA_IF_CODE_BUGCHK)) { 186 if (db_recover != 0) { 187 /* This will longjmp back into db_command_loop() */ 188 db_error("Caught exception in ddb.\n"); 189 /* NOTREACHED */ 190 } 191 192 /* 193 * Tell caller "We did NOT handle the trap." 194 * Caller should panic, or whatever. 195 */ 196 return (0); 197 } 198 199 /* 200 * alpha_debug() switches us to the debugger stack. 201 */ 202 203 /* Our register state is simply the trapframe. */ 204 ddb_regp = ci->ci_db_regs = regs; 205 206 s = splhigh(); 207 208 db_active++; 209 cnpollc(TRUE); /* Set polling mode, unblank video */ 210 211 db_trap(entry, a0); /* Where the work happens */ 212 213 cnpollc(FALSE); /* Resume interrupt mode */ 214 db_active--; 215 216 splx(s); 217 218 ddb_regp = ci->ci_db_regs = NULL; 219 220 /* 221 * Tell caller "We HAVE handled the trap." 222 */ 223 return (1); 224 } 225 226 /* 227 * Read bytes from kernel address space for debugger. 228 */ 229 void 230 db_read_bytes(addr, size, data) 231 vaddr_t addr; 232 register size_t size; 233 register char *data; 234 { 235 register char *src; 236 237 src = (char *)addr; 238 while (size-- > 0) 239 *data++ = *src++; 240 } 241 242 /* 243 * Write bytes to kernel address space for debugger. 244 */ 245 void 246 db_write_bytes(addr, size, data) 247 vaddr_t addr; 248 register size_t size; 249 register char *data; 250 { 251 register char *dst; 252 253 dst = (char *)addr; 254 while (size-- > 0) 255 *dst++ = *data++; 256 alpha_pal_imb(); 257 } 258 259 void 260 cpu_Debugger() 261 { 262 263 __asm __volatile("call_pal 0x81"); /* bugchk */ 264 } 265 266 /* 267 * Alpha-specific ddb commands: 268 * 269 * cpu tell DDB to use register state from the 270 * CPU specified (MULTIPROCESSOR) 271 */ 272 273 #if defined(MULTIPROCESSOR) 274 void 275 db_mach_cpu(addr, have_addr, count, modif) 276 db_expr_t addr; 277 int have_addr; 278 db_expr_t count; 279 char * modif; 280 { 281 struct cpu_info *ci; 282 283 if (have_addr == 0) { 284 cpu_debug_dump(); 285 return; 286 } 287 288 if (addr < 0 || addr >= ALPHA_MAXPROCS) { 289 db_printf("CPU %ld out of range\n", addr); 290 return; 291 } 292 293 ci = cpu_info[addr]; 294 if (ci == NULL) { 295 db_printf("CPU %ld is not configured\n", addr); 296 return; 297 } 298 299 if (ci != curcpu()) { 300 if ((ci->ci_flags & CPUF_PAUSED) == 0) { 301 db_printf("CPU %ld not paused\n", addr); 302 return; 303 } 304 } 305 306 if (ci->ci_db_regs == NULL) { 307 db_printf("CPU %ld has no register state\n", addr); 308 return; 309 } 310 311 db_printf("Using CPU %ld\n", addr); 312 ddb_regp = ci->ci_db_regs; 313 } 314 #endif /* MULTIPROCESSOR */ 315 316 /* 317 * Map Alpha register numbers to trapframe/db_regs_t offsets. 318 */ 319 static int reg_to_frame[32] = { 320 FRAME_V0, 321 FRAME_T0, 322 FRAME_T1, 323 FRAME_T2, 324 FRAME_T3, 325 FRAME_T4, 326 FRAME_T5, 327 FRAME_T6, 328 FRAME_T7, 329 330 FRAME_S0, 331 FRAME_S1, 332 FRAME_S2, 333 FRAME_S3, 334 FRAME_S4, 335 FRAME_S5, 336 FRAME_S6, 337 338 FRAME_A0, 339 FRAME_A1, 340 FRAME_A2, 341 FRAME_A3, 342 FRAME_A4, 343 FRAME_A5, 344 345 FRAME_T8, 346 FRAME_T9, 347 FRAME_T10, 348 FRAME_T11, 349 FRAME_RA, 350 FRAME_T12, 351 FRAME_AT, 352 FRAME_GP, 353 FRAME_SP, 354 -1, /* zero */ 355 }; 356 357 u_long 358 db_register_value(regs, regno) 359 db_regs_t *regs; 360 int regno; 361 { 362 363 if (regno > 31 || regno < 0) { 364 db_printf(" **** STRANGE REGISTER NUMBER %d **** ", regno); 365 return (0); 366 } 367 368 if (regno == 31) 369 return (0); 370 371 return (regs->tf_regs[reg_to_frame[regno]]); 372 } 373 374 /* 375 * Support functions for software single-step. 376 */ 377 378 boolean_t 379 db_inst_call(ins) 380 int ins; 381 { 382 alpha_instruction insn; 383 384 insn.bits = ins; 385 return ((insn.branch_format.opcode == op_bsr) || 386 ((insn.jump_format.opcode == op_j) && 387 (insn.jump_format.action & 1))); 388 } 389 390 boolean_t 391 db_inst_return(ins) 392 int ins; 393 { 394 alpha_instruction insn; 395 396 insn.bits = ins; 397 return ((insn.jump_format.opcode == op_j) && 398 (insn.jump_format.action == op_ret)); 399 } 400 401 boolean_t 402 db_inst_trap_return(ins) 403 int ins; 404 { 405 alpha_instruction insn; 406 407 insn.bits = ins; 408 return ((insn.pal_format.opcode == op_pal) && 409 (insn.pal_format.function == PAL_OSF1_rti)); 410 } 411 412 boolean_t 413 db_inst_branch(ins) 414 int ins; 415 { 416 alpha_instruction insn; 417 418 insn.bits = ins; 419 switch (insn.branch_format.opcode) { 420 case op_j: 421 case op_br: 422 case op_fbeq: 423 case op_fblt: 424 case op_fble: 425 case op_fbne: 426 case op_fbge: 427 case op_fbgt: 428 case op_blbc: 429 case op_beq: 430 case op_blt: 431 case op_ble: 432 case op_blbs: 433 case op_bne: 434 case op_bge: 435 case op_bgt: 436 return (TRUE); 437 } 438 439 return (FALSE); 440 } 441 442 boolean_t 443 db_inst_unconditional_flow_transfer(ins) 444 int ins; 445 { 446 alpha_instruction insn; 447 448 insn.bits = ins; 449 switch (insn.branch_format.opcode) { 450 case op_j: 451 case op_br: 452 return (TRUE); 453 454 case op_pal: 455 switch (insn.pal_format.function) { 456 case PAL_OSF1_retsys: 457 case PAL_OSF1_rti: 458 case PAL_OSF1_callsys: 459 return (TRUE); 460 } 461 } 462 463 return (FALSE); 464 } 465 466 #if 0 467 boolean_t 468 db_inst_spill(ins, regn) 469 int ins, regn; 470 { 471 alpha_instruction insn; 472 473 insn.bits = ins; 474 return ((insn.mem_format.opcode == op_stq) && 475 (insn.mem_format.rd == regn)); 476 } 477 #endif 478 479 boolean_t 480 db_inst_load(ins) 481 int ins; 482 { 483 alpha_instruction insn; 484 485 insn.bits = ins; 486 487 /* Loads. */ 488 if (insn.mem_format.opcode == op_ldbu || 489 insn.mem_format.opcode == op_ldq_u || 490 insn.mem_format.opcode == op_ldwu) 491 return (TRUE); 492 if ((insn.mem_format.opcode >= op_ldf) && 493 (insn.mem_format.opcode <= op_ldt)) 494 return (TRUE); 495 if ((insn.mem_format.opcode >= op_ldl) && 496 (insn.mem_format.opcode <= op_ldq_l)) 497 return (TRUE); 498 499 /* Prefetches. */ 500 if (insn.mem_format.opcode == op_special) { 501 /* Note: MB is treated as a store. */ 502 if ((insn.mem_format.displacement == (short)op_fetch) || 503 (insn.mem_format.displacement == (short)op_fetch_m)) 504 return (TRUE); 505 } 506 507 return (FALSE); 508 } 509 510 boolean_t 511 db_inst_store(ins) 512 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(ins, pc, regs) 541 int ins; 542 db_addr_t pc; 543 db_regs_t *regs; 544 { 545 long signed_immediate; 546 alpha_instruction insn; 547 db_addr_t newpc; 548 549 insn.bits = ins; 550 switch (insn.branch_format.opcode) { 551 /* 552 * Jump format: target PC is (contents of instruction's "RB") & ~3. 553 */ 554 case op_j: 555 newpc = db_register_value(regs, insn.jump_format.rb) & ~3; 556 break; 557 558 /* 559 * Branch format: target PC is 560 * (new PC) + (4 * sign-ext(displacement)). 561 */ 562 case op_br: 563 case op_fbeq: 564 case op_fblt: 565 case op_fble: 566 case op_bsr: 567 case op_fbne: 568 case op_fbge: 569 case op_fbgt: 570 case op_blbc: 571 case op_beq: 572 case op_blt: 573 case op_ble: 574 case op_blbs: 575 case op_bne: 576 case op_bge: 577 case op_bgt: 578 signed_immediate = insn.branch_format.displacement; 579 newpc = (pc + 4) + (signed_immediate << 2); 580 break; 581 582 default: 583 printf("DDB: db_inst_branch_taken on non-branch!\n"); 584 newpc = pc; /* XXX */ 585 } 586 587 return (newpc); 588 } 589