ArgUnion getImm(PC const origPC, int idx, const Unit* unit) { auto pc = origPC; auto const UNUSED op = decode_op(pc); assert(idx >= 0 && idx < numImmediates(op)); ArgUnion retval; retval.u_NA = 0; int cursor = 0; for (cursor = 0; cursor < idx; cursor++) { // Advance over this immediate. pc += immSize(origPC, cursor); } always_assert(cursor == idx); auto const type = immType(op, idx); if (type == IVA || type == LA || type == IA) { retval.u_IVA = decodeVariableSizeImm(&pc); } else if (type == KA) { assert(unit != nullptr); retval.u_KA = decode_member_key(pc, unit); } else if (!immIsVector(op, cursor)) { always_assert(type != RATA); // Decode RATAs with a different function. memcpy(&retval.bytes, pc, immSize(origPC, idx)); } always_assert(numImmediates(op) > idx); return retval; }
ArgUnion getImm(const PC origPC, int idx, const Unit* unit) { auto pc = origPC; auto const op = decode_op(pc); assertx(idx >= 0 && idx < numImmediates(op)); ArgUnion retval; retval.u_NA = 0; int cursor = 0; for (cursor = 0; cursor < idx; cursor++) { // Advance over this immediate. pc += immSize(immType(op, cursor), pc); } always_assert(cursor == idx); auto const type = immType(op, idx); if (type == IVA || type == LA || type == IA || type == CAR || type == CAW) { retval.u_IVA = decode_iva(pc); } else if (type == KA) { assertx(unit != nullptr); retval.u_KA = decode_member_key(pc, unit); } else if (type == LAR) { retval.u_LAR = decodeLocalRange(pc); } else if (type == FCA) { retval.u_FCA = decodeFCallArgs(pc); } else if (type == RATA) { assertx(unit != nullptr); retval.u_RATA = decodeRAT(unit, pc); } else if (!argTypeIsVector(type)) { memcpy(&retval.bytes, pc, immSize(type, pc)); } always_assert(numImmediates(op) > idx); return retval; }
offs_t lc8670_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { int pos = 0; char arg1[16], arg2[16]; UINT8 op = oprom[pos++]; int op_idx = decode_op(op); const dasm_entry *inst = &s_dasm_table[op_idx]; buffer += sprintf(buffer,"%-8s", inst->str); dasm_arg(op, inst->inv ? arg2 : arg1, pc+0, inst->arg1, oprom, pos); dasm_arg(op, inst->inv ? arg1 : arg2, pc+1, inst->arg2, oprom, pos); strcat(buffer, arg1); if (inst->arg2 != OP_NULL) { strcat(buffer, ","); strcat(buffer, arg2); } return pos; }
int instrLen(PC const origPC) { auto pc = origPC; auto op = decode_op(pc); int nImm = numImmediates(op); for (int i = 0; i < nImm; i++) { pc += immSize(origPC, i); } return pc - origPC; }
void decode_and_print_code( RW_Robo_Op *code, size_t length ) { size_t i; int opcode, reg1, reg2, reg3, imme; printf("Generated code:\n"); for( i = 0; i < length; i++ ) { printf("%d: ", (int)i); decode_op(code[i], opcode, reg1, reg2, reg3, imme); switch( opcode ) { case op_nop: case op_ne: case op_eq: case op_lt: case op_gt: case op_add: case op_sub: case op_mul: case op_div: case op_mod: case op_and: case op_or: case op_xor: case op_max: case op_min: case op_dist: case op_sin: case op_cos: case op_tan: case op_arcsin: case op_arccos: case op_arctan: print_code_3reg(opcode, reg1, reg2, reg3); break; case op_two_reg: print_code_2reg(reg3, reg1, reg2); break; case op_one_reg: print_code_1reg(reg3, reg1); break; case op_zero_reg: print_code_0reg(reg3); break; case op_call: case op_jump: case op_mova: case op_movb: case op_push: print_code_immed(opcode, imme); break; default: printf("BAD OPERATOR\n"); break; } } }
ArgUnion* getImmPtr(PC const origPC, int idx) { auto pc = origPC; auto const UNUSED op = decode_op(pc); assert(immType(op, idx) != IVA); assert(immType(op, idx) != LA); assert(immType(op, idx) != IA); assert(immType(op, idx) != RATA); for (int i = 0; i < idx; i++) { pc += immSize(origPC, i); } return (ArgUnion*)pc; }
// Await / Yield opcodes mark a suspend points of async functions and // generators. Execution will resume at this function later after the // opcode. void CmdNext::setupStepSuspend(ActRec* fp, PC pc) { // Yield is followed by the label where execution will continue. auto const op = decode_op(pc); assertx(op == OpAwait || op == OpYield || op == OpYieldK); if (op == OpAwait) { decode_iva(pc); } Offset nextInst = fp->func()->unit()->offsetOf(pc); assertx(nextInst != InvalidAbsoluteOffset); m_stepResumableId = fp; TRACE(2, "CmdNext: patch for resumable step at '%s' offset %d\n", fp->m_func->fullName()->data(), nextInst); m_stepResumable = StepDestination(fp->m_func->unit(), nextInst); }
ArgUnion* getImmPtr(const PC origPC, int idx) { auto pc = origPC; auto const op = decode_op(pc); assertx(immType(op, idx) != IVA); assertx(immType(op, idx) != LA); assertx(immType(op, idx) != IA); assertx(immType(op, idx) != CAR); assertx(immType(op, idx) != CAW); assertx(immType(op, idx) != RATA); for (int i = 0; i < idx; i++) { pc += immSize(immType(op, i), pc); } return (ArgUnion*)pc; }
/** * Return the number of successor-edges including fall-through paths but not * implicit exception paths. */ int numSuccs(PC const origPC) { auto pc = origPC; auto const op = decode_op(pc); if ((instrFlags(op) & TF) != 0) { if (isSwitch(op)) { return decode_raw<int32_t>(pc); } if (isUnconditionalJmp(op) || op == OpIterBreak) return 1; return 0; } if (!instrIsControlFlow(op)) return 1; if (instrJumpOffset(origPC)) return 2; return 1; }
/** * Return the number of successor-edges including fall-through paths but not * implicit exception paths. */ int numSuccs(PC const origPC) { auto pc = origPC; auto const op = decode_op(pc); if ((instrFlags(op) & TF) != 0) { if (isSwitch(op)) { if (op == Op::Switch) { decode_raw<SwitchKind>(pc); // skip bounded flag decode_raw<int64_t>(pc); // skip base } return decode_raw<int32_t>(pc); // vector length } if (isUnconditionalJmp(op) || op == OpIterBreak) return 1; return 0; } if (!instrIsControlFlow(op)) return 1; if (instrJumpOffset(origPC)) return 2; return 1; }
void test_instr_encoding() { RW_Robo_Op op; int opcode, reg1, reg2, reg3, imme; encode_op_regs(op, op_add, 1, 2, 3); decode_op(op, opcode, reg1, reg2, reg3, imme); if( opcode != op_add ) { printf("opcode encoding/decoding error\n"); } if( reg1 != 1 ) { printf("reg1 encoding/decoding error\n"); } if( reg2 != 2 ) { printf("reg2 encoding/decoding error\n"); } if( reg3 != 3 ) { printf("reg3 encoding/decoding error\n"); } }
int main(int argc, char ** argv) { char * operation = argv[1]; unsigned int size; unsigned short i, byte, key, op; if (argc != 4) usage(), exit(1); if (!strcmp(operation, "add")) { op = ADD; } else if (!strcmp(operation, "sub")) { op = SUB; } else if (!strcmp(operation, "xor")) { op = XOR; } else usage(), exit(1); key = atoi(argv[2]); size = strlen(argv[3]); printf("shellcode %s 0x%.2x encoded:\n", argv[1], key); printf("\""); printf( //_start: "\\xeb\\x0d" // jmp encoded //decoder: "\\x5e" // pop %esi "\\x6a\\x%.2x" // push $size "\\x5f" // pop %edx //decoder_loop: "\\x83\\x%.2x\\x3e\\x%.2x" // inst $key,(%esi,%edx,1) "\\x4f" // dec %edx "\\x75\\xf9" // jne decoder_loop "\\xeb\\x05" // jmp shellcode //encoded: "\\xe8\\xee\\xff\\xff\\xff", // call decoder //shellcode: size, decode_op(op), key); for(i = 0; i < size; i++) { byte = (argv[3][i] & 0xff); printf("\\x%.2x", calc(op, byte, key)); } puts("\""); return 0; }
void lc8670_cpu_device::execute_run() { if (m_clock_changed) { change_clock_source(); return; } do { check_irqs(); debugger_instruction_hook(this, m_pc); int cycles = 0; m_ppc = m_pc; if (REG_PCON & HALT_MODE) { // in HALT state the timers are still updated cycles = 1; } else { // instruction fetch m_op = fetch(); int op_idx = decode_op(m_op); // execute the instruction cycles = (this->*s_opcode_table[op_idx])(); } // update the instruction counter m_icount -= cycles; } while (m_icount > 0 && !m_clock_changed); }
Offset* instrJumpOffset(const PC origPC) { static const int8_t jumpMask[] = { #define IMM_NA 0 #define IMM_IVA 0 #define IMM_I64A 0 #define IMM_DA 0 #define IMM_SA 0 #define IMM_AA 0 #define IMM_RATA 0 #define IMM_BA 1 #define IMM_BLA 0 // these are jump offsets, but must be handled specially #define IMM_ILA 0 #define IMM_I32LA 0 #define IMM_BLLA 0 #define IMM_SLA 0 #define IMM_LA 0 #define IMM_IA 0 #define IMM_CAR 0 #define IMM_CAW 0 #define IMM_OA(x) 0 #define IMM_VSA 0 #define IMM_KA 0 #define IMM_LAR 0 #define IMM_FCA 0 #define ONE(a) IMM_##a #define TWO(a, b) (IMM_##a + 2 * IMM_##b) #define THREE(a, b, c) (IMM_##a + 2 * IMM_##b + 4 * IMM_##c) #define FOUR(a, b, c, d) (IMM_##a + 2 * IMM_##b + 4 * IMM_##c + 8 * IMM_##d) #define FIVE(a, b, c, d, e) (IMM_##a + 2 * IMM_##b + 4 * IMM_##c + 8 * IMM_##d + 16 * IMM_##e) #define O(name, imm, pop, push, flags) imm, OPCODES #undef IMM_NA #undef IMM_IVA #undef IMM_I64A #undef IMM_DA #undef IMM_SA #undef IMM_AA #undef IMM_RATA #undef IMM_LA #undef IMM_IA #undef IMM_CAR #undef IMM_CAW #undef IMM_BA #undef IMM_BLA #undef IMM_ILA #undef IMM_I32LA #undef IMM_BLLA #undef IMM_SLA #undef IMM_OA #undef IMM_VSA #undef IMM_KA #undef IMM_LAR #undef IMM_FCA #undef ONE #undef TWO #undef THREE #undef FOUR #undef FIVE #undef O }; auto pc = origPC; auto const op = decode_op(pc); assertx(!isSwitch(op)); // BLA doesn't work here if (op == OpIterBreak) { // offset is imm number 0 return const_cast<Offset*>(reinterpret_cast<const Offset*>(pc)); } int mask = jumpMask[size_t(op)]; if (mask == 0) { return nullptr; } int immNum; switch (mask) { case 0: return nullptr; case 1: immNum = 0; break; case 2: immNum = 1; break; case 4: immNum = 2; break; case 8: immNum = 3; break; case 16: immNum = 4; break; default: assertx(false); return nullptr; } return &getImmPtr(origPC, immNum)->u_BA; }
std::string instrToString(PC it, Either<const Unit*, const UnitEmitter*> u) { std::stringstream out; PC iStart = it; Op op = decode_op(it); auto readRATA = [&] { if (auto unit = u.left()) { auto const rat = decodeRAT(unit, it); out << ' ' << show(rat); return; } auto const pc = it; it += encodedRATSize(pc); out << " <RepoAuthType>"; }; auto offsetOf = [u](PC pc) { return u.match( [pc](const Unit* u) { return u->offsetOf(pc); }, [pc](const UnitEmitter* ue) { return ue->offsetOf(pc); } ); }; auto lookupLitstrId = [u](Id id) { return u.match( [id](const Unit* u) { return u->lookupLitstrId(id); }, [id](const UnitEmitter* ue) { return ue->lookupLitstr(id); } ); }; auto lookupArrayId = [u](Id id) { return u.match( [id](const Unit* u) { return u->lookupArrayId(id); }, [id](const UnitEmitter* ue) { return ue->lookupArray(id); } ); }; switch (op) { #define READ(t) out << " " << *((t*)&*it); it += sizeof(t) #define READOFF() do { \ Offset _value = *(Offset*)it; \ out << " " << _value; \ if (u != nullptr) { \ out << " (" << offsetOf(iStart + _value) << ")"; \ } \ it += sizeof(Offset); \ } while (false) #define READV() out << " " << decodeVariableSizeImm(&it); #define READLA() out << " L:" << decodeVariableSizeImm(&it); #define READIVA() do { \ out << " "; \ auto imm = decodeVariableSizeImm((const uint8_t**)&it); \ if (op == OpIncStat && immIdx == 0) { \ out << Stats::g_counterNames[imm]; \ } else { \ out << imm; \ } \ immIdx++; \ } while (false) #define READOA(type) do { \ auto const immVal = static_cast<type>( \ *reinterpret_cast<const uint8_t*>(it) \ ); \ it += sizeof(unsigned char); \ out << " " << subopToName(immVal); \ } while (false) #define READLITSTR(sep) do { \ Id id = decode_raw<Id>(it); \ if (id < 0) { \ assert(op == OpSSwitch); \ out << sep << "-"; \ } else { \ auto const sd = lookupLitstrId(id); \ out << sep << "\"" << \ escapeStringForCPP(sd->data(), sd->size()) << "\""; \ } \ } while (false) #define READSVEC() do { \ int sz = decode_raw<int>(it); \ out << " <"; \ const char* sep = ""; \ for (int i = 0; i < sz; ++i) { \ out << sep; \ if (op == OpSSwitch) { \ READLITSTR(""); \ out << ":"; \ } \ Offset o = decode_raw<Offset>(it); \ out << offsetOf(iStart + o); \ sep = " "; \ } \ out << ">"; \ } while (false) #define READIVEC() do { \ int sz = decode_raw<int>(it); \ out << " <"; \ const char* sep = ""; \ for (int i = 0; i < sz; ++i) { \ out << sep; \ IterKind k = (IterKind)decode_raw<Id>(it); \ switch(k) { \ case KindOfIter: out << "(Iter) "; break; \ case KindOfMIter: out << "(MIter) "; break; \ case KindOfCIter: out << "(CIter) "; break; \ } \ out << decode_raw<Id>(it); \ sep = ", "; \ } \ out << ">"; \ } while (false) #define ONE(a) H_##a #define TWO(a, b) H_##a; H_##b #define THREE(a, b, c) H_##a; H_##b; H_##c; #define FOUR(a, b, c, d) H_##a; H_##b; H_##c; H_##d; #define NA #define H_BLA READSVEC() #define H_SLA READSVEC() #define H_ILA READIVEC() #define H_IVA READIVA() #define H_I64A READ(int64_t) #define H_LA READLA() #define H_IA READV() #define H_DA READ(double) #define H_BA READOFF() #define H_OA(type) READOA(type) #define H_SA READLITSTR(" ") #define H_RATA readRATA() #define H_AA do { \ out << ' '; \ staticArrayStreamer(lookupArrayId(decode_raw<Id>(it)), out); \ } while (false) #define H_VSA do { \ int sz = decode_raw<int32_t>(it); \ out << " <"; \ for (int i = 0; i < sz; ++i) { \ H_SA; \ } \ out << " >"; \ } while (false) #define H_KA out << ' ' << show(decode_member_key(it, u)) #define O(name, imm, push, pop, flags) \ case Op##name: { \ out << #name; \ UNUSED unsigned immIdx = 0; \ imm; \ break; \ } OPCODES #undef O #undef READ #undef READV #undef READLA #undef ONE #undef TWO #undef THREE #undef FOUR #undef NA #undef H_BLA #undef H_SLA #undef H_ILA #undef H_IVA #undef H_I64A #undef H_LA #undef H_IA #undef H_DA #undef H_BA #undef H_OA #undef H_SA #undef H_AA #undef H_VSA #undef H_KA default: assert(false); }; return out.str(); }
Offset* instrJumpOffset(PC const origPC) { static const int8_t jumpMask[] = { #define IMM_NA 0 #define IMM_IVA 0 #define IMM_I64A 0 #define IMM_DA 0 #define IMM_SA 0 #define IMM_AA 0 #define IMM_RATA 0 #define IMM_BA 1 #define IMM_BLA 0 // these are jump offsets, but must be handled specially #define IMM_ILA 0 #define IMM_SLA 0 #define IMM_LA 0 #define IMM_IA 0 #define IMM_OA(x) 0 #define IMM_VSA 0 #define IMM_KA 0 #define ONE(a) IMM_##a #define TWO(a, b) (IMM_##a + 2 * IMM_##b) #define THREE(a, b, c) (IMM_##a + 2 * IMM_##b + 4 * IMM_##c) #define FOUR(a, b, c, d) (IMM_##a + 2 * IMM_##b + 4 * IMM_##c + 8 * IMM_##d) #define O(name, imm, pop, push, flags) imm, OPCODES #undef IMM_NA #undef IMM_IVA #undef IMM_I64A #undef IMM_DA #undef IMM_SA #undef IMM_AA #undef IMM_RATA #undef IMM_LA #undef IMM_IA #undef IMM_BA #undef IMM_BLA #undef IMM_ILA #undef IMM_SLA #undef IMM_OA #undef IMM_VSA #undef IMM_KA #undef ONE #undef TWO #undef THREE #undef FOUR #undef O }; auto pc = origPC; auto const op = decode_op(pc); assert(!isSwitch(op)); // BLA doesn't work here if (op == OpIterBreak) { auto const veclen = decode_raw<uint32_t>(pc); assert(veclen > 0); auto const target = const_cast<Offset*>( reinterpret_cast<const Offset*>( reinterpret_cast<const uint32_t*>(pc) + 2 * veclen ) ); return target; } int mask = jumpMask[size_t(op)]; if (mask == 0) { return nullptr; } int immNum; switch (mask) { case 0: return nullptr; case 1: immNum = 0; break; case 2: immNum = 1; break; case 4: immNum = 2; break; case 8: immNum = 3; break; default: assert(false); return nullptr; } return &getImmPtr(origPC, immNum)->u_BA; }
std::string instrToString(PC it, Either<const Unit*, const UnitEmitter*> u) { std::string out; PC iStart = it; Op op = decode_op(it); auto readRATA = [&] { if (auto unit = u.left()) { auto const rat = decodeRAT(unit, it); folly::format(&out, " {}", show(rat)); return; } auto const pc = it; it += encodedRATSize(pc); out += " <RepoAuthType>"; }; auto offsetOf = [u](PC pc) { return u.match( [pc](const Unit* u) { return u->offsetOf(pc); }, [pc](const UnitEmitter* ue) { return ue->offsetOf(pc); } ); }; auto lookupLitstrId = [u](Id id) { return u.match( [id](const Unit* u) { return u->lookupLitstrId(id); }, [id](const UnitEmitter* ue) { return ue->lookupLitstr(id); } ); }; auto lookupArrayId = [u](Id id) { return u.match( [id](const Unit* u) { return u->lookupArrayId(id); }, [id](const UnitEmitter* ue) { return ue->lookupArray(id); } ); }; switch (op) { #define READ(t) folly::format(&out, " {}", *((t*)&*it)); it += sizeof(t) #define READOFF() do { \ Offset _value = *(Offset*)it; \ folly::format(&out, " {}", _value); \ if (u != nullptr) { \ folly::format(&out, " ({})", offsetOf(iStart + _value)); \ } \ it += sizeof(Offset); \ } while (false) #define READV() folly::format(&out, " {}", decode_iva(it)); #define READLA() folly::format(&out, " L:{}", decode_iva(it)); #define READIVA() do { \ auto imm = decode_iva(it); \ folly::format(&out, " {}", imm); \ immIdx++; \ } while (false) #define READOA(type) do { \ auto const immVal = static_cast<type>( \ *reinterpret_cast<const uint8_t*>(it) \ ); \ it += sizeof(unsigned char); \ folly::format(&out, " {}", subopToName(immVal)); \ } while (false) #define READLITSTR(sep) do { \ Id id = decode_raw<Id>(it); \ if (id < 0) { \ assertx(op == OpSSwitch); \ folly::format(&out, "{}-", sep); \ } else { \ auto const sd = lookupLitstrId(id); \ folly::format(&out, "{}\"{}\"", sep, \ escapeStringForCPP(sd->data(), sd->size())); \ } \ } while (false) #define READSVEC() do { \ int sz = decode_iva(it); \ out += " <"; \ const char* sep = ""; \ for (int i = 0; i < sz; ++i) { \ out += sep; \ if (op == OpSSwitch) { \ READLITSTR(""); \ out += ":"; \ } \ Offset o = decode_raw<Offset>(it); \ folly::format(&out, "{}", offsetOf(iStart + o)); \ sep = " "; \ } \ out += ">"; \ } while (false) #define READI32VEC() do { \ int sz = decode_iva(it); \ out += " <"; \ const char* sep = ""; \ for (int i = 0; i < sz; ++i) { \ folly::format(&out, "{}{}", sep, decode_raw<uint32_t>(it));\ sep = ", "; \ } \ out += ">"; \ } while (false) #define READBOOLVEC() do { \ int sz = decode_iva(it); \ uint8_t tmp = 0; \ out += " \""; \ for (int i = 0; i < sz; ++i) { \ if (i % 8 == 0) tmp = decode_raw<uint8_t>(it); \ out += ((tmp >> (i % 8)) & 1) ? "1" : "0"; \ } \ out += "\""; \ } while (false) #define READITERTAB() do { \ auto const sz = decode_iva(it); \ out += " <"; \ const char* sep = ""; \ for (int i = 0; i < sz; ++i) { \ out += sep; \ auto const k = (IterKind)decode_iva(it); \ switch (k) { \ case KindOfIter: out += "(Iter) "; break; \ case KindOfMIter: out += "(MIter) "; break; \ case KindOfCIter: out += "(CIter) "; break; \ case KindOfLIter: out += "(LIter) "; break; \ } \ folly::format(&out, "{}", decode_iva(it)); \ if (k == KindOfLIter) { \ folly::format(&out, " L:{}", decode_iva(it)); \ } \ sep = ", "; \ } \ out += ">"; \ } while (false) #define ONE(a) H_##a #define TWO(a, b) H_##a; H_##b #define THREE(a, b, c) H_##a; H_##b; H_##c; #define FOUR(a, b, c, d) H_##a; H_##b; H_##c; H_##d; #define FIVE(a, b, c, d, e) H_##a; H_##b; H_##c; H_##d; H_##e; #define NA #define H_BLA READSVEC() #define H_SLA READSVEC() #define H_ILA READITERTAB() #define H_I32LA READI32VEC() #define H_BLLA READBOOLVEC() #define H_IVA READIVA() #define H_I64A READ(int64_t) #define H_LA READLA() #define H_IA READV() #define H_CAR READV() #define H_CAW READV() #define H_DA READ(double) #define H_BA READOFF() #define H_OA(type) READOA(type) #define H_SA READLITSTR(" ") #define H_RATA readRATA() #define H_AA do { \ out += ' '; \ staticArrayStreamer(lookupArrayId(decode_raw<Id>(it)), out); \ } while (false) #define H_VSA do { \ int sz = decode_iva(it); \ out += " <"; \ for (int i = 0; i < sz; ++i) { \ H_SA; \ } \ out += " >"; \ } while (false) #define H_KA (out += ' ', out += show(decode_member_key(it, u))) #define H_LAR (out += ' ', out += show(decodeLocalRange(it))) #define H_FCA (out += ' ', out += show(decodeFCallArgs(it))) #define O(name, imm, push, pop, flags) \ case Op##name: { \ out += #name; \ UNUSED unsigned immIdx = 0; \ imm; \ break; \ } OPCODES #undef O #undef READ #undef READV #undef READLA #undef ONE #undef TWO #undef THREE #undef FOUR #undef FIVE #undef NA #undef H_BLA #undef H_SLA #undef H_ILA #undef H_I32LA #undef H_BLLA #undef H_IVA #undef H_I64A #undef H_LA #undef H_IA #undef H_CAR #undef H_CAW #undef H_DA #undef H_BA #undef H_OA #undef H_SA #undef H_AA #undef H_VSA #undef H_KA #undef H_LAR #undef H_FCA default: assertx(false); }; return out; }
int immSize(PC origPC, int idx) { auto pc = origPC; auto const op = decode_op(pc); assert(idx >= 0 && idx < numImmediates(op)); always_assert(idx < 4); // No origPCs have more than four immediates static const int8_t argTypeToSizes[] = { #define ARGTYPE(nm, type) sizeof(type), #define ARGTYPEVEC(nm, type) 0, ARGTYPES #undef ARGTYPE #undef ARGTYPEVEC }; if (immType(op, idx) == IVA || immType(op, idx) == LA || immType(op, idx) == IA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); auto const imm = decode_raw<uint8_t>(pc); // Low order bit set => 4-byte. return (imm & 0x1 ? sizeof(int32_t) : sizeof(unsigned char)); } if (immType(op, idx) == RATA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); return encodedRATSize(pc); } if (immIsVector(op, idx)) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); int prefixes, vecElemSz; auto itype = immType(op, idx); if (itype == MA) { prefixes = 2; vecElemSz = sizeof(uint8_t); } else if (itype == BLA) { prefixes = 1; vecElemSz = sizeof(Offset); } else if (itype == ILA) { prefixes = 1; vecElemSz = 2 * sizeof(uint32_t); } else if (itype == VSA) { prefixes = 1; vecElemSz = sizeof(Id); } else { assert(itype == SLA); prefixes = 1; vecElemSz = sizeof(StrVecItem); } return prefixes * sizeof(int32_t) + vecElemSz * decode_raw<int32_t>(pc); } ArgType type = immType(op, idx); return (type >= 0) ? argTypeToSizes[type] : 0; }
std::string instrToString(PC it, const Unit* u /* = NULL */) { std::stringstream out; PC iStart = it; Op op = decode_op(it); auto readRATA = [&] { if (!u) { auto const pc = it; it += encodedRATSize(pc); out << " <RepoAuthType>"; return; } auto const rat = decodeRAT(u, it); out << ' ' << show(rat); }; switch (op) { #define READ(t) out << " " << *((t*)&*it); it += sizeof(t) #define READOFF() do { \ Offset _value = *(Offset*)it; \ out << " " << _value; \ if (u != nullptr) { \ out << " (" << u->offsetOf(iStart + _value) << ")"; \ } \ it += sizeof(Offset); \ } while (false) #define READV() out << " " << decodeVariableSizeImm(&it); #define READLA() out << " L:" << decodeVariableSizeImm(&it); #define READIVA() do { \ out << " "; \ auto imm = decodeVariableSizeImm((const uint8_t**)&it); \ if (op == OpIncStat && immIdx == 0) { \ out << Stats::g_counterNames[imm]; \ } else { \ out << imm; \ } \ immIdx++; \ } while (false) #define READOA(type) do { \ auto const immVal = static_cast<type>( \ *reinterpret_cast<const uint8_t*>(it) \ ); \ it += sizeof(unsigned char); \ out << " " << subopToName(immVal); \ } while (false) #define READVEC() do { \ int sz = *((int*)&*it); \ it += sizeof(int) * 2; \ const uint8_t* const start = (uint8_t*)it; \ out << " <"; \ if (sz > 0) { \ int immVal = (int)*((unsigned char*)&*it); \ out << ((immVal >= 0 && size_t(immVal) < locationNamesCount) ? \ locationCodeString(LocationCode(immVal)) : "?"); \ it += sizeof(unsigned char); \ int numLocImms = numLocationCodeImms(LocationCode(immVal)); \ for (int i = 0; i < numLocImms; ++i) { \ out << ':' << decodeVariableSizeImm((const uint8_t**)&it); \ } \ while (reinterpret_cast<const uint8_t*>(it) - start < sz) { \ immVal = (int)*((unsigned char*)&*it); \ out << " " << ((immVal >=0 && size_t(immVal) < memberNamesCount) ? \ memberCodeString(MemberCode(immVal)) : "?"); \ it += sizeof(unsigned char); \ if (memberCodeHasImm(MemberCode(immVal))) { \ int64_t imm = decodeMemberCodeImm((const uint8_t**)&it, \ MemberCode(immVal)); \ out << ':'; \ if (memberCodeImmIsString(MemberCode(immVal)) && u) { \ const StringData* str = u->lookupLitstrId(imm); \ int len = str->size(); \ String escaped = string_addslashes(str->data(), len); \ out << '"' << escaped.data() << '"'; \ } else { \ out << imm; \ } \ } \ } \ assert(reinterpret_cast<const uint8_t*>(it) - start == sz); \ } \ out << ">"; \ } while (false) #define READLITSTR(sep) do { \ Id id = decode_raw<Id>(it); \ if (id < 0) { \ assert(op == OpSSwitch); \ out << sep << "-"; \ } else if (u) { \ const StringData* sd = u->lookupLitstrId(id); \ out << sep << "\"" << \ escapeStringForCPP(sd->data(), sd->size()) << "\""; \ } else { \ out << sep << id; \ } \ } while (false) #define READSVEC() do { \ int sz = decode_raw<int>(it); \ out << " <"; \ const char* sep = ""; \ for (int i = 0; i < sz; ++i) { \ out << sep; \ if (op == OpSSwitch) { \ READLITSTR(""); \ out << ":"; \ } \ Offset o = decode_raw<Offset>(it); \ if (u != nullptr) { \ if (iStart + o == u->entry() - 1) { \ out << "Invalid"; \ } else { \ out << u->offsetOf(iStart + o); \ } \ } else { \ out << o; \ } \ sep = " "; \ } \ out << ">"; \ } while (false) #define READIVEC() do { \ int sz = decode_raw<int>(it); \ out << " <"; \ const char* sep = ""; \ for (int i = 0; i < sz; ++i) { \ out << sep; \ IterKind k = (IterKind)decode_raw<Id>(it); \ switch(k) { \ case KindOfIter: out << "(Iter) "; break; \ case KindOfMIter: out << "(MIter) "; break; \ case KindOfCIter: out << "(CIter) "; break; \ } \ out << decode_raw<Id>(it); \ sep = ", "; \ } \ out << ">"; \ } while (false) #define ONE(a) H_##a #define TWO(a, b) H_##a; H_##b #define THREE(a, b, c) H_##a; H_##b; H_##c; #define FOUR(a, b, c, d) H_##a; H_##b; H_##c; H_##d; #define NA #define H_MA READVEC() #define H_BLA READSVEC() #define H_SLA READSVEC() #define H_ILA READIVEC() #define H_IVA READIVA() #define H_I64A READ(int64_t) #define H_LA READLA() #define H_IA READV() #define H_DA READ(double) #define H_BA READOFF() #define H_OA(type) READOA(type) #define H_SA READLITSTR(" ") #define H_RATA readRATA() #define H_AA \ if (u) { \ out << " "; \ staticArrayStreamer(u->lookupArrayId(*((Id*)it)), out); \ } else { \ out << " " << *((Id*)it); \ } \ it += sizeof(Id) #define H_VSA do { \ int sz = decode_raw<int32_t>(it); \ out << " <"; \ for (int i = 0; i < sz; ++i) { \ H_SA; \ } \ out << " >"; \ } while (false) #define O(name, imm, push, pop, flags) \ case Op##name: { \ out << #name; \ UNUSED unsigned immIdx = 0; \ imm; \ break; \ } OPCODES #undef O #undef READ #undef READV #undef READLA #undef ONE #undef TWO #undef THREE #undef FOUR #undef NA #undef H_MA #undef H_BLA #undef H_SLA #undef H_ILA #undef H_IVA #undef H_I64A #undef H_LA #undef H_IA #undef H_DA #undef H_BA #undef H_OA #undef H_SA #undef H_AA #undef H_VSA default: assert(false); }; return out.str(); }
int immSize(PC origPC, int idx) { auto pc = origPC; auto const op = decode_op(pc); assert(idx >= 0 && idx < numImmediates(op)); always_assert(idx < 4); // No origPCs have more than four immediates static const int8_t argTypeToSizes[] = { #define ARGTYPE(nm, type) sizeof(type), #define ARGTYPEVEC(nm, type) 0, ARGTYPES #undef ARGTYPE #undef ARGTYPEVEC }; if (immType(op, idx) == IVA || immType(op, idx) == LA || immType(op, idx) == IA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); return encoded_iva_size(decode_raw<uint8_t>(pc)); } if (immType(op, idx) == KA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); switch (decode_raw<MemberCode>(pc)) { case MW: return 1; case MEL: case MPL: case MEC: case MPC: return 1 + encoded_iva_size(decode_raw<uint8_t>(pc)); case MEI: return 1 + sizeof(int64_t); case MET: case MPT: case MQT: return 1 + sizeof(Id); } not_reached(); } if (immType(op, idx) == RATA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); return encodedRATSize(pc); } if (immIsVector(op, idx)) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); int vecElemSz; auto itype = immType(op, idx); if (itype == BLA) { vecElemSz = sizeof(Offset); } else if (itype == ILA) { vecElemSz = 2 * sizeof(uint32_t); } else if (itype == VSA) { vecElemSz = sizeof(Id); } else { assert(itype == SLA); vecElemSz = sizeof(StrVecItem); } return sizeof(int32_t) + vecElemSz * decode_raw<int32_t>(pc); } ArgType type = immType(op, idx); return (type >= 0) ? argTypeToSizes[type] : 0; }