static int dis_rdpr(uint32_t *pc, uint32_t inst) { char *prs[] = { "%tpc", "%tnpc", "%tstate", "%tt", "%tick", "%tba", "%pstate", "%tl", "%pil", "%cwp", "%cansave", "%canrestore", "%cleanwin", "%otherwin", "%wstate", "%fq", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "%ver" }; if ((SIMM13(inst)) || (RS1(inst) >= 16 && RS1(inst) <=30)) { ILLEGAL; } (void)printf("%p:\trdpr\t%s,%s\n", (void *)pc, prs[RS1(inst)], sregs[RD(inst)]); return OK; }
void prologue(struct interpass_prolog *ipp) { int i, stack; stack = V9RESERVE + V9STEP(p2maxautooff); for (i = ipp->ipp_regs[0]; i; i >>= 1) if (i & 1) stack += 16; /* TODO printf("\t.proc %d\n"); */ if (SIMM13(stack)) printf("\tsave %%sp,-%d,%%sp\n", stack); else { printf("\tsetx -%d,%%g4,%%g1\n", stack); printf("\tsave %%sp,%%g1,%%sp\n"); } }
static int dis_wrpr(uint32_t *pc, uint32_t inst) { char *prs[] = { "%tpc", "%tnpc", "%tstate", "%tt", "%tick", "%tba", "%pstate", "%tl", "%pil", "%cwp", "%cansave", "%canrestore", "%cleanwin", "%otherwin", "%wstate", "%fq", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-" }; if (RD(inst) >= 15) { ILLEGAL; } (void)printf("%p:\twrpr\t%s,%s, ", (void *)pc, prs[RD(inst)], sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld, ", SIMM13(inst)); else (void)printf("%s, ", sregs[RS2(inst)]); (void)printf("%s\n", sregs[RD(inst)]); return OK; }
void zzzcode(NODE * p, int c) { char *str; NODE *l, *r; int sz; l = p->n_left; r = p->n_right; switch (c) { case 'A': /* Add const. */ if (ISPTR(l->n_type) && l->n_rval == FP) r->n_lval += V9BIAS; if (SIMM13(r->n_lval)) expand(p, 0, "\tadd AL,AR,A1\t\t! add const\n"); else expand(p, 0, "\tsetx AR,A3,A2\t\t! add const\n" "\tadd AL,A2,A1\n"); break; case 'B': /* Subtract const. */ if (ISPTR(l->n_type) && l->n_rval == FP) r->n_lval -= V9BIAS; if (SIMM13(r->n_lval)) expand(p, 0, "\tsub AL,AR,A1\t\t! subtract const\n"); else expand(p, 0, "\tsetx AR,A3,A2\t\t! subtract const\n" "\tsub AL,A2,A1\n"); break; case 'C': /* Load constant to register. */ if (ISPTR(p->n_type)) expand(p, 0, "\tsethi %h44(AL),A1\t\t! load label\n" "\tor A1,%m44(AL),A1\n" "\tsllx A1,12,A1\n" "\tor A1,%l44(AL),A1\n"); else if (SIMM13(p->n_lval)) expand(p, 0, "\tor %g0,AL,A1\t\t\t! load const\n"); else expand(p, 0, "\tsetx AL,A2,A1\t\t! load const\n"); break; case 'F': /* Floating-point comparison, cf. hopcode(). */ switch (p->n_op) { case EQ: str = "fbe"; break; case NE: str = "fbne"; break; case ULE: case LE: str = "fbule"; break; case ULT: case LT: str = "fbul"; break; case UGE: case GE: str = "fbuge"; break; case UGT: case GT: str = "fbug"; break; /* XXX case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break;*/ default: comperr("unknown float code: %d", p->n_op); return; } printf(str); break; case 'Q': /* Structure assignment. */ /* TODO Check if p->n_stsize is small and use a few ldx's to move the struct instead of memcpy. The equiv. could be done on all the architectures. */ sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); if (l->n_rval != O0) printf("\tmov %s,%s\n", rnames[l->n_rval], rnames[O0]); if (SIMM13(sz)) printf("\tor %%g0,%d,%%o2\n", sz); else printf("\tsetx %d,%%g1,%%o2\n", sz); printf("\tcall memcpy\t\t\t! struct assign (dest, src, len)\n"); printf("\tnop\n"); break; default: cerror("unknown zzzcode call: %c", c); } }
static int dis_class3(uint32_t *pc, uint32_t inst) { int op3 = OP3(inst); char *opc[0x40] = { "lduw", "ldub", "lduh", "ldd", "stw", "stb", "sth", "std", "ldsw", "ldsb", "ldsh", "ldx", "-", "ldstub", "stx", "swap", "lduwa", "lduba", "lduha", "ldda", "stwa", "stba", "stha", "stda", "ldswa", "ldsba", "ldsha", "ldxa", "-", "ldstuba", "stxa", "swapa", "ldf", "ldfsr", "ldqf", "lddf" "stf", "stfsr", "stqf", "stdf", "-", "-", "-", "-", "-", "prefetch", "-", "-", "ldfa", "-", "ldqfa", "lddfa", "stfa", "-", "stqfa", "stdfa", "-", "-", "-", "-", "casa", "prefetcha", "casxa", "-" }; switch(op3) { case 0x0c: case 0x1c: case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2e: case 0x31: case 0x35: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3f: ILLEGAL; case 0x00: /* LDUW */ case 0x01: /* LDUB */ case 0x02: /* LDUH */ case 0x03: /* LDD */ case 0x08: /* LDSW */ case 0x09: /* LDSB */ case 0x0a: /* LDSH */ case 0x0b: /* LDX */ case 0x0d: /* LDSTUB */ case 0x1f: /* SWAP */ (void)printf("%p:\t%s\t[%s + ", (void *)pc, opc[op3], sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld], ", SIMM13(inst)); else (void)printf("%s], ", sregs[RS2(inst)]); (void)printf("%s\n", sregs[RD(inst)]); return OK; case 0x04: /* STW */ case 0x05: /* STB */ case 0x06: /* STH */ case 0x07: /* STD */ case 0x0e: /* STX */ (void)printf("%p:\t%s\t%s, ", (void *)pc, opc[op3], sregs[RD(inst)]); (void)printf("[%s + ", sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld]\n", SIMM13(inst)); else (void)printf("%s]\n", sregs[RS2(inst)]); return OK; case 0x10: /* LDUWA */ case 0x11: /* LDUBA */ case 0x12: /* LDUHA */ case 0x13: /* LDDA */ case 0x18: /* LDSWA */ case 0x19: /* LDSBA */ case 0x1a: /* LDSHA */ case 0x1b: /* LDXA */ case 0x1d: /* LDSTUBA */ case 0x2f: /* SWAPA */ case 0x3c: /* CASA */ case 0x3e: /* CASXA */ (void)printf("%p:\t%s\t[%s + ", (void *)pc, opc[op3], sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld] %%asi, ", SIMM13(inst)); else (void)printf("%s] 0x%x, ", sregs[RS2(inst)], IMMASI(inst)); (void)printf("%s\n", sregs[RD(inst)]); return OK; case 0x14: /* STWA */ case 0x15: /* STBA */ case 0x16: /* STHA */ case 0x17: /* STDA */ case 0x1e: /* STXA */ (void)printf("%p:\t%s\t%s, ", (void *)pc, opc[op3], sregs[RD(inst)]); (void)printf("[%s + ", sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld] %%asi\n", SIMM13(inst)); else (void)printf("%s] 0x%x\n", sregs[RS2(inst)], IMMASI(inst)); return OK; case 0x2d: /* PREFETCH */ if ((RD(inst) >=5) && (RD(inst) <= 15)) { ILLEGAL; } (void)printf("%p:\t%s\t[%s + ", (void *)pc, opc[op3], sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld], ", SIMM13(inst)); else (void)printf("%s], ", sregs[RS2(inst)]); (void)printf("%d\n", RD(inst)); return OK; case 0x3d: /* PREFETCHA */ if ((RD(inst) >=5) && (RD(inst) <= 15)) { ILLEGAL; } (void)printf("%p:\t%s\t[%s + ", (void *)pc, opc[op3], sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld] %%asi, ", SIMM13(inst)); else (void)printf("%s] 0x%x, ", sregs[RS2(inst)], IMMASI(inst)); (void)printf("%d\n", RD(inst)); return OK; case 0x20: case 0x21: case 0x22: case 0x23: case 0x30: case 0x32: case 0x33: (void)printf("XXXX %p:\tLDF XXX op3=%x\n", (void *)pc, OP3(inst)); return ERR; case 0x24: case 0x25: case 0x26: case 0x27: case 0x34: case 0x36: case 0x37: (void)printf("XXXX %p:\tSTF XXX op3=%x\n", (void *)pc, OP3(inst)); return ERR; default: (void)printf("XXXX dis_class3 op3=%x\n", OP3(inst)); return ERR; } }
static int dis_wrasr(uint32_t *pc, uint32_t inst) { char *asrs[] = { "wry", "-", "wrccr", "wrasi", "wrtick", "-", "wrfprs", "-", "-", "-", "-", "-", "-", "-", "-", "sir", }; if ((RD(inst) == 0xf) && (RS1(inst) != 0) && (IMM(inst) == 0)) { ILLEGAL; } switch(RD(inst)) { case 0x01: ILLEGAL; case 0x0f: /* SIR */ case 0x00: /* WRY */ case 0x02: /* WRCCR */ case 0x03: /* WRASI */ case 0x06: /* WRFPRS */ (void)printf("%p:\t%s\t%s,", (void *)pc, asrs[RD(inst)], sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld, ", SIMM13(inst)); else (void)printf("%s, ", sregs[RS2(inst)]); (void)printf("\n"); return OK; case 0x04: case 0x05: case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: ILLEGAL; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: (void)printf("%p:\twr\t%s, ", (void *)pc, sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld, ", SIMM13(inst)); else (void)printf("%s, ", sregs[RS2(inst)]); (void)printf("%%asr%d\n", RD(inst)); return ERR; default: (void)printf("XXXX wrasr %d\n", RD(inst)); return ERR; } }
static int dis_class2(uint32_t *pc, uint32_t inst) { int op3 = OP3(inst); char *opc[] = { "add", "and", "or", "xor", "sub", "andn", "orn", "xnor", "addc", "mulx", "umul", "smul", "subc", "udivx", "udiv", "sdiv", "addcc", "andcc", "orcc", "xorcc", "subcc", "andncc", "orncc", "xnorcc", "addccc", "-", "umulcc", "smulcc", "subccc", "-", "udivcc", "sdivcc", "taddcc", "tsubcc", "taddcctv", "tsubcctv", "mulscc", "sll", "srl", "sra", "rdy", "-", "rdpr", "flushw", "movcc", "sdivx", "popc", "movr", "wry", "saved", "wrpr", "-", "fpop1", "fpop2", "impldep1", "impldep2", "jmpl", "return", "tcc", "flush", "save", "restore", "done", "-" }; switch(op3) { case 0x00: /* ADD */ case 0x01: /* AND */ case 0x02: /* OR */ case 0x03: /* XOR */ case 0x04: /* SUB */ case 0x05: /* ANDN */ case 0x06: /* ORN */ case 0x07: /* XNOR */ case 0x08: /* ADDC */ case 0x09: /* MULX */ case 0x0a: /* UMUL */ case 0x0b: /* SMUL */ case 0x0c: /* SUBC */ case 0x0d: /* UDIVX */ case 0x0e: /* UDIV */ case 0x0f: /* SDIV */ case 0x10: /* ADDcc */ case 0x11: /* ANDcc */ case 0x12: /* ORcc */ case 0x13: /* XORcc */ case 0x14: /* SUBcc */ case 0x15: /* ANDNcc */ case 0x16: /* ORNcc */ case 0x17: /* XNORcc */ case 0x18: /* ANDCcc */ case 0x1a: /* UMULcc */ case 0x1b: /* SMULcc */ case 0x1c: /* SUBCcc */ case 0x1e: /* UDIVcc */ case 0x1f: /* SDIVcc */ case 0x20: /* TADDcc */ case 0x21: /* TSUBcc */ case 0x22: /* TADDccTV */ case 0x23: /* TSUBccTV */ case 0x24: /* MULScc */ case 0x2c: /* MOVcc */ case 0x2d: /* SDIVX */ case 0x2f: /* MOVr */ case 0x38: /* JMPL */ case 0x3c: /* SAVE */ case 0x3d: /* RESTORE */ (void)printf("%p:\t%s\t%s, ", (void *)pc, opc[op3], sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld, ", SIMM13(inst)); else (void)printf("%s, ", sregs[RS2(inst)]); (void)printf("%s\n", sregs[RD(inst)]); return (op3 == 0x38) ? DELAY : OK; case 0x2b: /* FLUSHW */ if ((RD(inst) == 0) && (RS1(inst) == 0) && (IMM(inst) == 0) && (SIMM13(inst) == 0)) { (void)printf("%p:\t%s\n", (void *)pc, opc[op3]); return OK; } ILLEGAL; case 0x39: /* RETURN */ case 0x3b: /* FLUSH */ if (RD(inst)) { ILLEGAL; } (void)printf("%p:\t%s\t%s + ", (void *)pc, opc[op3], sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%ld\n", SIMM13(inst)); else (void)printf("%s\n", sregs[RS2(inst)]); return OK; case 0x19: case 0x1d: case 0x29: case 0x33: case 0x3f: ILLEGAL; case 0x25: /* SLL/SLLX */ case 0x26: /* SRL/SRLX */ case 0x27: /* SRA/SRAX */ (void)printf("%p:\t%s%s\t%s, ", (void *)pc, opc[op3], X(inst) ? "x" : "", sregs[RS1(inst)]); if (IMM(inst)) (void)printf("%d, ", X(inst) ? SHIFT64(inst) : SHIFT32(inst)); else (void)printf("%s, ", sregs[RS2(inst)]); (void)printf("%s\n", sregs[RD(inst)]); return OK; case 0x28: /* RDASR */ return dis_rdasr(pc, inst); case 0x2a: /* RDPR */ return dis_rdpr(pc, inst); case 0x30: /* WRASR */ return dis_wrasr(pc, inst); case 0x31: /* SAVED/RESTORED */ if(FCN(inst) == 0) { (void)printf("%p:\tsaved\n", (void *)pc); return OK; } if(FCN(inst) == 1) { (void)printf("%p:\trestored\n", (void *)pc); return OK; } ILLEGAL; case 0x32: /* WRPR */ return dis_wrpr(pc, inst); case 0x3a: /* Tcc */ return dis_tcc(pc, inst); case 0x3e: /* DONE/RETRY */ if(FCN(inst) == 0) { (void)printf("%p:\tdone\n", (void *)pc); return OK; } if(FCN(inst) == 1) { (void)printf("%p:\tretry\n", (void *)pc); return OK; } ILLEGAL; case 0x36: /* IMPDEP1 */ (void)printf("XXXX %p:\timpldep1\n", (void *)pc ); return ERR; case 0x37: /* IMPLDEP2 */ (void)printf("XXXX %p:\timpldep2\n", (void *)pc); return ERR; default: (void)printf("XXXX dis_class2 op3=%x\n", op3); return ERR; } }
void findcalls(nltype *parentp, pctype p_lowpc, pctype p_highpc) { unsigned long instructp; sztype length; nltype *childp; pctype destpc; if (textspace == 0) { return; } if (p_lowpc > s_highpc) return; if (p_highpc < s_lowpc) return; if (p_lowpc < s_lowpc) p_lowpc = s_lowpc; if (p_highpc > s_highpc) p_highpc = s_highpc; #ifdef DEBUG if (debug & CALLSDEBUG) { printf("[findcalls] %s: 0x%llx to 0x%llx\n", parentp->name, p_lowpc, p_highpc); } #endif /* DEBUG */ length = 4; for (instructp = (uintptr_t)textspace + p_lowpc - TORIGIN; instructp < (uintptr_t)textspace + p_highpc - TORIGIN; instructp += length) { switch (OP(instructp)) { case CALL: /* * May be a call, better check it out. */ #ifdef DEBUG if (debug & CALLSDEBUG) { printf("[findcalls]\t0x%x:call\n", PC_VAL(instructp)); } #endif /* DEBUG */ destpc = (DISP30(instructp) << 2) + PC_VAL(instructp); break; case FMT3_0x10: if (OP3(instructp) != JMPL) continue; #ifdef DEBUG if (debug & CALLSDEBUG) printf("[findcalls]\t0x%x:jmpl", PC_VAL(instructp)); #endif /* DEBUG */ if (RD(instructp) == R_G0) { #ifdef DEBUG if (debug & CALLSDEBUG) { switch (RS1(instructp)) { case R_O7: printf("\tprobably a RETL\n"); break; case R_I7: printf("\tprobably a RET\n"); break; default: printf(", but not a call: " "linked to g0\n"); } } #endif /* DEBUG */ continue; } #ifdef DEBUG if (debug & CALLSDEBUG) { printf("\toperands are DST = R%d,\tSRC = R%d", RD(instructp), RS1(instructp)); } #endif /* DEBUG */ if (IMMED(instructp)) { #ifdef DEBUG if (debug & CALLSDEBUG) { if (SIMM13(instructp) < 0) { printf(" - 0x%x\n", -(SIMM13(instructp))); } else { printf(" + 0x%x\n", SIMM13(instructp)); } } #endif /* DEBUG */ switch (RS1(instructp)) { case R_G0: /* * absolute address, simm 13 */ destpc = SIMM13(instructp); break; default: /* * indirect call */ addarc(parentp, &indirectchild, 0); continue; } } else { /* * two register sources, all cases are indirect */ #ifdef DEBUG if (debug & CALLSDEBUG) { printf(" + R%d\n", RS2(instructp)); } #endif /* DEBUG */ addarc(parentp, &indirectchild, 0); continue; } break; default: continue; } /* * Check that the destination is the address of * a function; this allows us to differentiate * real calls from someone trying to get the PC, * e.g. position independent switches. */ if (destpc >= s_lowpc && destpc <= s_highpc) { childp = nllookup(&modules, destpc, NULL); #ifdef DEBUG if (debug & CALLSDEBUG) { printf("[findcalls]\tdestpc 0x%llx", destpc); printf(" childp->name %s", childp->name); printf(" childp->value 0x%llx\n", childp->value); } #endif /* DEBUG */ if (childp->value == destpc) { /* * a hit */ addarc(parentp, childp, 0); continue; } } /* * else: * it looked like a call, * but it wasn't to anywhere. */ #ifdef DEBUG if (debug & CALLSDEBUG) { printf("[findcalls]\tbut it's a switch or a botch\n"); } #endif /* DEBUG */ continue; } }
* The assembler requires that all instances of the same mnemonic must be consecutive. If they aren't, the assembler will bomb at runtime. * The disassembler should not care about the order of the opcodes. */ struct sparc_opcode sparc_opcodes[] = { { "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", 0, v6 }, { "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", 0, v6 }, /* ld [rs1+%g0],d */ { "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", 0, v6 }, { "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", 0, v6 }, { "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", 0, v6 }, { "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ld [rs1+0],d */ { "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0), "[1+2],g", 0, v6 }, { "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0)|RS2_G0, "[1],g", 0, v6 }, /* ld [rs1+%g0],d */ { "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[1+i],g", 0, v6 }, { "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[i+1],g", 0, v6 }, { "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|RS1_G0, "[i],g", 0, v6 }, { "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ld [rs1+0],d */ { "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RD(~0), "[1+2],F", 0, v6 }, { "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RS2_G0|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+%g0],d */ { "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[1+i],F", 0, v6 }, { "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[i+1],F", 0, v6 }, { "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~0),"[i],F", 0, v6 }, { "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+0],d */ { "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2],D", F_ALIAS, v6 },