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