1 /* $OpenBSD: db_interface.c,v 1.32 2024/11/07 16:02:29 miod Exp $ */ 2 /* 3 * Mach Operating System 4 * Copyright (c) 1993-1991 Carnegie Mellon University 5 * Copyright (c) 1991 OMRON Corporation 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 AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND 16 * FOR 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 29 /* 30 * m88k interface to ddb debugger 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/proc.h> 36 #include <sys/reboot.h> 37 38 #include <uvm/uvm_extern.h> 39 40 #include <machine/asm_macro.h> 41 #include <machine/cmmu.h> 42 #include <machine/trap.h> 43 #include <machine/db_machdep.h> 44 #include <machine/cpu.h> 45 #ifdef M88100 46 #include <machine/m88100.h> 47 #include <machine/m8820x.h> 48 #endif 49 50 #include <ddb/db_access.h> 51 #include <ddb/db_command.h> 52 #include <ddb/db_extern.h> 53 #include <ddb/db_interface.h> 54 #include <ddb/db_output.h> 55 #include <ddb/db_run.h> 56 #include <ddb/db_sym.h> 57 58 extern label_t *db_recover; 59 extern int frame_is_sane(db_regs_t *, int); /* db_trace */ 60 extern void cnpollc(int); 61 62 void kdbprinttrap(int); 63 64 int m88k_dmx_print(u_int, u_int, u_int, u_int); 65 66 void m88k_db_trap(int, struct trapframe *); 67 void m88k_db_print_frame(db_expr_t, int, db_expr_t, char *); 68 void m88k_db_registers(db_expr_t, int, db_expr_t, char *); 69 void m88k_db_where(db_expr_t, int, db_expr_t, char *); 70 void m88k_db_frame_search(db_expr_t, int, db_expr_t, char *); 71 72 db_regs_t ddb_regs; 73 74 #ifdef MULTIPROCESSOR 75 #include <sys/mplock.h> 76 struct __mp_lock ddb_mp_lock; 77 cpuid_t ddb_mp_nextcpu = (cpuid_t)-1; 78 79 void m88k_db_cpu_cmd(db_expr_t, int, db_expr_t, char *); 80 #endif 81 82 /* 83 * If you really feel like understanding the following procedure and 84 * macros, see pages 6-22 to 6-30 (Section 6.7.3) of 85 * 86 * MC88100 RISC Microprocessor User's Manual Second Edition 87 * (Motorola Order: MC88100UM/AD REV 1) 88 * 89 * and ERRATA-5 (6-23, 6-24, 6-24) of 90 * 91 * Errata to MC88100 User's Manual Second Edition MC88100UM/AD Rev 1 92 * (Oct 2, 1990) 93 * (Motorola Order: MC88100UMAD/AD) 94 */ 95 96 #ifdef M88100 97 /* macros for decoding dmt registers */ 98 99 /* 100 * return 1 if the printing of the next stage should be suppressed 101 */ 102 int 103 m88k_dmx_print(u_int t, u_int d, u_int a, u_int no) 104 { 105 static const u_int addr_mod[16] = { 106 0, 3, 2, 2, 1, 0, 0, 0, 107 0, 0, 0, 0, 0, 0, 0, 0 108 }; 109 static const char *mode[16] = { 110 "?", ".b", ".b", ".h", ".b", "?", "?", "?", 111 ".b", "?", "?" , "?" , ".h" , "?", "?", "" 112 }; 113 static const u_int mask[16] = { 114 0, 0xff, 0xff00, 0xffff, 115 0xff0000, 0, 0, 0, 116 0xff000000, 0, 0, 0, 117 0xffff0000, 0, 0, 0xffffffff 118 }; 119 static const u_int shift[16] = { 120 0, 0, 8, 0, 16, 0, 0, 0, 121 24, 0, 0, 0, 16, 0, 0, 0 122 }; 123 int reg = DMT_DREGBITS(t); 124 125 if (ISSET(t, DMT_LOCKBAR)) { 126 db_printf("xmem%s%s r%d(0x%x) <-> mem(0x%x),", 127 DMT_ENBITS(t) == 0x0f ? "" : ".bu", 128 ISSET(t, DMT_DAS) ? "" : ".usr", reg, 129 ((t >> 2 & 0xf) == 0xf) ? d : (d & 0xff), a); 130 return 1; 131 } else if (DMT_ENBITS(t) == 0xf) { 132 /* full or double word */ 133 if (ISSET(t, DMT_WRITE)) { 134 if (ISSET(t, DMT_DOUB1) && no == 2) 135 db_printf("st.d%s -> mem(0x%x) (** restart sxip **)", 136 ISSET(t, DMT_DAS) ? "" : ".usr", a); 137 else 138 db_printf("st%s (0x%x) -> mem(0x%x)", 139 ISSET(t, DMT_DAS) ? "" : ".usr", d, a); 140 } else { 141 /* load */ 142 if (ISSET(t, DMT_DOUB1) && no == 2) 143 db_printf("ld.d%s r%d <- mem(0x%x), r%d <- mem(0x%x)", 144 ISSET(t, DMT_DAS) ? "" : ".usr", reg, a, reg+1, a+4); 145 else 146 db_printf("ld%s r%d <- mem(0x%x)", 147 ISSET(t, DMT_DAS) ? "" : ".usr", reg, a); 148 } 149 } else { 150 /* fractional word - check if load or store */ 151 a += addr_mod[DMT_ENBITS(t)]; 152 if (ISSET(t, DMT_WRITE)) 153 db_printf("st%s%s (0x%x) -> mem(0x%x)", 154 mode[DMT_ENBITS(t)], 155 ISSET(t, DMT_DAS) ? "" : ".usr", 156 (d & mask[DMT_ENBITS(t)]) >> shift[DMT_ENBITS(t)], 157 a); 158 else 159 db_printf("ld%s%s%s r%d <- mem(0x%x)", 160 mode[DMT_ENBITS(t)], 161 ISSET(t, DMT_SIGNED) ? "" : "u", 162 ISSET(t, DMT_DAS) ? "" : ".usr", reg, a); 163 } 164 return (0); 165 } 166 #endif /* M88100 */ 167 168 void 169 m88k_db_print_frame(addr, have_addr, count, modif) 170 db_expr_t addr; 171 int have_addr; 172 db_expr_t count; 173 char *modif; 174 { 175 struct trapframe *s = (struct trapframe *)addr; 176 const char *name; 177 db_expr_t offset; 178 #ifdef M88100 179 int suppress1 = 0, suppress2 = 0; 180 #endif 181 int c, force = 0, help = 0; 182 183 if (!have_addr) { 184 db_printf("requires address of frame\n"); 185 help = 1; 186 } 187 188 while (modif && *modif) { 189 switch (c = *modif++, c) { 190 case 'f': 191 force = 1; 192 break; 193 case 'h': 194 help = 1; 195 break; 196 default: 197 db_printf("unknown modifier [%c]\n", c); 198 help = 1; 199 break; 200 } 201 } 202 203 if (help) { 204 db_printf("usage: mach frame/[f] ADDRESS\n"); 205 db_printf(" /f force printing of insane frames.\n"); 206 return; 207 } 208 209 if (badaddr((vaddr_t)s, 4) || 210 badaddr((vaddr_t)(&((db_regs_t*)s)->fpit), 4)) { 211 db_printf("frame at %8p is unreadable\n", s); 212 return; 213 } 214 215 if (frame_is_sane((db_regs_t *)s, 0) == 0) { 216 if (force == 0) 217 return; 218 } 219 220 #define R(i) s->tf_r[i] 221 #define IPMASK(x) ((x) & ~(3)) 222 db_printf("R00-05: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", 223 R(0), R(1), R(2), R(3), R(4), R(5)); 224 db_printf("R06-11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", 225 R(6), R(7), R(8), R(9), R(10), R(11)); 226 db_printf("R12-17: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", 227 R(12), R(13), R(14), R(15), R(16), R(17)); 228 db_printf("R18-23: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", 229 R(18), R(19), R(20), R(21), R(22), R(23)); 230 db_printf("R24-29: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", 231 R(24), R(25), R(26), R(27), R(28), R(29)); 232 db_printf("R30-31: 0x%08lx 0x%08lx\n", R(30), R(31)); 233 234 db_printf("%cxip: 0x%08lx ", 235 CPU_IS88110 ? 'e' : 's', s->tf_sxip & XIP_ADDR); 236 db_find_xtrn_sym_and_offset((vaddr_t)IPMASK(s->tf_sxip), 237 &name, &offset); 238 if (name != NULL && (u_int)offset <= db_maxoff) 239 db_printf("%s+0x%08x", name, (u_int)offset); 240 db_printf("\n"); 241 242 if (s->tf_snip != s->tf_sxip + 4) { 243 db_printf("%cnip: 0x%08lx ", 244 CPU_IS88110 ? 'e' : 's', s->tf_snip); 245 db_find_xtrn_sym_and_offset((vaddr_t)IPMASK(s->tf_snip), 246 &name, &offset); 247 if (name != NULL && (u_int)offset <= db_maxoff) 248 db_printf("%s+0x%08x", name, (u_int)offset); 249 db_printf("\n"); 250 } 251 252 #ifdef M88100 253 if (CPU_IS88100) { 254 if (s->tf_sfip != s->tf_snip + 4) { 255 db_printf("sfip: 0x%08lx ", s->tf_sfip); 256 db_find_xtrn_sym_and_offset((vaddr_t)IPMASK(s->tf_sfip), 257 &name, &offset); 258 if (name != NULL && (u_int)offset <= db_maxoff) 259 db_printf("%s+0x%08x", name, (u_int)offset); 260 db_printf("\n"); 261 } 262 } 263 #endif 264 #ifdef M88110 265 if (CPU_IS88110) { 266 db_printf("fpsr: 0x%08lx fpcr: 0x%08lx fpecr: 0x%08lx\n", 267 s->tf_fpsr, s->tf_fpcr, s->tf_fpecr); 268 db_printf("dsap 0x%08lx duap 0x%08lx dsr 0x%08lx dlar 0x%08lx dpar 0x%08lx\n", 269 s->tf_dsap, s->tf_duap, s->tf_dsr, s->tf_dlar, s->tf_dpar); 270 db_printf("isap 0x%08lx iuap 0x%08lx isr 0x%08lx ilar 0x%08lx ipar 0x%08lx\n", 271 s->tf_isap, s->tf_iuap, s->tf_isr, s->tf_ilar, s->tf_ipar); 272 } 273 #endif 274 275 db_printf("epsr: 0x%08lx current process: %p\n", 276 s->tf_epsr, curproc); 277 db_printf("vector: 0x%02lx interrupt mask: 0x%08lx\n", 278 s->tf_vector, s->tf_mask); 279 280 /* 281 * If the vector indicates trap, instead of an exception or 282 * interrupt, skip the check of dmt and fp regs. 283 * 284 * Interrupt and exceptions are vectored at 0-10 and 114-127. 285 */ 286 if (!(s->tf_vector <= 10 || 287 (114 <= s->tf_vector && s->tf_vector <= 127))) { 288 db_printf("\n"); 289 return; 290 } 291 292 #ifdef M88100 293 if (CPU_IS88100) { 294 if (s->tf_vector == /*data*/3 || s->tf_dmt0 & DMT_VALID) { 295 db_printf("dmt,d,a0: 0x%08lx 0x%08lx 0x%08lx ", 296 s->tf_dmt0, s->tf_dmd0, s->tf_dma0); 297 db_find_xtrn_sym_and_offset((vaddr_t)s->tf_dma0, 298 &name, &offset); 299 if (name != NULL && (u_int)offset <= db_maxoff) 300 db_printf("%s+0x%08x", name, (u_int)offset); 301 db_printf("\n "); 302 303 suppress1 = m88k_dmx_print(s->tf_dmt0, s->tf_dmd0, 304 s->tf_dma0, 0); 305 db_printf("\n"); 306 307 if ((s->tf_dmt1 & DMT_VALID) && (!suppress1)) { 308 db_printf("dmt,d,a1: 0x%08lx 0x%08lx 0x%08lx ", 309 s->tf_dmt1, s->tf_dmd1, s->tf_dma1); 310 db_find_xtrn_sym_and_offset((vaddr_t)s->tf_dma1, 311 &name, &offset); 312 if (name != NULL && (u_int)offset <= db_maxoff) 313 db_printf("%s+0x%08x", name, 314 (u_int)offset); 315 db_printf("\n "); 316 suppress2 = m88k_dmx_print(s->tf_dmt1, 317 s->tf_dmd1, s->tf_dma1, 1); 318 db_printf("\n"); 319 320 if ((s->tf_dmt2 & DMT_VALID) && (!suppress2)) { 321 db_printf("dmt,d,a2: 0x%08lx 0x%08lx 0x%08lx ", 322 s->tf_dmt2, s->tf_dmd2, s->tf_dma2); 323 db_find_xtrn_sym_and_offset((vaddr_t)s->tf_dma2, 324 &name, &offset); 325 if (name != 0 && 326 (u_int)offset <= db_maxoff) 327 db_printf("%s+0x%08x", name, 328 (u_int)offset); 329 db_printf("\n "); 330 m88k_dmx_print(s->tf_dmt2, s->tf_dmd2, 331 s->tf_dma2, 2); 332 db_printf("\n"); 333 } 334 } 335 336 db_printf("fault code %ld\n", 337 CMMU_PFSR_FAULT(s->tf_dpfsr)); 338 } 339 } 340 #endif /* M88100 */ 341 342 if (s->tf_fpecr & 255) { /* floating point error occurred */ 343 db_printf("fpecr: 0x%08lx fpsr: 0x%08lx fpcr: 0x%08lx\n", 344 s->tf_fpecr, s->tf_fpsr, s->tf_fpcr); 345 #ifdef M88100 346 if (CPU_IS88100) { 347 db_printf("fcr1-4: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", 348 s->tf_fphs1, s->tf_fpls1, s->tf_fphs2, s->tf_fpls2); 349 db_printf("fcr5-8: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", 350 s->tf_fppt, s->tf_fprh, s->tf_fprl, s->tf_fpit); 351 } 352 #endif 353 } 354 db_printf("\n"); 355 } 356 357 void 358 m88k_db_registers(addr, have_addr, count, modif) 359 db_expr_t addr; 360 int have_addr; 361 db_expr_t count; 362 char *modif; 363 { 364 m88k_db_print_frame((db_expr_t)&ddb_regs, TRUE, 0, modif); 365 } 366 367 /* 368 * m88k_db_trap - field a TRACE or BPT trap 369 * Note that only the tf_regs part of the frame is valid - some ddb routines 370 * invoke this function with a promoted struct reg! 371 */ 372 void 373 m88k_db_trap(type, frame) 374 int type; 375 struct trapframe *frame; 376 { 377 #ifdef MULTIPROCESSOR 378 struct cpu_info *ci = curcpu(); 379 #endif 380 381 switch(type) { 382 case T_KDB_BREAK: 383 case T_KDB_TRACE: 384 case T_KDB_ENTRY: 385 break; 386 case -1: 387 break; 388 default: 389 kdbprinttrap(type); 390 if (db_recover != 0) { 391 db_error("Caught exception in ddb.\n"); 392 /*NOTREACHED*/ 393 } 394 } 395 396 #ifdef MULTIPROCESSOR 397 ci->ci_ddb_state = CI_DDB_ENTERDDB; 398 __mp_lock(&ddb_mp_lock); 399 ci->ci_ddb_state = CI_DDB_INDDB; 400 ddb_mp_nextcpu = (cpuid_t)-1; 401 m88k_broadcast_ipi(CI_IPI_DDB); /* pause other processors */ 402 #endif 403 404 ddb_regs = frame->tf_regs; 405 406 db_active++; 407 cnpollc(1); 408 db_trap(type, 0); 409 cnpollc(0); 410 db_active--; 411 412 frame->tf_regs = ddb_regs; 413 414 #ifdef MULTIPROCESSOR 415 ci->ci_ddb_state = CI_DDB_RUNNING; 416 __mp_release_all(&ddb_mp_lock); 417 #endif 418 } 419 420 extern const char *trap_type[]; 421 extern const int trap_types; 422 423 /* 424 * Print trap reason. 425 */ 426 void 427 kdbprinttrap(int type) 428 { 429 printf("kernel: "); 430 if (type >= trap_types || type < 0) 431 printf("type %d", type); 432 else 433 printf("%s", trap_type[type]); 434 printf(" trap\n"); 435 } 436 437 void 438 db_enter(void) 439 { 440 asm (ENTRY_ASM); /* entry trap */ 441 /* ends up at ddb_entry_trap below */ 442 return; 443 } 444 445 /* 446 * When the below routine is entered interrupts should be on 447 * but spl should be high 448 * 449 * The following routine is for breakpoint and watchpoint entry. 450 */ 451 452 /* breakpoint/watchpoint entry */ 453 int 454 ddb_break_trap(type, eframe) 455 int type; 456 db_regs_t *eframe; 457 { 458 m88k_db_trap(type, (struct trapframe *)eframe); 459 460 if (type == T_KDB_BREAK) { 461 /* 462 * back up an instruction and retry the instruction 463 * at the breakpoint address. mc88110's exip reg 464 * already has the address of the exception instruction. 465 */ 466 if (CPU_IS88100) 467 m88100_rewind_insn(eframe); 468 } 469 470 return 0; 471 } 472 473 /* enter at splhigh */ 474 int 475 ddb_entry_trap(level, eframe) 476 int level; 477 db_regs_t *eframe; 478 { 479 m88k_db_trap(T_KDB_ENTRY, (struct trapframe *)eframe); 480 481 return 0; 482 } 483 484 /* 485 * Read bytes from kernel address space for debugger. 486 */ 487 void 488 db_read_bytes(vaddr_t addr, size_t size, void *datap) 489 { 490 char *data = datap, *src; 491 492 src = (char *)addr; 493 494 while (size-- > 0) { 495 *data++ = *src++; 496 } 497 } 498 499 /* 500 * Write bytes to kernel address space for debugger. 501 */ 502 void 503 db_write_bytes(vaddr_t addr, size_t size, void *datap) 504 { 505 extern pt_entry_t *pmap_pte(pmap_t, vaddr_t); 506 char *data = datap, *dst = (char *)addr; 507 vaddr_t va; 508 paddr_t pa; 509 pt_entry_t *pte, opte, npte; 510 size_t len, olen; 511 int cpu = cpu_number(); 512 513 while (size != 0) { 514 va = trunc_page((vaddr_t)dst); 515 #ifdef M88100 516 if (CPU_IS88100 && va >= BATC8_VA) 517 pte = NULL; 518 else 519 #endif 520 pte = pmap_pte(pmap_kernel(), va); 521 if (pte != NULL) { 522 opte = *pte; 523 pa = (opte & PG_FRAME) | ((vaddr_t)dst & PAGE_MASK); 524 } 525 len = PAGE_SIZE - ((vaddr_t)dst & PAGE_MASK); 526 if (len > size) 527 len = size; 528 size -= olen = len; 529 530 if (pte != NULL && (opte & PG_RO)) { 531 npte = opte & ~PG_RO; 532 *pte = npte; 533 cmmu_tlbis(cpu, va, npte); 534 } 535 while (len-- != 0) 536 *dst++ = *data++; 537 if (pte != NULL && (opte & PG_RO)) { 538 *pte = opte; 539 cmmu_tlbis(cpu, va, opte); 540 } 541 if (pte != NULL && (opte & (CACHE_INH | CACHE_WT)) == 0) { 542 cmmu_dcache_wb(cpu, pa, olen); 543 cmmu_icache_inv(cpu, pa, olen); 544 } 545 } 546 } 547 548 /* display where all the cpus are stopped at */ 549 void 550 m88k_db_where(addr, have_addr, count, modif) 551 db_expr_t addr; 552 int have_addr; 553 db_expr_t count; 554 char *modif; 555 { 556 const char *name; 557 db_expr_t offset; 558 vaddr_t l; 559 560 l = PC_REGS(&ddb_regs); /* clear low bits */ 561 562 db_find_xtrn_sym_and_offset(l, &name, &offset); 563 if (name && (u_int)offset <= db_maxoff) 564 db_printf("stopped at 0x%lx (%s+0x%lx)\n", l, name, offset); 565 else 566 db_printf("stopped at 0x%lx\n", l); 567 } 568 569 /* 570 * Walk back a stack, looking for exception frames. 571 * These frames are recognized by the routine frame_is_sane. Frames 572 * only start with zero, so we only call frame_is_sane if the 573 * current address contains zero. 574 * 575 * If addr is given, it is assumed to an address on the stack to be 576 * searched. Otherwise, r31 of the current cpu is used. 577 */ 578 void 579 m88k_db_frame_search(addr, have_addr, count, modif) 580 db_expr_t addr; 581 int have_addr; 582 db_expr_t count; 583 char *modif; 584 { 585 if (have_addr) 586 addr &= ~3; /* round to word */ 587 else 588 addr = (ddb_regs.r[31]); 589 590 /* walk back up stack until 8k boundary, looking for 0 */ 591 while (addr & ((8 * 1024) - 1)) { 592 if (frame_is_sane((db_regs_t *)addr, 1) != 0) 593 db_printf("frame found at 0x%lx\n", addr); 594 addr += 4; 595 } 596 597 db_printf("(Walked back until 0x%lx)\n",addr); 598 } 599 600 #ifdef MULTIPROCESSOR 601 602 void 603 m88k_db_cpu_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 604 { 605 cpuid_t cpu; 606 struct cpu_info *ci; 607 char state[15]; 608 609 /* switch to another processor if requested */ 610 if (have_addr) { 611 cpu = (cpuid_t)addr; 612 if (cpu >= 0 && cpu < MAX_CPUS && 613 ISSET(m88k_cpus[cpu].ci_flags, CIF_ALIVE)) { 614 ddb_mp_nextcpu = cpu; 615 db_cmd_loop_done = 1; 616 } else { 617 db_printf("cpu%ld is not active\n", cpu); 618 } 619 return; 620 } 621 622 db_printf(" cpu flags state curproc curpcb depth ipi\n"); 623 CPU_INFO_FOREACH(cpu, ci) { 624 switch (ci->ci_ddb_state) { 625 case CI_DDB_RUNNING: 626 strlcpy(state, "running", sizeof state); 627 break; 628 case CI_DDB_ENTERDDB: 629 strlcpy(state, "entering ddb", sizeof state); 630 break; 631 case CI_DDB_INDDB: 632 strlcpy(state, "in ddb", sizeof state); 633 break; 634 case CI_DDB_PAUSE: 635 strlcpy(state, "paused", sizeof state); 636 break; 637 default: 638 snprintf(state, sizeof state, "unknown (%d)", 639 ci->ci_ddb_state); 640 break; 641 } 642 db_printf("%ccpu%d %02x %-14s %08lx %08lx %3u %08x\n", 643 (cpu == cpu_number()) ? '*' : ' ', CPU_INFO_UNIT(ci), 644 ci->ci_flags, state, (register_t)ci->ci_curproc, 645 (register_t)ci->ci_curpcb, ci->ci_idepth, ci->ci_ipi); 646 } 647 } 648 649 #endif /* MULTIPROCESSOR */ 650 651 /************************/ 652 /* COMMAND TABLE / INIT */ 653 /************************/ 654 655 const struct db_command db_machine_command_table[] = { 656 #ifdef MULTIPROCESSOR 657 { "ddbcpu", m88k_db_cpu_cmd, 0, NULL }, 658 #endif 659 { "frame", m88k_db_print_frame, 0, NULL }, 660 { "regs", m88k_db_registers, 0, NULL }, 661 { "searchframe",m88k_db_frame_search, 0, NULL }, 662 { "where", m88k_db_where, 0, NULL }, 663 #if defined(EXTRA_MACHDEP_COMMANDS) 664 EXTRA_MACHDEP_COMMANDS 665 #endif 666 { NULL, NULL, 0, NULL } 667 }; 668 669 void 670 db_machine_init() 671 { 672 #ifdef MULTIPROCESSOR 673 __mp_lock_init(&ddb_mp_lock); 674 #endif 675 } 676