1 /* $NetBSD: db_interface.c,v 1.140 2026/02/25 05:34:42 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 1996-2002 Eduardo Horvath. All rights reserved. 5 * Mach Operating System 6 * Copyright (c) 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 (at) 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 * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) 30 */ 31 32 /* 33 * Interface to new debugger. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.140 2026/02/25 05:34:42 skrll Exp $"); 38 39 #ifdef _KERNEL_OPT 40 #include "opt_ddb.h" 41 #include "opt_multiprocessor.h" 42 #endif 43 44 #include <sys/param.h> 45 #include <sys/proc.h> 46 #include <sys/reboot.h> 47 #include <sys/systm.h> 48 #include <sys/atomic.h> 49 50 #include <uvm/uvm.h> 51 52 #include <dev/cons.h> 53 54 #include <machine/db_machdep.h> 55 #include <ddb/db_active.h> 56 #include <ddb/db_command.h> 57 #include <ddb/db_sym.h> 58 #include <ddb/db_variables.h> 59 #include <ddb/db_user.h> 60 #include <ddb/db_extern.h> 61 #include <ddb/db_access.h> 62 #include <ddb/db_output.h> 63 #include <ddb/db_interface.h> 64 #include <ddb/ddbvar.h> 65 66 #include <machine/instr.h> 67 #include <machine/cpu.h> 68 #ifdef _KERNEL 69 #include <machine/promlib.h> 70 #endif 71 #include <machine/ctlreg.h> 72 #include <machine/pmap.h> 73 #include <machine/intr.h> 74 #include <machine/vmparam.h> 75 76 #ifdef _KERNEL 77 #include "fb.h" 78 #else 79 #include <stddef.h> 80 #include <stdbool.h> 81 #endif 82 83 extern struct traptrace { 84 unsigned short tl:3, /* Trap level */ 85 ns:4, /* PCB nsaved */ 86 tt:9; /* Trap type */ 87 unsigned short pid; /* PID */ 88 u_int tstate; /* tstate */ 89 u_int tsp; /* sp */ 90 u_int tpc; /* pc */ 91 u_int tfault; /* MMU tag access */ 92 } trap_trace[], trap_trace_end[]; 93 94 void fill_ddb_regs_from_tf(struct trapframe64 *tf); 95 void ddb_restore_state(void); 96 bool ddb_running_on_this_cpu(void); 97 98 #ifdef DDB 99 int db_active = 0; 100 #endif 101 102 extern char *trap_type[]; 103 104 void kdb_kbd_trap(struct trapframe64 *); 105 void db_prom_cmd(db_expr_t, bool, db_expr_t, const char *); 106 void db_lwp_cmd(db_expr_t, bool, db_expr_t, const char *); 107 void db_proc_cmd(db_expr_t, bool, db_expr_t, const char *); 108 void db_ctx_cmd(db_expr_t, bool, db_expr_t, const char *); 109 void db_dump_pcb(db_expr_t, bool, db_expr_t, const char *); 110 void db_dump_pv(db_expr_t, bool, db_expr_t, const char *); 111 void db_setpcb(db_expr_t, bool, db_expr_t, const char *); 112 void db_dump_dtlb(db_expr_t, bool, db_expr_t, const char *); 113 void db_dump_itlb(db_expr_t, bool, db_expr_t, const char *); 114 void db_dump_dtsb(db_expr_t, bool, db_expr_t, const char *); 115 void db_dump_itsb(db_expr_t, bool, db_expr_t, const char *); 116 void db_pmap_kernel(db_expr_t, bool, db_expr_t, const char *); 117 void db_pload_cmd(db_expr_t, bool, db_expr_t, const char *); 118 void db_pmap_cmd(db_expr_t, bool, db_expr_t, const char *); 119 void db_traptrace(db_expr_t, bool, db_expr_t, const char *); 120 void db_watch(db_expr_t, bool, db_expr_t, const char *); 121 void db_pm_extract(db_expr_t, bool, db_expr_t, const char *); 122 void db_cpu_cmd(db_expr_t, bool, db_expr_t, const char *); 123 void db_sir_cmd(db_expr_t, bool, db_expr_t, const char *); 124 125 #ifdef DDB 126 static void db_dump_pmap(struct pmap *); 127 static void db_print_trace_entry(struct traptrace *, int); 128 129 #ifdef MULTIPROCESSOR 130 131 #define NOCPU -1 132 133 static int db_suspend_others(void); 134 static void ddb_suspend(struct trapframe64 *); 135 void db_resume_others(void); 136 137 int ddb_cpu = NOCPU; 138 139 bool 140 ddb_running_on_this_cpu(void) 141 { 142 return ddb_cpu == cpu_number(); 143 } 144 145 static int 146 db_suspend_others(void) 147 { 148 int cpu_me = cpu_number(); 149 bool win; 150 151 if (cpus == NULL) 152 return 1; 153 154 win = atomic_cas_32(&ddb_cpu, NOCPU, cpu_me) == (uint32_t)NOCPU; 155 if (win) 156 mp_pause_cpus(); 157 158 return win; 159 } 160 161 void 162 db_resume_others(void) 163 { 164 int cpu_me = cpu_number(); 165 166 if (atomic_cas_32(&ddb_cpu, cpu_me, NOCPU) == cpu_me) 167 mp_resume_cpus(); 168 } 169 170 static void 171 ddb_suspend(struct trapframe64 *tf) 172 { 173 174 sparc64_ipi_pause_thiscpu(tf); 175 } 176 #endif /* MULTIPROCESSOR */ 177 178 /* 179 * Received keyboard interrupt sequence. 180 */ 181 void 182 kdb_kbd_trap(struct trapframe64 *tf) 183 { 184 if (db_active == 0 /* && (boothowto & RB_KDB) */) { 185 printf("\n\nkernel: keyboard interrupt tf=%p\n", tf); 186 kdb_trap(-1, tf); 187 } 188 } 189 190 void 191 fill_ddb_regs_from_tf(struct trapframe64 *tf) 192 { 193 extern int savetstate(struct trapstate *); 194 195 #ifdef MULTIPROCESSOR 196 static db_regs_t ddbregs[CPUSET_MAXNUMCPU]; 197 198 curcpu()->ci_ddb_regs = &ddbregs[cpu_number()]; 199 #else 200 static db_regs_t ddbregs; 201 202 curcpu()->ci_ddb_regs = &ddbregs; 203 #endif 204 205 DDB_REGS->db_tf = *tf; 206 #ifdef __arch64__ 207 DDB_REGS->db_fr = *(struct frame64 *)(uintptr_t)tf->tf_out[6]; 208 #else 209 { 210 struct frame32 *tf32 = (struct frame32 *)(uintptr_t)tf->tf_out[6]; 211 int i; 212 213 for (i = 0; i < 8; i++) 214 DDB_REGS->db_fr.fr_local[i] = (uint32_t)tf32->fr_local[i]; 215 for (i = 0; i < 6; i++) 216 DDB_REGS->db_fr.fr_arg[i] = (uint32_t)tf32->fr_arg[i]; 217 DDB_REGS->db_fr.fr_fp = tf32->fr_fp; 218 DDB_REGS->db_fr.fr_pc = tf32->fr_pc; 219 } 220 #endif 221 222 if (fplwp) { 223 savefpstate(fplwp->l_md.md_fpstate); 224 DDB_REGS->db_fpstate = *fplwp->l_md.md_fpstate; 225 loadfpstate(fplwp->l_md.md_fpstate); 226 } 227 /* We should do a proper copyin and xlate 64-bit stack frames, but... */ 228 /* if (tf->tf_tstate & TSTATE_PRIV) { .. } */ 229 230 #if 0 231 /* make sure this is not causing ddb problems. */ 232 if (tf->tf_out[6] & 1) { 233 if ((unsigned)(tf->tf_out[6] + BIAS) > (unsigned)KERNBASE) 234 DDB_REGS->db_fr = *(struct frame64 *)(tf->tf_out[6] + BIAS); 235 else 236 copyin((void *)(tf->tf_out[6] + BIAS), &DDB_REGS->db_fr, sizeof(struct frame64)); 237 } else { 238 struct frame32 tfr; 239 int i; 240 241 /* First get a local copy of the frame32 */ 242 if ((unsigned)(tf->tf_out[6]) > (unsigned)KERNBASE) 243 tfr = *(struct frame32 *)tf->tf_out[6]; 244 else 245 copyin((void *)(tf->tf_out[6]), &tfr, sizeof(struct frame32)); 246 /* Now copy each field from the 32-bit value to the 64-bit value */ 247 for (i=0; i<8; i++) 248 DDB_REGS->db_fr.fr_local[i] = tfr.fr_local[i]; 249 for (i=0; i<6; i++) 250 DDB_REGS->db_fr.fr_arg[i] = tfr.fr_arg[i]; 251 DDB_REGS->db_fr.fr_fp = (long)tfr.fr_fp; 252 DDB_REGS->db_fr.fr_pc = tfr.fr_pc; 253 } 254 #else 255 int i; 256 for (i=0; i<8; i++) 257 DDB_REGS->db_fr.fr_local[i] = tf->tf_local[i]; 258 for (i=0; i<6; i++) 259 DDB_REGS->db_fr.fr_arg[i] = tf->tf_in[i]; 260 /* XXX tp and pc are missing */ 261 #endif 262 DDB_REGS->db_tl = savetstate(&DDB_REGS->db_ts[0]); 263 } 264 265 void 266 ddb_restore_state(void) 267 { 268 extern void restoretstate(int, struct trapstate *); 269 270 restoretstate(DDB_REGS->db_tl, &DDB_REGS->db_ts[0]); 271 if (fplwp) { 272 *fplwp->l_md.md_fpstate = DDB_REGS->db_fpstate; 273 loadfpstate(fplwp->l_md.md_fpstate); 274 } 275 } 276 277 /* 278 * kdb_trap - field a TRACE or BPT trap 279 */ 280 int 281 kdb_trap(int type, struct trapframe64 *tf) 282 { 283 int s; 284 extern int trap_trace_dis; 285 extern int doing_shutdown; 286 287 trap_trace_dis++; 288 doing_shutdown++; 289 #if NFB > 0 290 fb_unblank(); 291 #endif 292 switch (type) { 293 case T_BREAKPOINT: /* breakpoint */ 294 break; 295 case -1: /* keyboard interrupt */ 296 printf("kdb tf=%p\n", tf); 297 break; 298 default: 299 if (!db_onpanic && db_recover==0) 300 return (0); 301 302 printf("kernel trap %x: %s\n", type, trap_type[type & 0x1ff]); 303 if (db_recover != 0) { 304 prom_abort(); 305 db_error("Faulted in DDB; continuing...\n"); 306 prom_abort(); 307 /*NOTREACHED*/ 308 } 309 db_recover = (label_t *)1; 310 } 311 312 /* Should switch to kdb`s own stack here. */ 313 write_all_windows(); 314 315 #if defined(MULTIPROCESSOR) 316 if (!db_suspend_others()) { 317 ddb_suspend(tf); 318 return 1; 319 } 320 #endif 321 322 /* Initialise local dbregs storage from trap frame */ 323 fill_ddb_regs_from_tf(tf); 324 325 s = splhigh(); 326 db_active++; 327 cnpollc(true); 328 /* Need to do spl stuff till cnpollc works */ 329 db_dump_ts(0, 0, 0, 0); 330 db_trap(type, 0/*code*/); 331 ddb_restore_state(); 332 cnpollc(false); 333 db_active--; 334 335 splx(s); 336 337 *tf = DDB_REGS->db_tf; 338 curcpu()->ci_ddb_regs = NULL; 339 340 trap_trace_dis--; 341 doing_shutdown--; 342 343 #if defined(MULTIPROCESSOR) 344 db_resume_others(); 345 #endif 346 347 return (1); 348 } 349 #endif /* DDB */ 350 351 #ifdef _KERNEL 352 /* 353 * Read bytes from kernel address space for debugger. 354 */ 355 void 356 db_read_bytes(db_addr_t addr, size_t size, char *data) 357 { 358 char *src; 359 360 src = (char *)(uintptr_t)addr; 361 while (size-- > 0) { 362 *data++ = probeget((paddr_t)(u_long)src++, ASI_P, 1); 363 } 364 } 365 366 367 /* 368 * Write bytes to kernel address space for debugger. 369 */ 370 void 371 db_write_bytes(db_addr_t addr, size_t size, const char *data) 372 { 373 char *dst; 374 extern paddr_t pmap_kextract(vaddr_t va); 375 extern vaddr_t ektext; 376 377 dst = (char *)(uintptr_t)addr; 378 while (size-- > 0) { 379 if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS) && 380 (dst < (char *)ektext)) 381 /* Read Only mapping -- need to do a bypass access */ 382 stba(pmap_kextract((vaddr_t)dst), ASI_PHYS_CACHED, *data); 383 else 384 *dst = *data; 385 dst++, data++; 386 } 387 388 } 389 #endif 390 391 #ifdef DDB 392 void 393 Debugger(void) 394 { 395 /* We use the breakpoint to trap into DDB */ 396 __asm("ta 1; nop"); 397 } 398 399 void 400 db_prom_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 401 { 402 prom_abort(); 403 } 404 405 /* 406 * Dump the [ID]TLB's. 407 * 408 * Spitfire has 64 entry TLBs for instruction and data. 409 * 410 * Cheetah has 5 TLBs in total: 411 * instruction tlbs - it16, it128 -- 16 and 128 entry TLBs 412 * data tlbs - dt16, dt512_0, dt512_1 -- 16, and 2*512 entry TLBs 413 * 414 * The TLB chosen is chosen depending on the values in bits 16/17, 415 * and the address is the index shifted 3 bits left. 416 * 417 * These are in db_tlb_access.S: 418 * void print_dtlb(size_t tlbsize, int tlbmask) 419 * void print_itlb(size_t tlbsize, int tlbmask) 420 */ 421 422 void 423 db_dump_dtlb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 424 { 425 extern void print_dtlb(size_t /*tlbsize*/, int /*tlbmask*/); 426 427 if (CPU_IS_USIII_UP()) { 428 print_dtlb(TLB_SIZE_CHEETAH_D16, TLB_CHEETAH_D16); 429 db_printf("DT512_0:\n"); 430 print_dtlb(TLB_SIZE_CHEETAH_D512_0, TLB_CHEETAH_D512_0); 431 db_printf("DT512_1:\n"); 432 print_dtlb(TLB_SIZE_CHEETAH_D512_1, TLB_CHEETAH_D512_1); 433 } else 434 print_dtlb(TLB_SIZE_SPITFIRE, 0); 435 } 436 437 void 438 db_dump_itlb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 439 { 440 extern void print_itlb(size_t /*tlbsize*/, int /*tlbmask*/); 441 442 if (CPU_IS_USIII_UP()) { 443 print_itlb(TLB_SIZE_CHEETAH_I16, TLB_CHEETAH_I16); 444 db_printf("IT128:\n"); 445 print_itlb(TLB_SIZE_CHEETAH_I128, TLB_CHEETAH_I128); 446 } else 447 print_itlb(TLB_SIZE_SPITFIRE, 0); 448 } 449 450 void 451 db_pload_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 452 { 453 static paddr_t oldaddr = -1; 454 int asi = ASI_PHYS_CACHED; 455 456 if (!have_addr) { 457 addr = oldaddr; 458 } 459 if (addr == -1) { 460 db_printf("no address\n"); 461 return; 462 } 463 addr &= ~0x7; /* align */ 464 { 465 register char c; 466 register const char *cp = modif; 467 while ((c = *cp++) != 0) 468 if (c == 'u') 469 asi = ASI_AIUS; 470 } 471 while (count--) { 472 if (db_print_position() == 0) { 473 /* Always print the address. */ 474 db_printf("%16.16lx:\t", (long)addr); 475 } 476 oldaddr=addr; 477 db_printf("%8.8lx\n", (long)ldxa(addr, asi)); 478 addr += 8; 479 if (db_print_position() != 0) 480 db_end_line(); 481 } 482 } 483 484 /* XXX no locking; shouldn't matter */ 485 int64_t pseg_get_real(struct pmap *, vaddr_t); 486 487 void 488 db_dump_pmap(struct pmap *pm) 489 { 490 /* print all valid pages in the kernel pmap */ 491 unsigned long long i, j, k, data0, data1; 492 paddr_t *pdir, *ptbl; 493 494 for (i = 0; i < STSZ; i++) { 495 pdir = (paddr_t *)(u_long)ldxa((vaddr_t)&pm->pm_segs[i], ASI_PHYS_CACHED); 496 if (!pdir) { 497 continue; 498 } 499 db_printf("pdir %lld at %lx:\n", i, (long)pdir); 500 for (k = 0; k < PDSZ; k++) { 501 ptbl = (paddr_t *)(u_long)ldxa((vaddr_t)&pdir[k], ASI_PHYS_CACHED); 502 if (!ptbl) { 503 continue; 504 } 505 db_printf("\tptable %lld:%lld at %lx:\n", i, k, (long)ptbl); 506 for (j = 0; j < PTSZ; j++) { 507 data0 = ldxa((vaddr_t)&ptbl[j], ASI_PHYS_CACHED); 508 j++; 509 data1 = ldxa((vaddr_t)&ptbl[j], ASI_PHYS_CACHED); 510 if (!data0 && !data1) { 511 continue; 512 } 513 db_printf("%016llx: %016llx\t", 514 (i << STSHIFT) | (k << PDSHIFT) | ((j - 1) << PTSHIFT), 515 data0); 516 db_printf("%016llx: %016llx\n", 517 (i << STSHIFT) | (k << PDSHIFT) | (j << PTSHIFT), 518 data1); 519 } 520 } 521 } 522 } 523 524 void 525 db_pmap_kernel(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 526 { 527 int i, j, full = 0; 528 uint64_t data; 529 530 { 531 register char c; 532 register const char *cp = modif; 533 while ((c = *cp++) != 0) 534 if (c == 'f') 535 full = 1; 536 } 537 if (have_addr) { 538 /* lookup an entry for this VA */ 539 540 if ((data = pseg_get_real(pmap_kernel(), (vaddr_t)addr))) { 541 db_printf("pmap_kernel(%p)->pm_segs[%lx][%lx][%lx]=>%qx\n", 542 (void *)(uintptr_t)addr, (u_long)va_to_seg(addr), 543 (u_long)va_to_dir(addr), (u_long)va_to_pte(addr), 544 (unsigned long long)data); 545 } else { 546 db_printf("No mapping for %p\n", (void *)(uintptr_t)addr); 547 } 548 return; 549 } 550 551 db_printf("pmap_kernel(%p) psegs %p phys %llx\n", 552 pmap_kernel(), pmap_kernel()->pm_segs, 553 (unsigned long long)pmap_kernel()->pm_physaddr); 554 if (full) { 555 db_dump_pmap(pmap_kernel()); 556 } else { 557 for (j=i=0; i<STSZ; i++) { 558 long seg = (long)ldxa((vaddr_t)pmap_kernel()->pm_segs[i], ASI_PHYS_CACHED); 559 if (seg) 560 db_printf("seg %d => %lx%c", i, seg, (j++%4)?'\t':'\n'); 561 } 562 } 563 } 564 565 void 566 db_pm_extract(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 567 { 568 if (have_addr) { 569 paddr_t pa; 570 571 if (pmap_extract(pmap_kernel(), addr, &pa)) 572 db_printf("pa = %llx\n", (long long)pa); 573 else 574 db_printf("%p not found\n", (void *)(uintptr_t)addr); 575 } else 576 db_printf("pmap_extract: no address\n"); 577 } 578 579 void 580 db_pmap_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 581 { 582 struct pmap* pm=NULL; 583 int i, j=0, full = 0; 584 585 { 586 register char c; 587 register const char *cp = modif; 588 if (modif) 589 while ((c = *cp++) != 0) 590 if (c == 'f') 591 full = 1; 592 } 593 if (curlwp && curlwp->l_proc->p_vmspace) 594 pm = curlwp->l_proc->p_vmspace->vm_map.pmap; 595 if (have_addr) 596 pm = (struct pmap*)(uintptr_t)addr; 597 598 db_printf("pmap %p: ctx %x refs %d physaddr %llx psegs %p\n", 599 pm, pmap_ctx(pm), pm->pm_refs, 600 (unsigned long long)pm->pm_physaddr, pm->pm_segs); 601 602 if (full) { 603 db_dump_pmap(pm); 604 } else { 605 for (i=0; i<STSZ; i++) { 606 long seg = (long)ldxa((vaddr_t)pmap_kernel()->pm_segs[i], ASI_PHYS_CACHED); 607 if (seg) 608 db_printf("seg %d => %lx%c", i, seg, (j++%4)?'\t':'\n'); 609 } 610 } 611 } 612 613 #define TSBENTS (512 << tsbsize) 614 extern pte_t *tsb_dmmu, *tsb_immu; 615 extern int tsbsize; 616 617 void db_dump_tsb_common(pte_t *); 618 619 void 620 db_dump_dtsb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 621 { 622 623 db_printf("DTSB:\n"); 624 db_dump_tsb_common(curcpu()->ci_tsb_dmmu); 625 } 626 627 void 628 db_dump_itsb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 629 { 630 631 db_printf("ITSB:\n"); 632 db_dump_tsb_common(curcpu()->ci_tsb_immu); 633 } 634 635 void 636 db_dump_tsb_common(pte_t *tsb) 637 { 638 uint64_t tag, data; 639 int i; 640 641 for (i = 0; i < TSBENTS; i++) { 642 tag = tsb[i].tag; 643 data = tsb[i].data; 644 db_printf("%4d:%4d:%08x %08x:%08x ", i, 645 (int)((tag & TSB_TAG_G) ? -1 : TSB_TAG_CTX(tag)), 646 (int)((i << 13) | TSB_TAG_VA(tag)), 647 (int)(data >> 32), (int)data); 648 i++; 649 tag = tsb[i].tag; 650 data = tsb[i].data; 651 db_printf("%4d:%4d:%08x %08x:%08x\n", i, 652 (int)((tag & TSB_TAG_G) ? -1 : TSB_TAG_CTX(tag)), 653 (int)((i << 13) | TSB_TAG_VA(tag)), 654 (int)(data >> 32), (int)data); 655 } 656 } 657 658 void db_page_cmd(db_expr_t, bool, db_expr_t, const char *); 659 void 660 db_page_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 661 { 662 663 if (!have_addr) { 664 db_printf("Need paddr for page\n"); 665 return; 666 } 667 668 db_printf("pa %llx pg %p\n", (unsigned long long)addr, 669 PHYS_TO_VM_PAGE(addr)); 670 } 671 672 void 673 db_lwp_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 674 { 675 struct lwp *l; 676 677 l = curlwp; 678 if (have_addr) 679 l = (struct lwp*)(uintptr_t)addr; 680 if (l == NULL) { 681 db_printf("no current lwp\n"); 682 return; 683 } 684 db_printf("lwp %p: lid %d\n", l, l->l_lid); 685 db_printf("wchan:%p pri:%d epri:%d tf:%p\n", 686 l->l_wchan, l->l_priority, lwp_eprio(l), l->l_md.md_tf); 687 db_printf("pcb: %p fpstate: %p\n", lwp_getpcb(l), 688 l->l_md.md_fpstate); 689 return; 690 } 691 692 void 693 db_proc_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 694 { 695 struct proc *p = NULL; 696 697 if (curlwp) 698 p = curlwp->l_proc; 699 if (have_addr) 700 p = (struct proc*)(uintptr_t)addr; 701 if (p == NULL) { 702 db_printf("no current process\n"); 703 return; 704 } 705 db_printf("process %p:", p); 706 db_printf("pid:%d vmspace:%p pmap:%p ctx:%x\n", 707 p->p_pid, p->p_vmspace, p->p_vmspace->vm_map.pmap, 708 pmap_ctx(p->p_vmspace->vm_map.pmap)); 709 db_printf("maxsaddr:%p ssiz:%dpg or %llxB\n", 710 p->p_vmspace->vm_maxsaddr, p->p_vmspace->vm_ssize, 711 (unsigned long long)ctob(p->p_vmspace->vm_ssize)); 712 db_printf("profile timer: %" PRId64 " sec %ld nsec\n", 713 p->p_stats->p_timer[ITIMER_PROF].it_value.tv_sec, 714 p->p_stats->p_timer[ITIMER_PROF].it_value.tv_nsec); 715 return; 716 } 717 718 void 719 db_ctx_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 720 { 721 struct proc *p; 722 struct lwp *l; 723 struct pcb *pcb; 724 725 /* XXX LOCKING XXX */ 726 LIST_FOREACH(p, &allproc, p_list) { 727 if (p->p_stat) { 728 db_printf("process %p:", p); 729 db_printf("pid:%d pmap:%p ctx:%x\n", 730 p->p_pid, p->p_vmspace->vm_map.pmap, 731 pmap_ctx(p->p_vmspace->vm_map.pmap)); 732 LIST_FOREACH(l, &p->p_lwps, l_sibling) { 733 pcb = lwp_getpcb(l); 734 db_printf("\tlwp %p: lid:%d tf:%p fpstate %p " 735 "lastcall:%s\n", 736 l, l->l_lid, l->l_md.md_tf, l->l_md.md_fpstate, 737 (pcb->lastcall) ? 738 pcb->lastcall : "Null"); 739 } 740 } 741 } 742 return; 743 } 744 745 void 746 db_dump_pcb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 747 { 748 struct pcb *pcb; 749 int i; 750 751 pcb = curpcb; 752 if (have_addr) 753 pcb = (struct pcb*)(uintptr_t)addr; 754 755 db_printf("pcb@%p sp:%p pc:%p cwp:%d pil:%d nsaved:%x onfault:%p\nlastcall:%s\nfull windows:\n", 756 pcb, (void *)(long)pcb->pcb_sp, (void *)(long)pcb->pcb_pc, pcb->pcb_cwp, 757 pcb->pcb_pil, pcb->pcb_nsaved, (void *)pcb->pcb_onfault, 758 (pcb->lastcall)?pcb->lastcall:"Null"); 759 760 for (i=0; i<pcb->pcb_nsaved; i++) { 761 db_printf("win %d: at %llx local, in\n", i, 762 (unsigned long long)pcb->pcb_rw[i+1].rw_in[6]); 763 db_printf("%16llx %16llx %16llx %16llx\n", 764 (unsigned long long)pcb->pcb_rw[i].rw_local[0], 765 (unsigned long long)pcb->pcb_rw[i].rw_local[1], 766 (unsigned long long)pcb->pcb_rw[i].rw_local[2], 767 (unsigned long long)pcb->pcb_rw[i].rw_local[3]); 768 db_printf("%16llx %16llx %16llx %16llx\n", 769 (unsigned long long)pcb->pcb_rw[i].rw_local[4], 770 (unsigned long long)pcb->pcb_rw[i].rw_local[5], 771 (unsigned long long)pcb->pcb_rw[i].rw_local[6], 772 (unsigned long long)pcb->pcb_rw[i].rw_local[7]); 773 db_printf("%16llx %16llx %16llx %16llx\n", 774 (unsigned long long)pcb->pcb_rw[i].rw_in[0], 775 (unsigned long long)pcb->pcb_rw[i].rw_in[1], 776 (unsigned long long)pcb->pcb_rw[i].rw_in[2], 777 (unsigned long long)pcb->pcb_rw[i].rw_in[3]); 778 db_printf("%16llx %16llx %16llx %16llx\n", 779 (unsigned long long)pcb->pcb_rw[i].rw_in[4], 780 (unsigned long long)pcb->pcb_rw[i].rw_in[5], 781 (unsigned long long)pcb->pcb_rw[i].rw_in[6], 782 (unsigned long long)pcb->pcb_rw[i].rw_in[7]); 783 } 784 } 785 786 787 void 788 db_setpcb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 789 { 790 struct proc *p; 791 int ctx; 792 793 if (!have_addr) { 794 db_printf("What PID do you want to map in?\n"); 795 return; 796 } 797 798 LIST_FOREACH(p, &allproc, p_list) { 799 if (p->p_stat && p->p_pid == addr) { 800 if (p->p_vmspace->vm_map.pmap == pmap_kernel()) { 801 db_printf("PID %ld has a kernel context.\n", 802 (long)addr); 803 return; 804 } 805 ctx = pmap_ctx(p->p_vmspace->vm_map.pmap); 806 if (ctx < 0) { 807 ctx = -ctx; 808 pmap_ctx(p->p_vmspace->vm_map.pmap) = ctx; 809 } else if (ctx == 0) { 810 pmap_activate_pmap(p->p_vmspace->vm_map.pmap); 811 ctx = pmap_ctx(p->p_vmspace->vm_map.pmap); 812 } 813 if (ctx > 0) { 814 if (CPU_IS_USIII_UP()) 815 switchtoctx_usiii(ctx); 816 else 817 switchtoctx_us(ctx); 818 return; 819 } 820 db_printf("could not activate pmap for PID %ld.\n", 821 (long)addr); 822 return; 823 } 824 } 825 db_printf("PID %ld not found.\n", (long)addr); 826 } 827 828 static void 829 db_print_trace_entry(struct traptrace *te, int i) 830 { 831 db_printf("%d:%d p:%d tt:%x:%llx:%llx %llx:%llx ", i, 832 (int)te->tl, (int)te->pid, 833 (int)te->tt, (unsigned long long)te->tstate, 834 (unsigned long long)te->tfault, (unsigned long long)te->tsp, 835 (unsigned long long)te->tpc); 836 db_printsym((u_long)te->tpc, DB_STGY_PROC, db_printf); 837 db_printf(": "); 838 if ((te->tpc && !(te->tpc&0x3)) && 839 curlwp && 840 (curproc->p_pid == te->pid)) { 841 db_disasm((u_long)te->tpc, 0); 842 } else db_printf("\n"); 843 } 844 845 void 846 db_traptrace(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 847 { 848 int i, start = 0, full = 0, reverse = 0; 849 struct traptrace *end; 850 851 start = 0; 852 end = &trap_trace_end[0]; 853 854 { 855 register char c; 856 register const char *cp = modif; 857 if (modif) 858 while ((c = *cp++) != 0) { 859 if (c == 'f') 860 full = 1; 861 if (c == 'r') 862 reverse = 1; 863 } 864 } 865 866 if (have_addr) { 867 start = addr / (sizeof (struct traptrace)); 868 if (&trap_trace[start] > &trap_trace_end[0]) { 869 db_printf("Address out of range.\n"); 870 return; 871 } 872 if (!full) end = &trap_trace[start+1]; 873 } 874 875 db_printf("#:tl p:pid tt:tt:tstate:tfault sp:pc\n"); 876 if (reverse) { 877 if (full && start) 878 for (i=start; --i;) { 879 db_print_trace_entry(&trap_trace[i], i); 880 } 881 i = (end - &trap_trace[0]); 882 while(--i > start) { 883 db_print_trace_entry(&trap_trace[i], i); 884 } 885 } else { 886 for (i=start; &trap_trace[i] < end ; i++) { 887 db_print_trace_entry(&trap_trace[i], i); 888 } 889 if (full && start) 890 for (i=0; i < start ; i++) { 891 db_print_trace_entry(&trap_trace[i], i); 892 } 893 } 894 } 895 896 /* 897 * Use physical or virtual watchpoint registers -- ugh 898 * 899 * UltraSPARC I and II have both a virtual and physical 900 * watchpoint register. They are controlled by the LSU 901 * control register. 902 */ 903 void 904 db_watch(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 905 { 906 int phys = 0; 907 int read = 0; 908 int width = 8; /* Default to 8 bytes */ 909 int64_t mask = 0xff; 910 911 #define WATCH_VR (1L<<22) 912 #define WATCH_VW (1L<<21) 913 #define WATCH_PR (1L<<24) 914 #define WATCH_PW (1L<<23) 915 #define WATCH_PM_SHIFT 33 916 #define WATCH_PM (((uint64_t)0xffffL)<<WATCH_PM_SHIFT) 917 #define WATCH_VM_SHIFT 25 918 #define WATCH_VM (((uint64_t)0xffffL)<<WATCH_VM_SHIFT) 919 920 { 921 register char c; 922 register const char *cp = modif; 923 if (modif) 924 while ((c = *cp++) != 0) 925 switch (c) { 926 case 'p': 927 /* Physical watchpoint */ 928 phys = 1; 929 break; 930 case 'r': 931 /* Trap reads too */ 932 read = 1; 933 break; 934 case 'b': 935 width = 1; 936 mask = 0x1 << (addr & 0x7); 937 break; 938 case 'h': 939 width = 2; 940 mask = 0x3 << (addr & 0x6); 941 break; 942 case 'l': 943 width = 4; 944 mask = 0x7 << (addr & 0x4); 945 break; 946 case 'L': 947 width = 8; 948 mask = 0xf; 949 break; 950 default: 951 break; 952 } 953 } 954 955 if (have_addr) { 956 /* turn on the watchpoint */ 957 int64_t tmp = ldxa(0, ASI_MCCR); 958 959 if (phys) { 960 tmp &= ~WATCH_PM; 961 tmp |= WATCH_PW | (mask << WATCH_PM_SHIFT); 962 if (read) tmp |= WATCH_PR; 963 964 stxa(PHYSICAL_WATCHPOINT, ASI_DMMU, addr); 965 db_printf("Setting physical watchpoint to %llx-%llx\n", 966 (long long)addr, (long long)addr + width); 967 } else { 968 tmp &= ~WATCH_VM; 969 tmp |= WATCH_VW | (mask << WATCH_VM_SHIFT); 970 if (read) tmp |= WATCH_VR; 971 972 stxa(VIRTUAL_WATCHPOINT, ASI_DMMU, addr); 973 db_printf("Setting virtual watchpoint to %llx-%llx\n", 974 (long long)addr, (long long)addr + width); 975 } 976 stxa(0, ASI_MCCR, tmp); 977 } else { 978 /* turn off the watchpoint */ 979 int64_t tmp = ldxa(0, ASI_MCCR); 980 if (phys) { 981 tmp &= ~(WATCH_PM|WATCH_PR|WATCH_PW); 982 db_printf("Disabling physical watchpoint\n"); 983 } else { 984 tmp &= ~(WATCH_VM|WATCH_VR|WATCH_VW); 985 db_printf("Disabling virtual watchpoint\n"); 986 } 987 stxa(0, ASI_MCCR, tmp); 988 } 989 } 990 991 /* XXX this belongs in cpu.c */ 992 static void cpu_debug_dump(void); 993 static void 994 cpu_debug_dump(void) 995 { 996 struct cpu_info *ci; 997 998 for (ci = cpus; ci; ci = ci->ci_next) { 999 db_printf("cpu%d: self 0x%08lx lwp 0x%08lx pcb 0x%08lx " 1000 "fplwp 0x%08lx\n", ci->ci_index, (u_long)ci->ci_self, 1001 (u_long)ci->ci_curlwp, (u_long)ci->ci_cpcb, 1002 (u_long)ci->ci_fplwp); 1003 } 1004 } 1005 1006 void 1007 db_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 1008 { 1009 #ifdef MULTIPROCESSOR 1010 struct cpu_info *ci; 1011 #endif 1012 1013 if (!have_addr) { 1014 cpu_debug_dump(); 1015 return; 1016 } 1017 #ifdef MULTIPROCESSOR 1018 for (ci = cpus; ci != NULL; ci = ci->ci_next) 1019 if (ci->ci_index == addr) 1020 break; 1021 if (ci == NULL) { 1022 db_printf("CPU %ld not configured\n", (long)addr); 1023 return; 1024 } 1025 if (ci != curcpu()) { 1026 if (!mp_cpu_is_paused(ci->ci_index)) { 1027 db_printf("CPU %ld not paused\n", (long)addr); 1028 return; 1029 } 1030 /* no locking needed - all other cpus are paused */ 1031 ddb_cpu = ci->ci_index; 1032 mp_resume_cpu(ddb_cpu); 1033 sparc64_do_pause(); 1034 } 1035 #endif 1036 } 1037 1038 void 1039 db_sir_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 1040 { 1041 1042 __asm("sir; nop"); 1043 } 1044 1045 const struct db_command db_machine_command_table[] = { 1046 { DDB_ADD_CMD("ctx", db_ctx_cmd, 0, 1047 "Print process MMU context information", NULL,NULL) }, 1048 #ifdef MULTIPROCESSOR 1049 { DDB_ADD_CMD("cpu", db_cpu_cmd, 0, 1050 "switch to another cpu", "cpu-no", NULL) }, 1051 #endif 1052 { DDB_ADD_CMD("dtlb", db_dump_dtlb, 0, 1053 "Display data translation look-aside buffer context information.", 1054 NULL,NULL) }, 1055 { DDB_ADD_CMD("itlb", db_dump_itlb, 0, 1056 "Display instruction translation look-aside buffer information.", 1057 NULL,NULL) }, 1058 { DDB_ADD_CMD("dtsb", db_dump_dtsb, 0, 1059 "Display data translation storage buffer information.", NULL,NULL) }, 1060 { DDB_ADD_CMD("itsb", db_dump_itsb, 0, 1061 "Display instruction translation storage buffer information.", 1062 NULL,NULL) }, 1063 { DDB_ADD_CMD("extract", db_pm_extract, 0, 1064 "Extract the physical address from the kernel pmap.", 1065 "address", " address:\tvirtual address to look up") }, 1066 { DDB_ADD_CMD("fpstate", db_dump_fpstate,0, 1067 "Dump the FPU state." ,NULL,NULL) }, 1068 { DDB_ADD_CMD("kmap", db_pmap_kernel, 0, 1069 "Display information about mappings in the kernel pmap.", 1070 "[/f] [address]", 1071 " address:\tdisplay the mapping for this virtual address\n" 1072 " /f:\tif no address is given, display a full dump of the pmap") }, 1073 { DDB_ADD_CMD("lwp", db_lwp_cmd, 0, 1074 "Display a struct lwp", 1075 "[address]", 1076 " address:\tthe struct lwp to print (curlwp otherwise)") }, 1077 { DDB_ADD_CMD("pcb", db_dump_pcb, 0, 1078 "Display information about a struct pcb", 1079 "[address]", 1080 " address:\tthe struct pcb to print (curpcb otherwise)") }, 1081 { DDB_ADD_CMD("pctx", db_setpcb, 0, 1082 "Attempt to change MMU process context","pid", 1083 " pid:\tthe process id to switch the MMU context to") }, 1084 { DDB_ADD_CMD("page", db_page_cmd, 0, 1085 "Display the address of a struct vm_page given a physical address", 1086 "pa", " pa:\tphysical address to look up") }, 1087 { DDB_ADD_CMD("phys", db_pload_cmd, 0, 1088 "Display physical memory.", "[address][,count]", 1089 " address:\tphysical address to start (8 byte aligned)\n" 1090 " count:\tnumber of bytes to display") }, 1091 { DDB_ADD_CMD("pmap", db_pmap_cmd, 0, 1092 "Display the pmap", "[/f] [pm_addr]", 1093 " pm_addr:\tAddress of struct pmap to display\n" 1094 " /f:\tdo a full dump of the pmap") }, 1095 { DDB_ADD_CMD("proc", db_proc_cmd, 0, 1096 "Display some information about a process", 1097 "[addr]"," addr:\tstruct proc address (curproc otherwise)") }, 1098 { DDB_ADD_CMD("prom", db_prom_cmd, 0, 1099 "Enter the OFW PROM.", NULL,NULL) }, 1100 { DDB_ADD_CMD("pv", db_dump_pv, 0, 1101 "Display a struct pv for a physical address", 1102 "pa", " pa:\tphysical address of a managed page") }, 1103 { DDB_ADD_CMD("sir", db_sir_cmd, 0, 1104 "do a Software Initiated Reset (entering PROM)", NULL,NULL) }, 1105 { DDB_ADD_CMD("stack", db_dump_stack, 0, 1106 "Dump the window stack.", "[/u] [addr]", 1107 " addr:\tstart address of dump (current stack otherwise)\n" 1108 " /u:\tcontinue trace into userland") }, 1109 { DDB_ADD_CMD("tf", db_dump_trap, 0, 1110 "Display full trap frame state.", 1111 "[/u] [addr]", 1112 " addr:\tdisplay this trap frame (current kernel frame otherwise)\n" 1113 " /u:\tdisplay the current userland trap frame") }, 1114 { DDB_ADD_CMD("ts", db_dump_ts, 0, 1115 "Display trap state.", NULL,NULL) }, 1116 { DDB_ADD_CMD("traptrace", db_traptrace, 0, 1117 "Display or set trap trace information.", 1118 "[/fr] [addr]", 1119 " addr:\tstart address of trace\n" 1120 " /f:\tdisplay full information\n" 1121 " /r:\treverse the trace order") }, 1122 { DDB_ADD_CMD("watch", db_watch, 0, 1123 "Set or clear a physical or virtual hardware watchpoint.", 1124 "[/prbhlL] [addr]", 1125 " addr:\tset the breakpoint (clear watchpoint if not present)\n" 1126 " /p:\taddress is physical\n" 1127 " /r:\ttrap on reads too (otherwise only write access)\n" 1128 " /b:\t8 bit\n" 1129 " /h:\t16 bit\n" 1130 " /l:\t32 bit\n" 1131 " /L:\t64 bit") }, 1132 { DDB_ADD_CMD("window", db_dump_window, 0, 1133 "Print register window information", 1134 "[no]", " no:\tstack frame number (0, i.e. top, if missing)") }, 1135 { DDB_END_CMD }, 1136 }; 1137 #endif /* DDB */ 1138 1139 /* 1140 * support for SOFTWARE_SSTEP: 1141 * return the next pc if the given branch is taken. 1142 * 1143 * note: in the case of conditional branches with annul, 1144 * this actually returns the next pc in the "not taken" path, 1145 * but in that case next_instr_address() will return the 1146 * next pc in the "taken" path. so even tho the breakpoints 1147 * are backwards, everything will still work, and the logic is 1148 * much simpler this way. 1149 */ 1150 db_addr_t 1151 db_branch_taken(int inst, db_addr_t pc, db_regs_t *regs) 1152 { 1153 union instr insn; 1154 db_addr_t npc; 1155 1156 npc = DDB_REGS->db_tf.tf_npc; 1157 1158 insn.i_int = inst; 1159 1160 /* 1161 * if this is not an annulled conditional branch, the next pc is "npc". 1162 */ 1163 1164 if (insn.i_any.i_op != IOP_OP2 || insn.i_branch.i_annul != 1) 1165 return npc; 1166 1167 switch (insn.i_op2.i_op2) { 1168 case IOP2_Bicc: 1169 case IOP2_FBfcc: 1170 case IOP2_BPcc: 1171 case IOP2_FBPfcc: 1172 case IOP2_CBccc: 1173 /* branch on some condition-code */ 1174 switch (insn.i_branch.i_cond) 1175 { 1176 case Icc_A: /* always */ 1177 return pc + ((inst << 10) >> 8); 1178 1179 default: /* all other conditions */ 1180 return npc + 4; 1181 } 1182 1183 case IOP2_BPr: 1184 /* branch on register, always conditional */ 1185 return npc + 4; 1186 1187 default: 1188 /* not a branch */ 1189 printf("branch_taken() on non-branch"); 1190 return pc; 1191 } 1192 } 1193 1194 bool 1195 db_inst_branch(int inst) 1196 { 1197 union instr insn; 1198 1199 insn.i_int = inst; 1200 1201 if (insn.i_any.i_op != IOP_OP2) 1202 return false; 1203 1204 switch (insn.i_op2.i_op2) { 1205 case IOP2_BPcc: 1206 case IOP2_Bicc: 1207 case IOP2_BPr: 1208 case IOP2_FBPfcc: 1209 case IOP2_FBfcc: 1210 case IOP2_CBccc: 1211 return true; 1212 1213 default: 1214 return false; 1215 } 1216 } 1217 1218 1219 bool 1220 db_inst_call(int inst) 1221 { 1222 union instr insn; 1223 1224 insn.i_int = inst; 1225 1226 switch (insn.i_any.i_op) { 1227 case IOP_CALL: 1228 return true; 1229 1230 case IOP_reg: 1231 return (insn.i_op3.i_op3 == IOP3_JMPL) && !db_inst_return(inst); 1232 1233 default: 1234 return false; 1235 } 1236 } 1237 1238 1239 bool 1240 db_inst_unconditional_flow_transfer(int inst) 1241 { 1242 union instr insn; 1243 1244 insn.i_int = inst; 1245 1246 if (db_inst_call(inst)) 1247 return true; 1248 1249 if (insn.i_any.i_op != IOP_OP2) 1250 return false; 1251 1252 switch (insn.i_op2.i_op2) 1253 { 1254 case IOP2_BPcc: 1255 case IOP2_Bicc: 1256 case IOP2_FBPfcc: 1257 case IOP2_FBfcc: 1258 case IOP2_CBccc: 1259 return insn.i_branch.i_cond == Icc_A; 1260 1261 default: 1262 return false; 1263 } 1264 } 1265 1266 1267 bool 1268 db_inst_return(int inst) 1269 { 1270 return (inst == I_JMPLri(I_G0, I_O7, 8) || /* ret */ 1271 inst == I_JMPLri(I_G0, I_I7, 8)); /* retl */ 1272 } 1273 1274 bool 1275 db_inst_trap_return(int inst) 1276 { 1277 union instr insn; 1278 1279 insn.i_int = inst; 1280 1281 return (insn.i_any.i_op == IOP_reg && 1282 insn.i_op3.i_op3 == IOP3_RETT); 1283 } 1284 1285 1286 int 1287 db_inst_load(int inst) 1288 { 1289 union instr insn; 1290 1291 insn.i_int = inst; 1292 1293 if (insn.i_any.i_op != IOP_mem) 1294 return 0; 1295 1296 switch (insn.i_op3.i_op3) { 1297 case IOP3_LD: 1298 case IOP3_LDUB: 1299 case IOP3_LDUH: 1300 case IOP3_LDD: 1301 case IOP3_LDSB: 1302 case IOP3_LDSH: 1303 case IOP3_LDSTUB: 1304 case IOP3_SWAP: 1305 case IOP3_LDA: 1306 case IOP3_LDUBA: 1307 case IOP3_LDUHA: 1308 case IOP3_LDDA: 1309 case IOP3_LDSBA: 1310 case IOP3_LDSHA: 1311 case IOP3_LDSTUBA: 1312 case IOP3_SWAPA: 1313 case IOP3_LDF: 1314 case IOP3_LDFSR: 1315 case IOP3_LDDF: 1316 case IOP3_LFC: 1317 case IOP3_LDCSR: 1318 case IOP3_LDDC: 1319 return 1; 1320 1321 default: 1322 return 0; 1323 } 1324 } 1325 1326 int 1327 db_inst_store(int inst) 1328 { 1329 union instr insn; 1330 1331 insn.i_int = inst; 1332 1333 if (insn.i_any.i_op != IOP_mem) 1334 return 0; 1335 1336 switch (insn.i_op3.i_op3) { 1337 case IOP3_ST: 1338 case IOP3_STB: 1339 case IOP3_STH: 1340 case IOP3_STD: 1341 case IOP3_LDSTUB: 1342 case IOP3_SWAP: 1343 case IOP3_STA: 1344 case IOP3_STBA: 1345 case IOP3_STHA: 1346 case IOP3_STDA: 1347 case IOP3_LDSTUBA: 1348 case IOP3_SWAPA: 1349 case IOP3_STF: 1350 case IOP3_STFSR: 1351 case IOP3_STDFQ: 1352 case IOP3_STDF: 1353 case IOP3_STC: 1354 case IOP3_STCSR: 1355 case IOP3_STDCQ: 1356 case IOP3_STDC: 1357 return 1; 1358 1359 default: 1360 return 0; 1361 } 1362 } 1363