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