/* Capstone Disassembly Engine */ /* By Dmitry Sibirtsev , 2023 */ #ifdef CAPSTONE_HAS_HPPA #include #include // offsetof macro #include #include "HPPADisassembler.h" #include "HPPAConstants.h" #include "../../Mapping.h" #include "../../MathExtras.h" #include "../../utils.h" #define CMPLT_HAS_MODIFY_BIT(CMPLT) (((CMPLT)&1) == 1) #define HPPA_EXT_REF(MI) (&MI->hppa_ext) static const char *const compare_cond_names[] = { "", "=", "<", "<=", "<<", "<<=", "sv", "od", "tr", "<>", ">=", ">", ">>=", ">>", "nsv", "ev" }; static const char *const compare_cond_64_names[] = { "*", "*=", "*<", "*<=", "*<<", "*<<=", "*sv", "*od", "*tr", "*<>", "*>=", "*>", "*>>=", "*>>", "*nsv", "*ev" }; static const char *const cmpib_cond_64_names[] = { "*<<", "*=", "*<", "*<=", "*>>=", "*<>", "*>=", "*>" }; static const char *const add_cond_names[] = { "", "=", "<", "<=", "nuv", "znv", "sv", "od", "tr", "<>", ">=", ">", "uv", "vnz", "nsv", "ev" }; static const char *const add_cond_64_names[] = { "*", "*=", "*<", "*<=", "*nuv", "*znv", "*sv", "*od", "*tr", "*<>", "*>=", "*>", "*uv", "*vnz", "*nsv", "*ev" }; static const char *const wide_add_cond_names[] = { "*", "=", "<", "<=", "nuv", "*=", "*<", "*<=", "tr", "<>", ">=", ">", "uv", "*<>", "*>=", "*>" }; static const char *const logical_cond_names[] = { "", "=", "<", "<=", "", "", "", "od", "tr", "<>", ">=", ">", "", "", "", "ev" }; static const char *const logical_cond_64_names[] = { "*", "*=", "*<", "*<=", "", "", "", "*od", "*tr", "*<>", "*>=", "*>", "", "", "", "*ev" }; static const char *const unit_cond_names[] = { "", "swz", "sbz", "shz", "sdc", "swc", "sbc", "shc", "tr", "nwz", "nbz", "nhz", "ndc", "nwc", "nbc", "nhc" }; static const char *const unit_cond_64_names[] = { "*", "*swz", "*sbz", "*shz", "*sdc", "*swc", "*sbc", "*shc", "*tr", "*nwz", "*nbz", "*nhz", "*ndc", "*nwc", "*nbc", "*nhc" }; static const char *const shift_cond_names[] = { "", "=", "<", "od", "tr", "<>", ">=", "ev" }; static const char *const shift_cond_64_names[] = { "*", "*=", "*<", "*od", "*tr", "*<>", "*>=", "*ev" }; static const char *const index_compl_names[] = { "", "m", "s", "sm" }; static const char *const short_ldst_compl_names[] = { "", "ma", "", "mb" }; static const char *const short_bytes_compl_names[] = { "", "b,m", "e", "e,m" }; static const char *const float_format_names[] = { "sgl", "dbl", "", "quad" }; static const char *const float_cond_names[] = { "", "acc", "rej", "", "", "acc8", "rej8", "", "", "acc6", "", "", "", "acc4", "", "", "", "acc2", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }; static const char *const fcnv_fixed_names[] = { "w", "dw", "", "qw" }; static const char *const fcnv_ufixed_names[] = { "uw", "udw", "", "uqw" }; static const char *const float_comp_names[] = { "false?", "false", "?", "!<=>", "=", "=t", "?=", "!<>", "!?>=", "<", "?<", "!>=", "!?>", "<=", "?<=", "!>", "!?<=", ">", "?>", "!<=", "!?<", ">=", "?>=", "!<", "!?=", "<>", "!=", "!=t", "!?", "<=>", "true?", "true" }; static const char *const signed_unsigned_names[] = { "u", "s" }; static const char *const saturation_names[] = { "us", "ss", "", "" }; static const char *const add_compl_names[] = { "", "", "l", "tsv" }; #define CREATE_GR_REG(MI, gr) MCOperand_CreateReg0(MI, gr + HPPA_REG_GR0) #define CREATE_SR_REG(MI, sr) MCOperand_CreateReg0(MI, sr + HPPA_REG_SR0) #define CREATE_CR_REG(MI, cr) MCOperand_CreateReg0(MI, cr + HPPA_REG_CR0) #define CREATE_FPR_REG(MI, fpr) MCOperand_CreateReg0(MI, fpr + HPPA_REG_FPR0) #define CREATE_FPE_REG(MI, fpe) MCOperand_CreateReg0(MI, fpe + HPPA_REG_FPE0) #define CREATE_SP_FPR_REG(MI, fpr) \ MCOperand_CreateReg0(MI, fpr + HPPA_REG_SP_FPR0) static void create_float_reg_spec(MCInst *MI, uint32_t reg, uint32_t fpe_flag) { if (fpe_flag == 1) { CREATE_FPE_REG(MI, reg); } else { CREATE_FPR_REG(MI, reg); } } /* Get at various relevant fields of an instruction word. */ #define MASK_5 0x1f #define MASK_10 0x3ff #define MASK_11 0x7ff #define MASK_14 0x3fff #define MASK_16 0xffff #define MASK_21 0x1fffff /* Routines to extract various sized constants out of hppa instructions. */ /* Extract a 3-bit space register number from a be, ble, mtsp or mfsp. */ static int extract_3(unsigned word) { return get_insn_field(word, 18, 18) << 2 | get_insn_field(word, 16, 17); } static int extract_5_load(unsigned word) { return LowSignExtend64(word >> 16 & MASK_5, 5); } /* Extract the immediate field from a st{bhw}s instruction. */ static int extract_5_store(unsigned word) { return LowSignExtend64(word & MASK_5, 5); } /* Extract an 11 bit immediate field. */ static int extract_11(unsigned word) { return LowSignExtend64(word & MASK_11, 11); } /* Extract a 14 bit immediate field. */ static int extract_14(unsigned word) { return LowSignExtend64(word & MASK_14, 14); } /* Extract a 16 bit immediate field. */ static int extract_16(unsigned word, bool wide) { int m15, m0, m1; m0 = get_insn_bit(word, 16); m1 = get_insn_bit(word, 17); m15 = get_insn_bit(word, 31); word = (word >> 1) & 0x1fff; if (wide) { word = word | (m15 << 15) | ((m15 ^ m0) << 14) | ((m15 ^ m1) << 13); } else { word = word | (m15 << 15) | (m15 << 14) | (m15 << 13); } return SignExtend32(word, 16); } /* Extract a 21 bit constant. */ static int extract_21(unsigned word) { int val; word &= MASK_21; word <<= 11; val = get_insn_field(word, 20, 20); val <<= 11; val |= get_insn_field(word, 9, 19); val <<= 2; val |= get_insn_field(word, 5, 6); val <<= 5; val |= get_insn_field(word, 0, 4); val <<= 2; val |= get_insn_field(word, 7, 8); return SignExtend32(val, 21) << 11; } /* Extract a 12 bit constant from branch instructions. */ static int extract_12(unsigned word) { return SignExtend32(get_insn_field(word, 19, 28) | get_insn_field(word, 29, 29) << 10 | (word & 0x1) << 11, 12) << 2; } /* Extract a 17 bit constant from branch instructions, returning the 19 bit signed value. */ static int extract_17(unsigned word) { return SignExtend32(get_insn_field(word, 19, 28) | get_insn_field(word, 29, 29) << 10 | get_insn_field(word, 11, 15) << 11 | (word & 0x1) << 16, 17) << 2; } static int extract_22(unsigned word) { return SignExtend32(get_insn_field(word, 19, 28) | get_insn_field(word, 29, 29) << 10 | get_insn_field(word, 11, 15) << 11 | get_insn_field(word, 6, 10) << 16 | (word & 0x1) << 21, 22) << 2; } static void push_str_modifier(hppa_ext *hppa, const char *modifier) { if (strcmp(modifier, "")) { hppa_modifier *mod = &hppa->modifiers[hppa->mod_num++]; assert(hppa->mod_num <= HPPA_MAX_MODIFIERS_LEN); mod->type = HPPA_MOD_STR; assert(strlen(modifier) <= HPPA_STR_MODIFIER_LEN); strcpy(mod->str_mod, modifier); } } static void push_int_modifier(hppa_ext *hppa, uint64_t modifier) { hppa_modifier *mod = &hppa->modifiers[hppa->mod_num++]; assert(hppa->mod_num <= HPPA_MAX_MODIFIERS_LEN); mod->type = HPPA_MOD_INT; mod->int_mod = modifier; } static void fill_sysop_insn_name(MCInst *MI, uint32_t insn) { uint32_t ext8 = get_insn_field(insn, 19, 26); uint32_t ext5 = get_insn_field(insn, 11, 15); if (MODE_IS_HPPA_20(MI->csh->mode)) { switch (ext8) { case 0xa5: MCInst_setOpcode(MI, HPPA_INS_MFIA); return; case 0xc6: MCInst_setOpcode(MI, HPPA_INS_MTSARCM); return; case 0x65: push_str_modifier(HPPA_EXT_REF(MI), "r"); // fallthrough case 0x60: MCInst_setOpcode(MI, HPPA_INS_RFI); return; default: break; } } switch (ext8) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_BREAK); break; case 0x20: if (ext5 == 0x00) { MCInst_setOpcode(MI, HPPA_INS_SYNC); } else if (ext5 == 0x10) { MCInst_setOpcode(MI, HPPA_INS_SYNCDMA); } break; case 0x60: MCInst_setOpcode(MI, HPPA_INS_RFI); break; case 0x65: MCInst_setOpcode(MI, HPPA_INS_RFIR); break; case 0x6b: MCInst_setOpcode(MI, HPPA_INS_SSM); break; case 0x73: MCInst_setOpcode(MI, HPPA_INS_RSM); break; case 0xc3: MCInst_setOpcode(MI, HPPA_INS_MTSM); break; case 0x85: MCInst_setOpcode(MI, HPPA_INS_LDSID); break; case 0xc1: MCInst_setOpcode(MI, HPPA_INS_MTSP); break; case 0x25: MCInst_setOpcode(MI, HPPA_INS_MFSP); break; case 0xc2: MCInst_setOpcode(MI, HPPA_INS_MTCTL); break; case 0x45: MCInst_setOpcode(MI, HPPA_INS_MFCTL); if (get_insn_bit(insn, 17) == 1 && MODE_IS_HPPA_20(MI->csh->mode)) { push_str_modifier(HPPA_EXT_REF(MI), "w"); } break; default: break; } } static bool decode_sysop(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t ext8 = get_insn_field(insn, 19, 26); uint32_t ext5 = get_insn_field(insn, 11, 15); uint32_t r1 = get_insn_field(insn, 6, 10); uint32_t r2 = get_insn_field(insn, 11, 15); uint32_t t = get_insn_field(insn, 27, 31); uint32_t s = extract_3(insn); if (MODE_IS_HPPA_20(MI->csh->mode)) { switch (ext8) { case 0xa5: if (ext5 != 0) { return false; } CREATE_GR_REG(MI, t); return true; case 0xc6: CREATE_GR_REG(MI, r2); return true; default: break; } } switch (ext8) { case 0x00: MCOperand_CreateImm0(MI, t); MCOperand_CreateImm0(MI, get_insn_field(insn, 6, 18)); return true; case 0x20: if (ext5 != 0x00 && ext5 != 0x10) { return false; } // fallthrough case 0x60: case 0x65: return true; case 0x6b: case 0x73: MCOperand_CreateImm0(MI, get_insn_field(insn, 9, 15)); CREATE_GR_REG(MI, t); return true; case 0xc3: CREATE_GR_REG(MI, r2); return true; case 0x85: CREATE_SR_REG(MI, s); CREATE_GR_REG(MI, r1); CREATE_GR_REG(MI, t); return true; case 0xc1: CREATE_GR_REG(MI, r2); CREATE_SR_REG(MI, s); return true; case 0x25: if (ext5 != 0) { return false; } CREATE_SR_REG(MI, s); CREATE_GR_REG(MI, t); return true; case 0xc2: CREATE_GR_REG(MI, r2); CREATE_CR_REG(MI, r1); return true; case 0x45: if (ext5 != 0) { return false; } if (get_insn_bit(insn, 17) == 1 && MODE_IS_HPPA_20(ud->mode) && r1 != 11) { return false; } CREATE_CR_REG(MI, r1); CREATE_GR_REG(MI, t); return true; default: return false; } } static void fill_memmgmt_insn_name(MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 19, 25); if (MODE_IS_HPPA_20(MI->csh->mode)) { switch (ext) { case 0x20: MCInst_setOpcode(MI, HPPA_INS_IITLBT); return; case 0x18: MCInst_setOpcode(MI, HPPA_INS_PITLB); push_str_modifier(HPPA_EXT_REF(MI), "l"); return; case 0x60: MCInst_setOpcode(MI, HPPA_INS_IDTLBT); return; case 0x58: MCInst_setOpcode(MI, HPPA_INS_PDTLB); push_str_modifier(HPPA_EXT_REF(MI), "l"); return; case 0x4f: MCInst_setOpcode(MI, HPPA_INS_FIC); return; case 0x46: if (get_insn_bit(insn, 18) == 0) { MCInst_setOpcode(MI, HPPA_INS_PROBE); } else { MCInst_setOpcode(MI, HPPA_INS_PROBEI); }; push_str_modifier(HPPA_EXT_REF(MI), "r"); return; case 0x47: if (get_insn_bit(insn, 18) == 0) { MCInst_setOpcode(MI, HPPA_INS_PROBE); } else { MCInst_setOpcode(MI, HPPA_INS_PROBEI); }; push_str_modifier(HPPA_EXT_REF(MI), "w"); return; default: break; } } switch (ext) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_IITLBP); break; case 0x01: MCInst_setOpcode(MI, HPPA_INS_IITLBA); break; case 0x08: MCInst_setOpcode(MI, HPPA_INS_PITLB); break; case 0x09: MCInst_setOpcode(MI, HPPA_INS_PITLBE); break; case 0x0a: MCInst_setOpcode(MI, HPPA_INS_FIC); break; case 0x0b: MCInst_setOpcode(MI, HPPA_INS_FICE); break; case 0x40: MCInst_setOpcode(MI, HPPA_INS_IDTLBP); break; case 0x41: MCInst_setOpcode(MI, HPPA_INS_IDTLBA); break; case 0x48: MCInst_setOpcode(MI, HPPA_INS_PDTLB); break; case 0x49: MCInst_setOpcode(MI, HPPA_INS_PDTLBE); break; case 0x4a: MCInst_setOpcode(MI, HPPA_INS_FDC); break; case 0x4b: MCInst_setOpcode(MI, HPPA_INS_FDCE); break; case 0x4e: MCInst_setOpcode(MI, HPPA_INS_PDC); break; case 0x46: if (get_insn_bit(insn, 18) == 0) { MCInst_setOpcode(MI, HPPA_INS_PROBER); } else { MCInst_setOpcode(MI, HPPA_INS_PROBERI); }; break; case 0x47: if (get_insn_bit(insn, 18) == 0) { MCInst_setOpcode(MI, HPPA_INS_PROBEW); } else { MCInst_setOpcode(MI, HPPA_INS_PROBEWI); }; break; case 0x4d: MCInst_setOpcode(MI, HPPA_INS_LPA); break; case 0x4c: MCInst_setOpcode(MI, HPPA_INS_LCI); break; default: break; } } static void fill_memmgmt_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode) { uint8_t cmplt = get_insn_bit(insn, 26); uint32_t ext = get_insn_field(insn, 19, 25); if (MODE_IS_HPPA_20(mode)) { switch (ext) { case 0x18: case 0x58: case 0x4f: goto success; default: break; } } switch (ext) { case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4e: case 0x4d: break; default: return; } success: if (CMPLT_HAS_MODIFY_BIT(cmplt)) { hppa_ext->b_writeble = true; } push_str_modifier(hppa_ext, index_compl_names[cmplt]); } static bool decode_memmgmt(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 19, 25); uint32_t b = get_insn_field(insn, 6, 10); uint32_t r = get_insn_field(insn, 11, 15); uint32_t s3 = extract_3(insn); uint32_t s2 = get_insn_field(insn, 16, 17); uint32_t t = get_insn_field(insn, 27, 31); if (ext > 0x20 && get_insn_bit(insn, 18) == 1 && (ext != 0x46 && ext != 0x47)) { if (MODE_IS_HPPA_20(ud->mode)) { if (ext != 0x4a) { return false; } } else { return false; } } if (MODE_IS_HPPA_20(ud->mode)) { switch (ext) { case 0x20: case 0x60: CREATE_GR_REG(MI, r); CREATE_GR_REG(MI, b); goto success; case 0x58: case 0x4f: CREATE_GR_REG(MI, r); CREATE_SR_REG(MI, s2); CREATE_GR_REG(MI, b); goto success; case 0x18: CREATE_GR_REG(MI, r); CREATE_SR_REG(MI, s3); CREATE_GR_REG(MI, b); goto success; case 0x4a: if (get_insn_bit(insn, 18) == 1) { MCOperand_CreateImm0(MI, LowSignExtend64(r, 5)); } else { CREATE_GR_REG(MI, r); } CREATE_SR_REG(MI, s2); CREATE_GR_REG(MI, b); goto success; default: break; } } switch (ext) { case 0x00: case 0x01: case 0x08: case 0x09: case 0x0a: case 0x0b: CREATE_GR_REG(MI, r); CREATE_SR_REG(MI, s3); CREATE_GR_REG(MI, b); break; case 0x40: case 0x41: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4e: CREATE_GR_REG(MI, r); CREATE_SR_REG(MI, s2); CREATE_GR_REG(MI, b); break; case 0x46: case 0x47: CREATE_SR_REG(MI, s2); CREATE_GR_REG(MI, b); if (get_insn_bit(insn, 18) == 0) { CREATE_GR_REG(MI, r); } else { MCOperand_CreateImm0(MI, r); } CREATE_GR_REG(MI, t); break; case 0x4d: case 0x4c: CREATE_GR_REG(MI, r); CREATE_SR_REG(MI, s2); CREATE_GR_REG(MI, b); CREATE_GR_REG(MI, t); break; default: return false; } success: fill_memmgmt_mods(insn, HPPA_EXT_REF(MI), MI->csh->mode); return true; } static void fill_alu_insn_name(MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 20, 25); if (MODE_IS_HPPA_20(MI->csh->mode)) { switch (ext) { case 0x28: case 0x38: case 0x1c: case 0x3c: MCInst_setOpcode(MI, HPPA_INS_ADD); return; case 0x19: case 0x29: case 0x39: case 0x1a: case 0x2a: case 0x3a: case 0x1b: case 0x2b: case 0x3b: MCInst_setOpcode(MI, HPPA_INS_SHLADD); return; case 0x30: case 0x13: case 0x33: case 0x14: case 0x34: MCInst_setOpcode(MI, HPPA_INS_SUB); return; case 0x22: MCInst_setOpcode(MI, HPPA_INS_CMPCLR); return; case 0x27: MCInst_setOpcode(MI, HPPA_INS_UADDCM); return; case 0x2f: MCInst_setOpcode(MI, HPPA_INS_DCOR); return; case 0x0f: case 0x0d: case 0x0c: MCInst_setOpcode(MI, HPPA_INS_HADD); return; case 0x07: case 0x05: case 0x04: MCInst_setOpcode(MI, HPPA_INS_HSUB); return; case 0x0b: MCInst_setOpcode(MI, HPPA_INS_HAVG); return; case 0x1d: case 0x1e: case 0x1f: MCInst_setOpcode(MI, HPPA_INS_HSHLADD); return; case 0x15: case 0x16: case 0x17: MCInst_setOpcode(MI, HPPA_INS_HSHRADD); return; default: break; } } switch (ext) { case 0x18: MCInst_setOpcode(MI, HPPA_INS_ADD); break; case 0x38: MCInst_setOpcode(MI, HPPA_INS_ADDO); break; case 0x1c: MCInst_setOpcode(MI, HPPA_INS_ADDC); break; case 0x3c: MCInst_setOpcode(MI, HPPA_INS_ADDCO); break; case 0x19: MCInst_setOpcode(MI, HPPA_INS_SH1ADD); break; case 0x39: MCInst_setOpcode(MI, HPPA_INS_SH1ADDO); break; case 0x1a: MCInst_setOpcode(MI, HPPA_INS_SH2ADD); break; case 0x3a: MCInst_setOpcode(MI, HPPA_INS_SH2ADDO); break; case 0x1b: MCInst_setOpcode(MI, HPPA_INS_SH3ADD); break; case 0x3b: MCInst_setOpcode(MI, HPPA_INS_SH3ADDO); break; case 0x10: MCInst_setOpcode(MI, HPPA_INS_SUB); break; case 0x30: MCInst_setOpcode(MI, HPPA_INS_SUBO); break; case 0x13: MCInst_setOpcode(MI, HPPA_INS_SUBT); break; case 0x33: MCInst_setOpcode(MI, HPPA_INS_SUBTO); break; case 0x14: MCInst_setOpcode(MI, HPPA_INS_SUBB); break; case 0x34: MCInst_setOpcode(MI, HPPA_INS_SUBBO); break; case 0x11: MCInst_setOpcode(MI, HPPA_INS_DS); break; case 0x00: MCInst_setOpcode(MI, HPPA_INS_ANDCM); break; case 0x08: MCInst_setOpcode(MI, HPPA_INS_AND); break; case 0x09: MCInst_setOpcode(MI, HPPA_INS_OR); break; case 0x0a: MCInst_setOpcode(MI, HPPA_INS_XOR); break; case 0x0e: MCInst_setOpcode(MI, HPPA_INS_UXOR); break; case 0x22: MCInst_setOpcode(MI, HPPA_INS_COMCLR); break; case 0x26: MCInst_setOpcode(MI, HPPA_INS_UADDCM); break; case 0x27: MCInst_setOpcode(MI, HPPA_INS_UADDCMT); break; case 0x28: MCInst_setOpcode(MI, HPPA_INS_ADDL); break; case 0x29: MCInst_setOpcode(MI, HPPA_INS_SH1ADDL); break; case 0x2a: MCInst_setOpcode(MI, HPPA_INS_SH2ADDL); break; case 0x2b: MCInst_setOpcode(MI, HPPA_INS_SH3ADDL); break; case 0x2e: MCInst_setOpcode(MI, HPPA_INS_DCOR); break; case 0x2f: MCInst_setOpcode(MI, HPPA_INS_IDCOR); break; default: break; } } static void fill_alu_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode) { uint32_t cond = (get_insn_field(insn, 19, 19) << 3) | get_insn_field(insn, 16, 18); uint32_t ext = get_insn_field(insn, 20, 25); if (MODE_IS_HPPA_20(mode)) { uint32_t e1 = get_insn_field(insn, 20, 21); uint32_t e2 = get_insn_bit(insn, 23); uint32_t e3 = get_insn_field(insn, 24, 25); uint32_t d = get_insn_bit(insn, 26); switch (ext) { case 0x18: case 0x28: case 0x38: case 0x1c: case 0x3c: if (e2 == 1) { if (d == 1) { push_str_modifier(hppa_ext, "dc"); } else { push_str_modifier(hppa_ext, "c"); } } // fallthrough case 0x19: case 0x29: case 0x39: case 0x1a: case 0x2a: case 0x3a: case 0x1b: case 0x2b: case 0x3b: push_str_modifier(hppa_ext, add_compl_names[e1]); if (d == 1) { push_str_modifier(hppa_ext, add_cond_64_names[cond]); } else { push_str_modifier(hppa_ext, add_cond_names[cond]); } return; case 0x10: case 0x30: case 0x13: case 0x33: case 0x14: case 0x34: if (e2 == 1) { if (d == 1) { push_str_modifier(hppa_ext, "db"); } else { push_str_modifier(hppa_ext, "b"); } } if (e1 == 3) { push_str_modifier(hppa_ext, "tsv"); } if (e3 == 3) { push_str_modifier(hppa_ext, "tc"); } // fallthrough case 0x22: if (d == 1) { push_str_modifier(hppa_ext, compare_cond_64_names[cond]); } else { push_str_modifier(hppa_ext, compare_cond_names[cond]); } return; case 0x00: case 0x08: case 0x09: case 0x0a: if (d == 1) { push_str_modifier(hppa_ext, logical_cond_64_names[cond]); } else { push_str_modifier(hppa_ext, logical_cond_names[cond]); } return; case 0x27: push_str_modifier(hppa_ext, "tc"); goto unit_cond; case 0x2f: push_str_modifier(hppa_ext, "i"); // fallthrough case 0x26: case 0x0e: case 0x2e: unit_cond: if (d == 1) { push_str_modifier(hppa_ext, unit_cond_64_names[cond]); } else { push_str_modifier(hppa_ext, unit_cond_names[cond]); } return; case 0x0d: case 0x0c: case 0x05: case 0x04: push_str_modifier(hppa_ext, saturation_names[e3]); return; default: break; } } switch (ext) { case 0x18: case 0x38: case 0x1c: case 0x3c: case 0x19: case 0x39: case 0x1a: case 0x3a: case 0x3b: case 0x28: case 0x29: case 0x2a: case 0x2b: push_str_modifier(hppa_ext, add_cond_names[cond]); break; case 0x10: case 0x30: case 0x13: case 0x33: case 0x14: case 0x34: case 0x11: case 0x22: push_str_modifier(hppa_ext, compare_cond_names[cond]); break; case 0x00: case 0x08: case 0x09: case 0x0a: push_str_modifier(hppa_ext, logical_cond_names[cond]); break; case 0x0e: case 0x26: case 0x27: case 0x2e: case 0x2f: push_str_modifier(hppa_ext, unit_cond_names[cond]); break; default: break; } } static bool decode_alu(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 20, 25); uint32_t r1 = get_insn_field(insn, 11, 15); uint32_t r2 = get_insn_field(insn, 6, 10); uint32_t t = get_insn_field(insn, 27, 31); if (MODE_IS_HPPA_20(ud->mode)) { switch (ext) { case 0x19: case 0x29: case 0x39: case 0x1a: case 0x2a: case 0x3a: case 0x1b: case 0x2b: case 0x3b: case 0x1d: case 0x1e: case 0x1f: case 0x15: case 0x16: case 0x17: case 0x0f: case 0x0d: case 0x0c: case 0x07: case 0x05: case 0x04: case 0x0b: CREATE_GR_REG(MI, r1); if (ext > 0x10) { MCOperand_CreateImm0( MI, get_insn_field(insn, 24, 25)); } CREATE_GR_REG(MI, r2); CREATE_GR_REG(MI, t); goto success; default: break; } } switch (ext) { case 0x18: case 0x38: case 0x1c: case 0x3c: case 0x19: case 0x39: case 0x1a: case 0x3a: case 0x1b: case 0x3b: case 0x10: case 0x30: case 0x13: case 0x33: case 0x14: case 0x34: case 0x11: case 0x00: case 0x08: case 0x09: case 0x0a: case 0x0e: case 0x22: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a: case 0x2b: CREATE_GR_REG(MI, r1); // fallthrough case 0x2e: case 0x2f: CREATE_GR_REG(MI, r2); CREATE_GR_REG(MI, t); break; default: return false; } success: fill_alu_mods(insn, HPPA_EXT_REF(MI), MI->csh->mode); return true; } static void fill_idxmem_insn_name(MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 22, 25); if (MODE_IS_HPPA_20(MI->csh->mode)) { switch (ext) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_LDB); return; case 0x01: MCInst_setOpcode(MI, HPPA_INS_LDH); return; case 0x02: MCInst_setOpcode(MI, HPPA_INS_LDW); return; case 0x03: MCInst_setOpcode(MI, HPPA_INS_LDD); return; case 0x04: MCInst_setOpcode(MI, HPPA_INS_LDDA); return; case 0x05: MCInst_setOpcode(MI, HPPA_INS_LDCD); return; case 0x06: MCInst_setOpcode(MI, HPPA_INS_LDWA); return; case 0x07: MCInst_setOpcode(MI, HPPA_INS_LDCW); return; default: break; } if (get_insn_bit(insn, 19) == 1) { switch (ext) { case 0x08: MCInst_setOpcode(MI, HPPA_INS_STB); return; case 0x09: MCInst_setOpcode(MI, HPPA_INS_STH); return; case 0x0a: MCInst_setOpcode(MI, HPPA_INS_STW); return; case 0x0b: MCInst_setOpcode(MI, HPPA_INS_STD); return; case 0x0c: MCInst_setOpcode(MI, HPPA_INS_STBY); return; case 0x0d: MCInst_setOpcode(MI, HPPA_INS_STDBY); return; case 0x0e: MCInst_setOpcode(MI, HPPA_INS_STWA); return; case 0x0f: MCInst_setOpcode(MI, HPPA_INS_STDA); return; default: break; } } } if (get_insn_bit(insn, 19) == 0) { switch (ext) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_LDBX); break; case 0x01: MCInst_setOpcode(MI, HPPA_INS_LDHX); break; case 0x02: MCInst_setOpcode(MI, HPPA_INS_LDWX); break; case 0x07: MCInst_setOpcode(MI, HPPA_INS_LDCWX); break; case 0x06: MCInst_setOpcode(MI, HPPA_INS_LDWAX); break; default: break; } } else { switch (ext) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_LDBS); break; case 0x01: MCInst_setOpcode(MI, HPPA_INS_LDHS); break; case 0x02: MCInst_setOpcode(MI, HPPA_INS_LDWS); break; case 0x07: MCInst_setOpcode(MI, HPPA_INS_LDCWS); break; case 0x06: MCInst_setOpcode(MI, HPPA_INS_LDWAS); break; case 0x08: MCInst_setOpcode(MI, HPPA_INS_STBS); break; case 0x09: MCInst_setOpcode(MI, HPPA_INS_STHS); break; case 0x0a: MCInst_setOpcode(MI, HPPA_INS_STWS); break; case 0x0c: MCInst_setOpcode(MI, HPPA_INS_STBYS); break; case 0x0e: MCInst_setOpcode(MI, HPPA_INS_STWAS); break; default: break; } } } static void fill_idxmem_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode, uint32_t im5) { uint32_t cmplt = (get_insn_bit(insn, 18) << 1) | get_insn_bit(insn, 26); uint32_t cc = get_insn_field(insn, 20, 21); uint32_t ext = get_insn_field(insn, 22, 25); if (CMPLT_HAS_MODIFY_BIT(cmplt)) { hppa_ext->b_writeble = true; } if (get_insn_bit(insn, 19) == 0) { switch (ext) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x06: push_str_modifier(hppa_ext, index_compl_names[cmplt]); if (cc == 2) { push_str_modifier(hppa_ext, "sl"); } break; case 0x05: case 0x07: push_str_modifier(hppa_ext, index_compl_names[cmplt]); if (cc == 1) { push_str_modifier(hppa_ext, "co"); } break; default: break; } } else { switch (ext) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x06: if (cmplt == 1 && im5 == 0) { push_str_modifier(hppa_ext, "o"); } else { push_str_modifier( hppa_ext, short_ldst_compl_names[cmplt]); } if (cc == 2) { push_str_modifier(hppa_ext, "sl"); } break; case 0x05: case 0x07: if (cmplt == 1 && im5 == 0) { push_str_modifier(hppa_ext, "o"); } else { push_str_modifier( hppa_ext, short_ldst_compl_names[cmplt]); } if (cc == 1) { push_str_modifier(hppa_ext, "co"); } break; case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0e: case 0x0f: if (cmplt == 1 && im5 == 0) { push_str_modifier(hppa_ext, "o"); } else { push_str_modifier( hppa_ext, short_ldst_compl_names[cmplt]); } if (cc == 1) { push_str_modifier(hppa_ext, "bc"); } else if (cc == 2) { push_str_modifier(hppa_ext, "sl"); } break; case 0x0c: case 0x0d: push_str_modifier(hppa_ext, short_bytes_compl_names[cmplt]); if (cc == 1) { push_str_modifier(hppa_ext, "bc"); } else if (cc == 2) { push_str_modifier(hppa_ext, "sl"); } break; default: break; } } } static bool decode_idxmem(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 22, 25); uint32_t im5; uint32_t r = get_insn_field(insn, 11, 15); uint32_t b = get_insn_field(insn, 6, 10); uint32_t t = get_insn_field(insn, 27, 31); uint32_t s = get_insn_field(insn, 16, 17); if (MODE_IS_HPPA_20(ud->mode)) { if (get_insn_bit(insn, 19) == 0) { switch (ext) { case 0x03: case 0x05: case 0x04: CREATE_GR_REG(MI, r); if (ext != 0x04) { CREATE_SR_REG(MI, s); } CREATE_GR_REG(MI, b); CREATE_GR_REG(MI, t); fill_idxmem_mods(insn, HPPA_EXT_REF(MI), ud->mode, -1); return true; default: break; } } else { switch (ext) { case 0x03: case 0x05: case 0x04: im5 = extract_5_load(insn); MCOperand_CreateImm0(MI, im5); if (ext != 0x04) { CREATE_SR_REG(MI, s); } CREATE_GR_REG(MI, b); CREATE_GR_REG(MI, t); fill_idxmem_mods(insn, HPPA_EXT_REF(MI), ud->mode, im5); return true; case 0x0b: case 0x0d: case 0x0f: im5 = extract_5_store(insn); CREATE_GR_REG(MI, r); MCOperand_CreateImm0(MI, im5); if (ext != 0x0f) { CREATE_SR_REG(MI, s); } CREATE_GR_REG(MI, b); fill_idxmem_mods(insn, HPPA_EXT_REF(MI), ud->mode, im5); return true; default: break; } } } if (get_insn_bit(insn, 19) == 0) { switch (ext) { case 0x00: case 0x01: case 0x02: case 0x07: case 0x06: CREATE_GR_REG(MI, r); if (ext != 0x06) { CREATE_SR_REG(MI, s); } CREATE_GR_REG(MI, b); CREATE_GR_REG(MI, t); break; default: return false; } fill_idxmem_mods(insn, HPPA_EXT_REF(MI), ud->mode, -1); return true; } else { switch (ext) { case 0x00: case 0x01: case 0x02: case 0x07: case 0x06: im5 = extract_5_load(insn); MCOperand_CreateImm0(MI, im5); if (ext != 0x06) { CREATE_SR_REG(MI, s); } CREATE_GR_REG(MI, b); CREATE_GR_REG(MI, t); break; case 0x08: case 0x09: case 0x0a: case 0x0c: case 0x0e: im5 = extract_5_store(insn); CREATE_GR_REG(MI, r); MCOperand_CreateImm0(MI, im5); if (ext != 0x0e) { CREATE_SR_REG(MI, s); } CREATE_GR_REG(MI, b); break; default: return false; } if (MODE_IS_HPPA_20(ud->mode)) { fill_idxmem_mods(insn, HPPA_EXT_REF(MI), ud->mode, im5); } else { fill_idxmem_mods(insn, HPPA_EXT_REF(MI), ud->mode, -1); } return true; } } static void fill_ldst_dw_insn_name(MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; uint32_t ext = get_insn_bit(insn, 30); if (opcode == 0x14) { if (ext == 0) { MCInst_setOpcode(MI, HPPA_INS_LDD); } else { MCInst_setOpcode(MI, HPPA_INS_FLDD); } } else { if (ext == 0) { MCInst_setOpcode(MI, HPPA_INS_STD); } else { MCInst_setOpcode(MI, HPPA_INS_FSTD); } } } static void fill_ldst_dw_mods(uint32_t insn, hppa_ext *hppa_ext, uint32_t im) { uint32_t cmplt = (get_insn_bit(insn, 29) << 1) | get_insn_bit(insn, 28); if (cmplt == 1 && im == 0) { push_str_modifier(hppa_ext, "o"); } else { push_str_modifier(hppa_ext, short_ldst_compl_names[cmplt]); } } static bool decode_ldst_dw(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; uint32_t im = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); im &= ~7; uint32_t ext = get_insn_bit(insn, 30); uint32_t r = get_insn_field(insn, 11, 15); uint32_t b = get_insn_field(insn, 6, 10); uint32_t s = get_insn_field(insn, 16, 17); if (opcode == HPPA_OP_TYPE_LOADDW) { MCOperand_CreateImm0(MI, im); CREATE_SR_REG(MI, s); CREATE_GR_REG(MI, b); if (ext == 0) { CREATE_GR_REG(MI, r); } else { CREATE_FPR_REG(MI, r); } } else { if (ext == 0) { CREATE_GR_REG(MI, r); } else { CREATE_FPR_REG(MI, r); } MCOperand_CreateImm0(MI, im); CREATE_SR_REG(MI, s); CREATE_GR_REG(MI, b); } fill_ldst_dw_mods(insn, HPPA_EXT_REF(MI), im); return true; } static void fill_ldst_w_insn_name(MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; uint32_t ext = get_insn_bit(insn, 29); if (opcode == 0x17) { if (ext == 0) { MCInst_setOpcode(MI, HPPA_INS_FLDW); } else { MCInst_setOpcode(MI, HPPA_INS_LDW); } } else { if (ext == 0) { MCInst_setOpcode(MI, HPPA_INS_FSTW); } else { MCInst_setOpcode(MI, HPPA_INS_STW); } } } static void fill_ldst_w_mods(uint32_t insn, hppa_ext *hppa_ext, uint32_t im) { if (im >= 0) { push_str_modifier(hppa_ext, "mb"); } else { push_str_modifier(hppa_ext, "ma"); } } static bool decode_ldst_w(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; uint32_t ext = get_insn_bit(insn, 29); uint32_t im = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); im &= ~3; uint32_t r = get_insn_field(insn, 11, 15); uint32_t b = get_insn_field(insn, 6, 10); uint32_t s = get_insn_field(insn, 16, 17); if (opcode == 0x17) { MCOperand_CreateImm0(MI, im); CREATE_SR_REG(MI, s); CREATE_GR_REG(MI, b); if (ext == 1) { CREATE_GR_REG(MI, r); } else { CREATE_FPR_REG(MI, r); } } else { if (ext == 1) { CREATE_GR_REG(MI, r); } else { CREATE_FPR_REG(MI, r); } MCOperand_CreateImm0(MI, im); CREATE_SR_REG(MI, s); CREATE_GR_REG(MI, b); } if (ext == 1) { fill_ldst_w_mods(insn, HPPA_EXT_REF(MI), im); } return true; } static void fill_arith_imm_insn_name(MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; if (MODE_IS_HPPA_20(MI->csh->mode)) { switch (opcode) { case 0x2d: case 0x2c: MCInst_setOpcode(MI, HPPA_INS_ADDI); return; case 0x25: MCInst_setOpcode(MI, HPPA_INS_SUBI); return; default: break; } } if (get_insn_bit(insn, 20) == 0) { switch (opcode) { case 0x2d: MCInst_setOpcode(MI, HPPA_INS_ADDI); break; case 0x2c: MCInst_setOpcode(MI, HPPA_INS_ADDIT); break; case 0x25: MCInst_setOpcode(MI, HPPA_INS_SUBI); break; default: break; } } else { switch (opcode) { case 0x2d: MCInst_setOpcode(MI, HPPA_INS_ADDIO); break; case 0x2c: MCInst_setOpcode(MI, HPPA_INS_ADDITO); break; case 0x25: MCInst_setOpcode(MI, HPPA_INS_SUBIO); break; default: break; } } } static void fill_arith_imm_insn_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode) { uint32_t opcode = insn >> 26; uint32_t cond = (get_insn_bit(insn, 19) << 3) | get_insn_field(insn, 16, 18); uint32_t cmplt = get_insn_bit(insn, 20); if (MODE_IS_HPPA_20(mode)) { if (cmplt == 1) { push_str_modifier(hppa_ext, "tsv"); } if (opcode == 0x2c) { push_str_modifier(hppa_ext, "tc"); } } switch (opcode) { case 0x2d: case 0x2c: push_str_modifier(hppa_ext, add_cond_names[cond]); break; case 0x25: push_str_modifier(hppa_ext, compare_cond_names[cond]); break; default: break; } } static bool decode_arith_imm(const cs_struct *ud, MCInst *MI, uint32_t insn) { MCOperand_CreateImm0(MI, extract_11(insn)); CREATE_GR_REG(MI, get_insn_field(insn, 6, 10)); CREATE_GR_REG(MI, get_insn_field(insn, 11, 15)); fill_arith_imm_insn_mods(insn, HPPA_EXT_REF(MI), ud->mode); return true; } static void fill_shexdep0_insn_name(MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 19, 21); uint32_t d = get_insn_bit(insn, 22); if (MODE_IS_HPPA_20(MI->csh->mode)) { switch (ext) { case 0x01: case 0x03: MCInst_setOpcode(MI, HPPA_INS_SHRPD); return; case 0x02: MCInst_setOpcode(MI, HPPA_INS_SHRPW); return; case 0x06: case 0x07: MCInst_setOpcode(MI, HPPA_INS_EXTRW); return; case 0x00: if (d == 0) { MCInst_setOpcode(MI, HPPA_INS_SHRPW); } else { MCInst_setOpcode(MI, HPPA_INS_SHRPD); } return; case 0x04: case 0x05: if (d == 0) { MCInst_setOpcode(MI, HPPA_INS_EXTRW); } else { MCInst_setOpcode(MI, HPPA_INS_EXTRD); } return; default: break; } } switch (ext) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_VSHD); break; case 0x02: MCInst_setOpcode(MI, HPPA_INS_SHD); break; case 0x04: MCInst_setOpcode(MI, HPPA_INS_VEXTRU); break; case 0x05: MCInst_setOpcode(MI, HPPA_INS_VEXTRS); break; case 0x06: MCInst_setOpcode(MI, HPPA_INS_EXTRU); break; case 0x07: MCInst_setOpcode(MI, HPPA_INS_EXTRS); break; default: break; } } static void fill_shexdep0_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode) { uint32_t cond = get_insn_field(insn, 16, 18); uint32_t ext = get_insn_field(insn, 19, 21); uint32_t d = get_insn_bit(insn, 22); if (ext >= 0x04 && MODE_IS_HPPA_20(mode)) { push_str_modifier(hppa_ext, signed_unsigned_names[ext & 1]); } if (MODE_IS_HPPA_20(mode)) { switch (ext) { case 0x00: case 0x04: case 0x05: if (d == 0) { break; } // fallthrough case 0x01: case 0x03: push_str_modifier(hppa_ext, shift_cond_64_names[cond]); return; default: break; } } push_str_modifier(hppa_ext, shift_cond_names[cond]); } static bool decode_shexdep0(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 19, 21); uint32_t cp = get_insn_bit(insn, 20); uint32_t cpos = get_insn_field(insn, 22, 26); uint32_t sa = 63 - ((cp << 5) | cpos); uint32_t r1 = get_insn_field(insn, 11, 15); uint32_t r2 = get_insn_field(insn, 6, 10); uint32_t clen_t = get_insn_field(insn, 27, 31); if (MODE_IS_HPPA_20(ud->mode)) { switch (ext) { case 0x01: case 0x00: case 0x03: case 0x02: CREATE_GR_REG(MI, r1); CREATE_GR_REG(MI, r2); if (ext <= 0x01) { CREATE_CR_REG(MI, 11); HPPA_EXT_REF(MI)->is_alternative = true; } else { MCOperand_CreateImm0(MI, sa); } CREATE_GR_REG(MI, clen_t); break; case 0x06: case 0x07: case 0x04: case 0x05: CREATE_GR_REG(MI, r2); if (ext >= 0x06) { MCOperand_CreateImm0(MI, cpos); } else { CREATE_CR_REG(MI, 11); HPPA_EXT_REF(MI)->is_alternative = true; } MCOperand_CreateImm0(MI, 32 - clen_t); CREATE_GR_REG(MI, r1); break; default: return false; } } else { switch (ext) { case 0x00: case 0x02: CREATE_GR_REG(MI, r1); CREATE_GR_REG(MI, r2); if (ext == 0x02) { MCOperand_CreateImm0(MI, 31 - cpos); } CREATE_GR_REG(MI, clen_t); break; case 0x04: case 0x05: case 0x06: case 0x07: CREATE_GR_REG(MI, r2); if (ext >= 0x06) { MCOperand_CreateImm0(MI, cpos); } MCOperand_CreateImm0(MI, 32 - clen_t); CREATE_GR_REG(MI, r1); break; default: return false; } } fill_shexdep0_mods(insn, HPPA_EXT_REF(MI), ud->mode); return true; } static void fill_shexdep1_insn_name(MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 19, 21); uint32_t d = get_insn_bit(insn, 22); if (MODE_IS_HPPA_20(MI->csh->mode)) { switch (ext) { case 0x02: case 0x03: MCInst_setOpcode(MI, HPPA_INS_DEPW); break; case 0x06: case 0x07: MCInst_setOpcode(MI, HPPA_INS_DEPWI); break; case 0x00: case 0x01: if (d == 0) { MCInst_setOpcode(MI, HPPA_INS_DEPW); } else { MCInst_setOpcode(MI, HPPA_INS_DEPD); } break; case 0x04: case 0x05: if (d == 0) { MCInst_setOpcode(MI, HPPA_INS_DEPWI); } else { MCInst_setOpcode(MI, HPPA_INS_DEPDI); } break; default: break; } } else { switch (ext) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_ZVDEP); break; case 0x01: MCInst_setOpcode(MI, HPPA_INS_VDEP); break; case 0x02: MCInst_setOpcode(MI, HPPA_INS_ZDEP); break; case 0x03: MCInst_setOpcode(MI, HPPA_INS_DEP); break; case 0x04: MCInst_setOpcode(MI, HPPA_INS_ZVDEPI); break; case 0x05: MCInst_setOpcode(MI, HPPA_INS_VDEPI); break; case 0x06: MCInst_setOpcode(MI, HPPA_INS_ZDEPI); break; case 0x07: MCInst_setOpcode(MI, HPPA_INS_DEPI); break; default: break; } } } static void fill_shexdep1_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode) { uint32_t cond = get_insn_field(insn, 16, 18); uint32_t cmplt = get_insn_bit(insn, 21); uint32_t ext = get_insn_field(insn, 19, 21); if (MODE_IS_HPPA_20(mode)) { if (cmplt == 0) { push_str_modifier(hppa_ext, "z"); } switch (ext) { case 0x00: case 0x01: case 0x04: case 0x05: push_str_modifier(hppa_ext, shift_cond_64_names[cond]); return; default: break; } } push_str_modifier(hppa_ext, shift_cond_names[cond]); } static bool decode_shexdep1(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 19, 21); uint32_t cl = get_insn_bit(insn, 23); uint32_t clen = get_insn_field(insn, 27, 31); uint32_t len = (cl + 1) * 32 - clen; uint32_t r = get_insn_field(insn, 11, 15); uint32_t t = get_insn_field(insn, 6, 10); uint32_t cpos = get_insn_field(insn, 22, 26); if (MODE_IS_HPPA_20(ud->mode)) { switch (ext) { case 0x02: case 0x03: case 0x06: case 0x07: if (ext >= 0x06) { MCOperand_CreateImm0(MI, LowSignExtend64(r, 5)); } else { CREATE_GR_REG(MI, r); } MCOperand_CreateImm0(MI, 31 - cpos); MCOperand_CreateImm0(MI, 32 - clen); CREATE_GR_REG(MI, t); break; case 0x00: case 0x01: case 0x04: case 0x05: if (ext >= 0x04) { MCOperand_CreateImm0(MI, LowSignExtend64(r, 5)); } else { CREATE_GR_REG(MI, r); } CREATE_CR_REG(MI, 11); HPPA_EXT_REF(MI)->is_alternative = true; MCOperand_CreateImm0(MI, len); CREATE_GR_REG(MI, t); break; default: break; } } else { switch (ext) { case 0x00: case 0x01: case 0x02: case 0x03: CREATE_GR_REG(MI, r); if (ext >= 0x02) { MCOperand_CreateImm0(MI, 31 - cpos); } MCOperand_CreateImm0(MI, 32 - clen); CREATE_GR_REG(MI, t); break; case 0x04: case 0x05: case 0x06: case 0x07: MCOperand_CreateImm0(MI, LowSignExtend64(r, 5)); if (ext >= 0x06) { MCOperand_CreateImm0(MI, 31 - cpos); } MCOperand_CreateImm0(MI, 32 - clen); CREATE_GR_REG(MI, t); break; default: break; } } fill_shexdep1_mods(insn, HPPA_EXT_REF(MI), ud->mode); return true; } static void fill_shexdep2_mods(uint32_t insn, hppa_ext *hppa_ext) { uint32_t cmplt = get_insn_bit(insn, 21); uint32_t cond = get_insn_field(insn, 16, 18); push_str_modifier(hppa_ext, signed_unsigned_names[cmplt]); push_str_modifier(hppa_ext, shift_cond_64_names[cond]); } static bool decode_shexdep2(MCInst *MI, uint32_t insn) { uint32_t pos = (get_insn_bit(insn, 20) << 5) | get_insn_field(insn, 22, 26); uint32_t cl = get_insn_bit(insn, 19); uint32_t clen = get_insn_field(insn, 27, 31); uint32_t len = (cl + 1) * 32 - clen; CREATE_GR_REG(MI, get_insn_field(insn, 6, 10)); MCOperand_CreateImm0(MI, pos); MCOperand_CreateImm0(MI, len); CREATE_GR_REG(MI, get_insn_field(insn, 11, 15)); fill_shexdep2_mods(insn, HPPA_EXT_REF(MI)); return true; } static void fill_shexdep3_mods(uint32_t insn, hppa_ext *hppa_ext) { uint32_t cmplt = get_insn_bit(insn, 21); uint32_t cond = get_insn_field(insn, 16, 18); if (cmplt == 0) { push_str_modifier(hppa_ext, "z"); } push_str_modifier(hppa_ext, shift_cond_64_names[cond]); } static bool decode_shexdep3(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; if (opcode == HPPA_OP_TYPE_SHEXDEP3) { MCInst_setOpcode(MI, HPPA_INS_DEPD); } else { MCInst_setOpcode(MI, HPPA_INS_DEPDI); } uint32_t pos = 63 - ((get_insn_bit(insn, 20) << 5) | get_insn_field(insn, 22, 26)); uint32_t cl = get_insn_bit(insn, 19); uint32_t clen = get_insn_field(insn, 27, 31); uint32_t len = (cl + 1) * 32 - clen; if (opcode == HPPA_OP_TYPE_SHEXDEP3) { CREATE_GR_REG(MI, get_insn_field(insn, 11, 15)); } else { MCOperand_CreateImm0( MI, LowSignExtend64(get_insn_field(insn, 11, 15), 5)); } MCOperand_CreateImm0(MI, pos); MCOperand_CreateImm0(MI, len); CREATE_GR_REG(MI, get_insn_field(insn, 6, 10)); fill_shexdep3_mods(insn, HPPA_EXT_REF(MI)); return true; } static void fill_multmed_insn_name(MCInst *MI, uint32_t insn) { uint32_t bit_16 = get_insn_bit(insn, 16); uint32_t ext = (get_insn_field(insn, 17, 18) << 2) | get_insn_field(insn, 20, 21); if (bit_16 == 0) { MCInst_setOpcode(MI, HPPA_INS_PERMH); return; } switch (ext) { case 0x02: MCInst_setOpcode(MI, HPPA_INS_HSHL); break; case 0x0a: case 0x0b: MCInst_setOpcode(MI, HPPA_INS_HSHR); break; case 0x00: case 0x08: MCInst_setOpcode(MI, HPPA_INS_MIXW); break; case 0x01: case 0x09: MCInst_setOpcode(MI, HPPA_INS_MIXH); break; default: break; } } static void fill_multmed_mods(uint32_t insn, hppa_ext *hppa_ext) { uint32_t bit_16 = get_insn_bit(insn, 16); uint32_t ext = (get_insn_field(insn, 17, 18) << 2) | get_insn_field(insn, 20, 21); uint32_t eb = get_insn_field(insn, 20, 21); uint32_t ea = get_insn_field(insn, 17, 18); if (bit_16 == 0) { char c[5]; snprintf(c, sizeof(c), "%d%d%d%d", get_insn_field(insn, 17, 18), get_insn_field(insn, 20, 21), get_insn_field(insn, 22, 23), get_insn_field(insn, 24, 25)); push_str_modifier(hppa_ext, c); return; } switch (ext) { case 0x0a: case 0x0b: if (eb >= 2) { push_str_modifier(hppa_ext, signed_unsigned_names[eb - 2]); } break; case 0x00: case 0x08: case 0x01: case 0x09: if (ea == 2) { push_str_modifier(hppa_ext, "l"); } else if (ea == 0) { push_str_modifier(hppa_ext, "r"); } break; default: break; } } static bool decode_multmed(MCInst *MI, uint32_t insn) { uint32_t bit_16 = get_insn_bit(insn, 16); uint32_t ext = (get_insn_field(insn, 17, 18) << 2) | get_insn_field(insn, 20, 21); uint32_t r1 = get_insn_field(insn, 11, 15); uint32_t r2 = get_insn_field(insn, 6, 10); uint32_t t = get_insn_field(insn, 27, 31); uint32_t sa = get_insn_field(insn, 22, 25); if (bit_16 == 0) { CREATE_GR_REG(MI, r2); CREATE_GR_REG(MI, t); goto success; } switch (ext) { case 0x02: case 0x0a: case 0x0b: if (ext >= 0x0a) { CREATE_GR_REG(MI, r2); } else { CREATE_GR_REG(MI, r1); } MCOperand_CreateImm0(MI, sa); CREATE_GR_REG(MI, t); break; case 0x00: case 0x08: case 0x01: case 0x09: CREATE_GR_REG(MI, r1); CREATE_GR_REG(MI, r2); CREATE_GR_REG(MI, t); break; default: return false; } success: fill_multmed_mods(insn, HPPA_EXT_REF(MI)); return true; } static void fill_branch_insn_name(MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 16, 18); uint32_t bit_19 = get_insn_bit(insn, 19); if (MODE_IS_HPPA_20(MI->csh->mode)) { if (insn == 0xe8004005) { MCInst_setOpcode(MI, HPPA_INS_CLRBTS); return; } else if (insn == 0xe8004001) { MCInst_setOpcode(MI, HPPA_INS_PUSHNOM); return; } switch (ext) { case 0x00: case 0x01: case 0x04: case 0x05: MCInst_setOpcode(MI, HPPA_INS_B); return; case 0x06: if (bit_19 == 0) { MCInst_setOpcode(MI, HPPA_INS_BV); } else { MCInst_setOpcode(MI, HPPA_INS_BVE); } return; case 0x07: if (bit_19 == 1) { MCInst_setOpcode(MI, HPPA_INS_BVE); } return; case 0x02: if (get_insn_field(insn, 19, 29) == 0 && get_insn_bit(insn, 31) == 0) { MCInst_setOpcode(MI, HPPA_INS_BLR); return; } if (get_insn_field(insn, 19, 31) == 1) { MCInst_setOpcode(MI, HPPA_INS_PUSHBTS); return; } if (bit_19 == 0 && get_insn_field(insn, 29, 31) == 0x5) { MCInst_setOpcode(MI, HPPA_INS_POPBTS); return; } return; default: return; } } switch (ext) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_BL); break; case 0x01: MCInst_setOpcode(MI, HPPA_INS_GATE); break; case 0x02: MCInst_setOpcode(MI, HPPA_INS_BLR); break; case 0x06: MCInst_setOpcode(MI, HPPA_INS_BV); break; default: break; } } static void fill_branch_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode) { uint32_t ext = get_insn_field(insn, 16, 18); uint32_t n = get_insn_bit(insn, 30); uint32_t p = get_insn_bit(insn, 31); if (MODE_IS_HPPA_20(mode)) { switch (ext) { case 0x00: case 0x05: push_str_modifier(hppa_ext, "l"); // fallthrough case 0x02: break; case 0x01: push_str_modifier(hppa_ext, "gate"); break; case 0x04: push_str_modifier(hppa_ext, "l"); push_str_modifier(hppa_ext, "push"); break; case 0x06: case 0x07: if (get_insn_bit(insn, 19) == 0) { break; } if (ext == 7) { push_str_modifier(hppa_ext, "l"); hppa_ext->is_alternative = true; if (p == 1) { push_str_modifier(hppa_ext, "push"); } } else { if (p == 1) { push_str_modifier(hppa_ext, "pop"); } } break; default: return; } } if (n == 1) { push_str_modifier(hppa_ext, "n"); } } static bool decode_branch(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 16, 18); uint32_t t = get_insn_field(insn, 6, 10); uint32_t i = get_insn_field(insn, 20, 28); uint32_t r = get_insn_field(insn, 11, 15); uint32_t bit_19 = get_insn_bit(insn, 19); if (MODE_IS_HPPA_20(ud->mode)) { if (insn == 0xe8004005 || insn == 0xe8004001) { return true; } switch (ext) { case 0x01: case 0x00: MCOperand_CreateImm0(MI, extract_17(insn)); CREATE_GR_REG(MI, t); break; case 0x04: case 0x05: MCOperand_CreateImm0(MI, extract_22(insn)); CREATE_GR_REG(MI, t); break; case 0x02: if (bit_19 == 1) { return false; } if (get_insn_field(insn, 20, 31) == 1 && t == 0) { CREATE_GR_REG(MI, r); break; } if (r == 0 && t == 0 && get_insn_field(insn, 29, 31) == 0x5) { MCOperand_CreateImm0(MI, i); break; } if (get_insn_bit(insn, 31) == 0 && get_insn_field(insn, 19, 29) == 0) { CREATE_GR_REG(MI, r); CREATE_GR_REG(MI, t); break; } return false; case 0x06: if (bit_19 == 0) { CREATE_GR_REG(MI, r); } CREATE_GR_REG(MI, t); break; case 0x07: if (bit_19 == 1) { CREATE_GR_REG(MI, t); CREATE_GR_REG(MI, 2); break; } // fallthrough default: return false; } fill_branch_mods(insn, HPPA_EXT_REF(MI), ud->mode); return true; } else { switch (ext) { case 0x00: case 0x01: MCOperand_CreateImm0(MI, extract_17(insn)); CREATE_GR_REG(MI, t); break; case 0x02: case 0x06: CREATE_GR_REG(MI, r); CREATE_GR_REG(MI, t); break; default: return false; } fill_branch_mods(insn, HPPA_EXT_REF(MI), ud->mode); return true; } } static void fill_corpdw_insn_name(MCInst *MI, uint32_t insn) { uint32_t ext = (get_insn_field(insn, 19, 19) << 1) | get_insn_field(insn, 22, 22); uint32_t opcode = insn >> 26; uint32_t uid = get_insn_field(insn, 23, 25); if (MODE_IS_HPPA_20(MI->csh->mode)) { if (opcode == 0x09) { switch (ext) { case 0x00: case 0x02: if (uid <= 0x01) { MCInst_setOpcode(MI, HPPA_INS_FLDW); } else { MCInst_setOpcode(MI, HPPA_INS_CLDW); } return; case 0x01: case 0x03: if (uid <= 0x01) { MCInst_setOpcode(MI, HPPA_INS_FSTW); } else { MCInst_setOpcode(MI, HPPA_INS_CSTW); } return; default: break; } } else { switch (ext) { case 0x00: case 0x02: if (uid == 0x00) { MCInst_setOpcode(MI, HPPA_INS_FLDD); } else { MCInst_setOpcode(MI, HPPA_INS_CLDD); } return; case 0x01: case 0x03: if (uid == 0x00) { MCInst_setOpcode(MI, HPPA_INS_FSTD); } else { MCInst_setOpcode(MI, HPPA_INS_CSTD); } return; default: break; } } } if (opcode == 0x09) { switch (ext) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_CLDWX); break; case 0x01: MCInst_setOpcode(MI, HPPA_INS_CSTWX); break; case 0x02: MCInst_setOpcode(MI, HPPA_INS_CLDWS); break; case 0x03: MCInst_setOpcode(MI, HPPA_INS_CSTWS); break; default: break; } } else { switch (ext) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_CLDDX); break; case 0x01: MCInst_setOpcode(MI, HPPA_INS_CSTDX); break; case 0x02: MCInst_setOpcode(MI, HPPA_INS_CLDDS); break; case 0x03: MCInst_setOpcode(MI, HPPA_INS_CSTDS); break; default: break; } } } static inline bool coprdw_has_uid_mod(uint32_t opcode, uint32_t uid) { return !((opcode == HPPA_OP_TYPE_COPRW && uid <= 0x01) || (opcode == HPPA_OP_TYPE_COPRDW && uid == 0x00)); } static void fill_corpdw_mods(uint32_t insn, uint32_t im, hppa_ext *hppa_ext, cs_mode mode) { uint32_t uid = get_insn_field(insn, 23, 25); uint32_t cmplt = (get_insn_bit(insn, 18) << 1) | get_insn_bit(insn, 26); uint32_t cc = get_insn_field(insn, 20, 21); uint32_t ext = (get_insn_bit(insn, 19) << 1) | get_insn_bit(insn, 22); uint32_t opcode = insn >> 26; if (coprdw_has_uid_mod(opcode, uid)) { push_int_modifier(hppa_ext, uid); } if (CMPLT_HAS_MODIFY_BIT(cmplt)) { hppa_ext->b_writeble = true; } switch (ext) { case 0x00: case 0x01: push_str_modifier(hppa_ext, index_compl_names[cmplt]); break; case 0x02: case 0x03: if (MODE_IS_HPPA_20(mode)) { if (cmplt == 1 && im == 0) { push_str_modifier(hppa_ext, "o"); break; } } push_str_modifier(hppa_ext, short_ldst_compl_names[cmplt]); break; default: break; } if ((ext & 1) == 1 && cc == 1) { push_str_modifier(hppa_ext, "bc"); } if (cc == 2) { push_str_modifier(hppa_ext, "sl"); } } static bool decode_corpdw(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t ext = (get_insn_bit(insn, 19) << 1) | get_insn_bit(insn, 22); uint32_t x = get_insn_field(insn, 11, 15); uint32_t b = get_insn_field(insn, 6, 10); uint32_t s = get_insn_field(insn, 16, 17); uint32_t t = get_insn_field(insn, 27, 31); uint32_t opcode = MCInst_getOpcode(MI); switch (ext) { case 0x00: case 0x02: if (ext == 0x02) { x = LowSignExtend64(x, 5); MCOperand_CreateImm0(MI, x); } else { CREATE_GR_REG(MI, x); } CREATE_SR_REG(MI, s); CREATE_GR_REG(MI, b); if (opcode == HPPA_INS_FLDW || opcode == HPPA_INS_FLDD) { CREATE_FPR_REG(MI, t); } else { CREATE_GR_REG(MI, t); } break; case 0x01: case 0x03: if (opcode == HPPA_INS_FSTW || opcode == HPPA_INS_FSTD) { CREATE_FPR_REG(MI, t); } else { CREATE_GR_REG(MI, t); } if (ext == 0x03) { x = LowSignExtend64(x, 5); MCOperand_CreateImm0(MI, x); } else { CREATE_GR_REG(MI, x); } CREATE_SR_REG(MI, s); CREATE_GR_REG(MI, b); break; default: break; } fill_corpdw_mods(insn, x, HPPA_EXT_REF(MI), ud->mode); return true; } static void fill_spop_insn_name(MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 21, 22); switch (ext) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_SPOP0); break; case 0x01: MCInst_setOpcode(MI, HPPA_INS_SPOP1); break; case 0x02: MCInst_setOpcode(MI, HPPA_INS_SPOP2); break; case 0x03: MCInst_setOpcode(MI, HPPA_INS_SPOP3); break; default: break; } } static void fill_spop_mods(uint32_t insn, uint32_t ext, hppa_ext *hppa_ext) { uint32_t sfu = get_insn_field(insn, 23, 25); uint32_t n = get_insn_field(insn, 26, 26); uint32_t sop; push_int_modifier(hppa_ext, sfu); switch (ext) { case 0x00: sop = (get_insn_field(insn, 6, 20) << 5) | get_insn_field(insn, 27, 31); break; case 0x01: sop = get_insn_field(insn, 6, 20); break; case 0x02: sop = (get_insn_field(insn, 11, 20) << 5) | get_insn_field(insn, 27, 31); break; case 0x03: sop = (get_insn_field(insn, 16, 20) << 5) | get_insn_field(insn, 27, 31); break; default: return; } push_int_modifier(hppa_ext, sop); if (n == 1) { push_str_modifier(hppa_ext, "n"); } } static bool decode_spop(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t ext = get_insn_field(insn, 21, 22); uint32_t r2 = get_insn_field(insn, 11, 15); uint32_t r1 = get_insn_field(insn, 6, 10); uint32_t t = get_insn_field(insn, 27, 31); switch (ext) { case 0x00: break; case 0x01: CREATE_GR_REG(MI, t); break; case 0x02: CREATE_GR_REG(MI, r1); break; case 0x03: CREATE_GR_REG(MI, r2); CREATE_GR_REG(MI, r1); break; default: return false; } fill_spop_mods(insn, ext, HPPA_EXT_REF(MI)); return true; } static void fill_copr_insn_name(MCInst *MI, uint32_t insn) { uint32_t class = get_insn_field(insn, 21, 22); uint32_t uid = get_insn_field(insn, 23, 25); uint32_t subop; if (MODE_IS_HPPA_20(MI->csh->mode)) { if (uid == 0) { if (class == 0) { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_FID); return; case 0x06: MCInst_setOpcode(MI, HPPA_INS_FNEG); return; case 0x07: MCInst_setOpcode(MI, HPPA_INS_FNEGABS); return; default: break; } } else if (class == 1) { subop = get_insn_field(insn, 14, 16); if (subop != 4) { MCInst_setOpcode(MI, HPPA_INS_FCNV); return; } } else if (class == 2) { if (get_insn_bit(insn, 26) == 0) { MCInst_setOpcode(MI, HPPA_INS_FCMP); } else { MCInst_setOpcode(MI, HPPA_INS_FTEST); } return; } } } if (uid == 0) { if (class == 0) { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_COPR); return; case 0x02: MCInst_setOpcode(MI, HPPA_INS_FCPY); return; case 0x03: MCInst_setOpcode(MI, HPPA_INS_FABS); return; case 0x04: MCInst_setOpcode(MI, HPPA_INS_FSQRT); return; case 0x05: MCInst_setOpcode(MI, HPPA_INS_FRND); return; default: break; } } else if (class == 1) { subop = get_insn_field(insn, 15, 16); switch (subop) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_FCNVFF); return; case 0x01: MCInst_setOpcode(MI, HPPA_INS_FCNVXF); return; case 0x02: MCInst_setOpcode(MI, HPPA_INS_FCNVFX); return; case 0x03: MCInst_setOpcode(MI, HPPA_INS_FCNVFXT); return; default: break; } } else if (class == 2) { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_FCMP); return; case 0x01: MCInst_setOpcode(MI, HPPA_INS_FTEST); return; default: break; } } else if (class == 3) { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_FADD); return; case 0x01: MCInst_setOpcode(MI, HPPA_INS_FSUB); return; case 0x02: MCInst_setOpcode(MI, HPPA_INS_FMPY); return; case 0x03: MCInst_setOpcode(MI, HPPA_INS_FDIV); return; default: break; } } } else if (uid == 2) { subop = get_insn_field(insn, 18, 22); switch (subop) { case 0x01: MCInst_setOpcode(MI, HPPA_INS_PMDIS); return; case 0x03: MCInst_setOpcode(MI, HPPA_INS_PMENB); return; default: break; } } MCInst_setOpcode(MI, HPPA_INS_COPR); } static void fill_copr_mods(uint32_t insn, uint32_t uid, uint32_t class, hppa_ext *hppa_ext, uint32_t subop, cs_mode mode) { uint32_t n = get_insn_field(insn, 26, 26); uint32_t sf = get_insn_field(insn, 19, 20); uint32_t df = get_insn_field(insn, 17, 18); if (MODE_IS_HPPA_20(mode)) { if (uid == 0) { if (class == 0) { switch (subop) { case 0x00: return; default: break; } } else if (class == 1) { switch (subop) { case 0x00: push_str_modifier( hppa_ext, float_format_names[sf]); push_str_modifier( hppa_ext, float_format_names[df]); return; case 0x01: push_str_modifier(hppa_ext, fcnv_fixed_names[sf]); push_str_modifier( hppa_ext, float_format_names[df]); return; case 0x03: push_str_modifier(hppa_ext, "t"); // fallthrough case 0x02: push_str_modifier( hppa_ext, float_format_names[sf]); push_str_modifier(hppa_ext, fcnv_fixed_names[df]); return; case 0x05: push_str_modifier( hppa_ext, fcnv_ufixed_names[sf]); push_str_modifier( hppa_ext, float_format_names[df]); return; case 0x07: push_str_modifier(hppa_ext, "t"); // fallthrough case 0x06: push_str_modifier( hppa_ext, float_format_names[sf]); push_str_modifier( hppa_ext, fcnv_ufixed_names[df]); return; default: break; } } } } if (uid == 0) { if (class == 0) { switch (subop) { case 0x00: push_int_modifier(hppa_ext, 0); push_int_modifier(hppa_ext, 0); if (n == 1) { push_str_modifier(hppa_ext, "n"); } break; case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: push_str_modifier(hppa_ext, float_format_names[sf]); break; default: break; } } else if (class == 1) { push_str_modifier(hppa_ext, float_format_names[sf]); push_str_modifier(hppa_ext, float_format_names[df]); } else if (class == 2) { uint32_t cond = get_insn_field(insn, 27, 31); if (n == 1 && subop == 1) { push_str_modifier(hppa_ext, float_cond_names[cond]); } if (n == 0) { push_str_modifier(hppa_ext, float_format_names[sf]); push_str_modifier(hppa_ext, float_comp_names[cond]); } } else if (class == 3) { push_str_modifier(hppa_ext, float_format_names[sf]); } } else if (uid == 2) { if (n == 1) { push_str_modifier(hppa_ext, "n"); } } else { uid = get_insn_field(insn, 23, 25); uint32_t sop = (get_insn_field(insn, 6, 22) << 5) | get_insn_field(insn, 27, 31); push_int_modifier(hppa_ext, uid); push_int_modifier(hppa_ext, sop); if (n == 1) { push_str_modifier(hppa_ext, "n"); } } } static bool decode_copr(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t class = get_insn_field(insn, 21, 22); uint32_t uid = get_insn_field(insn, 23, 25); uint32_t subop; uint32_t r1 = get_insn_field(insn, 6, 10); uint32_t r2 = get_insn_field(insn, 11, 15); uint32_t t = get_insn_field(insn, 27, 31); if (MODE_IS_HPPA_20(ud->mode)) { if (uid == 0) { if (class == 0) { subop = get_insn_field(insn, 16, 18); if (subop == 0x01) { return false; } if (subop >= 0x02) { CREATE_FPR_REG(MI, r1); CREATE_FPR_REG(MI, t); } } else if (class == 1) { subop = get_insn_field(insn, 14, 16); if (subop == 0x04) { return false; } CREATE_FPR_REG(MI, r1); CREATE_FPR_REG(MI, t); } else if (class == 2) { uint32_t n = get_insn_bit(insn, 26); subop = get_insn_field(insn, 16, 18); if (n == 0) { CREATE_FPR_REG(MI, r1); CREATE_FPR_REG(MI, r2); if (subop != 0) { MCOperand_CreateImm0(MI, subop - 1); HPPA_EXT_REF(MI) ->is_alternative = true; } } else { if (subop != 1) { MCOperand_CreateImm0( MI, (subop ^ 1) - 1); HPPA_EXT_REF(MI) ->is_alternative = true; } } } else { subop = get_insn_field(insn, 16, 18); if (subop >= 4) { return false; } CREATE_FPR_REG(MI, r1); CREATE_FPR_REG(MI, r2); CREATE_FPR_REG(MI, t); } fill_copr_mods(insn, uid, class, HPPA_EXT_REF(MI), subop, ud->mode); return true; } } if (uid == 0) { if (class == 0) { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x02: case 0x03: case 0x04: case 0x05: CREATE_FPR_REG(MI, r1); CREATE_FPR_REG(MI, t); // fallthrough case 0x00: break; default: return false; } } else if (class == 1) { subop = get_insn_field(insn, 15, 16); switch (subop) { case 0x00: case 0x01: case 0x02: case 0x03: CREATE_FPR_REG(MI, r1); CREATE_FPR_REG(MI, t); break; default: return false; } } else if (class == 2) { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x00: CREATE_FPR_REG(MI, r1); CREATE_FPR_REG(MI, r2); // fallthrough case 0x01: break; default: return false; } } else { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x00: case 0x01: case 0x02: case 0x03: CREATE_FPR_REG(MI, r1); CREATE_FPR_REG(MI, r2); CREATE_FPR_REG(MI, t); break; default: return false; } } fill_copr_mods(insn, uid, class, HPPA_EXT_REF(MI), subop, ud->mode); return true; } else if (uid == 2) { subop = get_insn_field(insn, 18, 22); switch (subop) { case 0x01: case 0x03: break; default: return false; } } fill_copr_mods(insn, uid, class, HPPA_EXT_REF(MI), -1, ud->mode); return true; } static void fill_float_insn_name(MCInst *MI, uint32_t insn) { uint32_t class = get_insn_field(insn, 21, 22); uint32_t subop; if (MODE_IS_HPPA_20(MI->csh->mode)) { if (class == 0) { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x06: MCInst_setOpcode(MI, HPPA_INS_FNEG); return; case 0x07: MCInst_setOpcode(MI, HPPA_INS_FNEGABS); return; default: break; } } else if (class == 1) { subop = get_insn_field(insn, 14, 16); if (subop == 0x04) { return; } MCInst_setOpcode(MI, HPPA_INS_FCNV); return; } else if (class == 2) { MCInst_setOpcode(MI, HPPA_INS_FCMP); return; } } if (class == 0) { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x02: MCInst_setOpcode(MI, HPPA_INS_FCPY); break; case 0x03: MCInst_setOpcode(MI, HPPA_INS_FABS); break; case 0x04: MCInst_setOpcode(MI, HPPA_INS_FSQRT); break; case 0x05: MCInst_setOpcode(MI, HPPA_INS_FRND); break; default: break; } } else if (class == 1) { subop = get_insn_field(insn, 15, 16); switch (subop) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_FCNVFF); break; case 0x01: MCInst_setOpcode(MI, HPPA_INS_FCNVXF); break; case 0x02: MCInst_setOpcode(MI, HPPA_INS_FCNVFX); break; case 0x03: MCInst_setOpcode(MI, HPPA_INS_FCNVFXT); break; default: break; } } else if (class == 2) { subop = get_insn_field(insn, 16, 18); if (subop == 0x00) { MCInst_setOpcode(MI, HPPA_INS_FCMP); } } else if (class == 3) { subop = get_insn_field(insn, 16, 18); uint32_t fixed = get_insn_field(insn, 23, 23); if (fixed == 0) { switch (subop) { case 0x00: MCInst_setOpcode(MI, HPPA_INS_FADD); break; case 0x01: MCInst_setOpcode(MI, HPPA_INS_FSUB); break; case 0x02: MCInst_setOpcode(MI, HPPA_INS_FMPY); break; case 0x03: MCInst_setOpcode(MI, HPPA_INS_FDIV); break; default: break; } } else { if (subop == 0x02) { MCInst_setOpcode(MI, HPPA_INS_XMPYU); } } } } static void fill_float_mods(uint32_t insn, uint32_t class, hppa_ext *hppa_ext, uint32_t subop, cs_mode mode) { uint32_t sf = get_insn_field(insn, 19, 20); uint32_t df = get_insn_field(insn, 17, 18); if (MODE_IS_HPPA_20(mode)) { if (class == 1) { switch (subop) { case 0x00: push_str_modifier(hppa_ext, float_format_names[sf]); push_str_modifier(hppa_ext, float_format_names[df]); return; case 0x01: push_str_modifier(hppa_ext, fcnv_fixed_names[sf]); push_str_modifier(hppa_ext, float_format_names[df]); return; case 0x03: push_str_modifier(hppa_ext, "t"); // fallthrough case 0x02: push_str_modifier(hppa_ext, float_format_names[sf]); push_str_modifier(hppa_ext, fcnv_fixed_names[df]); return; case 0x05: push_str_modifier(hppa_ext, fcnv_ufixed_names[sf]); push_str_modifier(hppa_ext, float_format_names[df]); return; case 0x07: push_str_modifier(hppa_ext, "t"); // fallthrough case 0x06: push_str_modifier(hppa_ext, float_format_names[sf]); push_str_modifier(hppa_ext, fcnv_ufixed_names[df]); return; default: return; } } } if (class == 0) { uint32_t fmt = get_insn_field(insn, 19, 20); push_str_modifier(hppa_ext, float_format_names[fmt]); } else if (class == 1) { push_str_modifier(hppa_ext, float_format_names[sf]); push_str_modifier(hppa_ext, float_format_names[df]); } else if (class == 2) { uint32_t fmt = get_insn_field(insn, 20, 20); uint32_t cond = get_insn_field(insn, 27, 31); push_str_modifier(hppa_ext, float_format_names[fmt]); push_str_modifier(hppa_ext, float_cond_names[cond]); } else if (class == 3) { if (get_insn_field(insn, 23, 23) == 0) { uint32_t fmt = get_insn_field(insn, 20, 20); push_str_modifier(hppa_ext, float_format_names[fmt]); } } } static bool decode_float(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t class = get_insn_field(insn, 21, 22); uint32_t subop; uint32_t r1 = get_insn_field(insn, 6, 10); uint32_t r1_fpe = get_insn_bit(insn, 24); uint32_t r2 = get_insn_field(insn, 11, 15); uint32_t r2_fpe = get_insn_bit(insn, 19); uint32_t t = get_insn_field(insn, 27, 31); uint32_t t_fpe = get_insn_bit(insn, 25); if (MODE_IS_HPPA_20(ud->mode)) { if (class == 0) { subop = get_insn_field(insn, 16, 18); if (subop >= 0x02) { create_float_reg_spec(MI, r1, r1_fpe); create_float_reg_spec(MI, t, t_fpe); fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop, ud->mode); return true; } } else if (class == 1) { subop = get_insn_field(insn, 14, 16); if (subop == 0x04) { return false; } create_float_reg_spec(MI, r1, r1_fpe); create_float_reg_spec(MI, t, t_fpe); fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop, ud->mode); return true; } else if (class == 2) { subop = get_insn_field(insn, 16, 18); create_float_reg_spec(MI, r1, r1_fpe); create_float_reg_spec(MI, r2, r2_fpe); if (subop != 0) { MCOperand_CreateImm0(MI, subop - 1); } fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop, ud->mode); return true; } } if (class == 0) { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x02: case 0x03: case 0x04: case 0x05: create_float_reg_spec(MI, r1, r1_fpe); create_float_reg_spec(MI, t, t_fpe); fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop, ud->mode); return true; default: return false; } } else if (class == 1) { subop = get_insn_field(insn, 15, 16); if (subop <= 0x03) { create_float_reg_spec(MI, r1, r1_fpe); create_float_reg_spec(MI, t, t_fpe); fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop, ud->mode); return true; } } else if (class == 2) { subop = get_insn_field(insn, 16, 18); switch (subop) { case 0x00: create_float_reg_spec(MI, r1, r1_fpe); create_float_reg_spec(MI, r2, r2_fpe); fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop, ud->mode); return true; default: return false; } } else if (class == 3) { subop = get_insn_field(insn, 16, 18); uint32_t fixed = get_insn_field(insn, 23, 23); if ((fixed == 0 && subop <= 0x03) || (fixed == 1 && subop == 0x02)) { create_float_reg_spec(MI, r1, r1_fpe); create_float_reg_spec(MI, r2, r2_fpe); create_float_reg_spec(MI, t, t_fpe); fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop, ud->mode); return true; } return false; } return false; } static void fill_fpfused_insn_name(MCInst *MI, uint32_t insn) { uint32_t subop = get_insn_bit(insn, 26); if (subop == 0x00) { MCInst_setOpcode(MI, HPPA_INS_FMPYFADD); } else { MCInst_setOpcode(MI, HPPA_INS_FMPYNFADD); } } static void fill_fpfused_mods(uint32_t insn, hppa_ext *hppa_ext) { uint32_t fmt = get_insn_bit(insn, 20); push_str_modifier(hppa_ext, float_format_names[fmt]); } static bool decode_fpfused(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t r1 = get_insn_field(insn, 6, 10); uint32_t r1_fpe = get_insn_bit(insn, 24); uint32_t r2 = get_insn_field(insn, 11, 15); uint32_t r2_fpe = get_insn_bit(insn, 19); uint32_t ra = (get_insn_field(insn, 16, 18) << 2) | get_insn_field(insn, 21, 22); uint32_t ra_fpe = get_insn_bit(insn, 23); uint32_t t = get_insn_field(insn, 27, 31); uint32_t t_fpe = get_insn_bit(insn, 25); create_float_reg_spec(MI, r1, r1_fpe); create_float_reg_spec(MI, r2, r2_fpe); create_float_reg_spec(MI, ra, ra_fpe); create_float_reg_spec(MI, t, t_fpe); fill_fpfused_mods(insn, HPPA_EXT_REF(MI)); return true; } static void fill_action_and_branch_insn_name(MCInst *MI, uint32_t opcode) { if (MODE_IS_HPPA_20(MI->csh->mode)) { switch (opcode) { case HPPA_OP_TYPE_CMPBT: case HPPA_OP_TYPE_CMPBF: case HPPA_OP_TYPE_CMPBDWT: case HPPA_OP_TYPE_CMPBDWF: MCInst_setOpcode(MI, HPPA_INS_CMPB); return; case HPPA_OP_TYPE_CMPIBT: case HPPA_OP_TYPE_CMPIBF: case HPPA_OP_TYPE_CMPIBDW: MCInst_setOpcode(MI, HPPA_INS_CMPIB); return; case HPPA_OP_TYPE_ADDBT: case HPPA_OP_TYPE_ADDBF: MCInst_setOpcode(MI, HPPA_INS_ADDB); return; case HPPA_OP_TYPE_ADDIBT: case HPPA_OP_TYPE_ADDIBF: MCInst_setOpcode(MI, HPPA_INS_ADDIB); return; case HPPA_OP_TYPE_BBS: MCInst_setOpcode(MI, HPPA_INS_BB); return; default: break; } } switch (opcode) { case HPPA_OP_TYPE_CMPBT: MCInst_setOpcode(MI, HPPA_INS_COMBT); break; case HPPA_OP_TYPE_CMPBF: MCInst_setOpcode(MI, HPPA_INS_COMBF); break; case HPPA_OP_TYPE_CMPIBT: MCInst_setOpcode(MI, HPPA_INS_COMIBT); break; case HPPA_OP_TYPE_CMPIBF: MCInst_setOpcode(MI, HPPA_INS_COMIBF); break; case HPPA_OP_TYPE_ADDBT: MCInst_setOpcode(MI, HPPA_INS_ADDBT); break; case HPPA_OP_TYPE_ADDBF: MCInst_setOpcode(MI, HPPA_INS_ADDBF); break; case HPPA_OP_TYPE_ADDIBT: MCInst_setOpcode(MI, HPPA_INS_ADDIBT); break; case HPPA_OP_TYPE_ADDIBF: MCInst_setOpcode(MI, HPPA_INS_ADDIBF); break; case HPPA_OP_TYPE_MOVB: MCInst_setOpcode(MI, HPPA_INS_MOVB); break; case HPPA_OP_TYPE_MOVIB: MCInst_setOpcode(MI, HPPA_INS_MOVIB); break; case HPPA_OP_TYPE_BBS: MCInst_setOpcode(MI, HPPA_INS_BVB); break; case HPPA_OP_TYPE_BB: MCInst_setOpcode(MI, HPPA_INS_BB); break; default: break; } } static void fill_action_and_branch_mods(uint32_t insn, uint32_t opcode, hppa_ext *hppa_ext, cs_mode mode) { uint32_t cond = get_insn_field(insn, 16, 18); uint32_t n = get_insn_bit(insn, 30); uint32_t d = get_insn_bit(insn, 18); if (MODE_IS_HPPA_20(mode)) { switch (opcode) { case HPPA_OP_TYPE_CMPBT: case HPPA_OP_TYPE_CMPIBT: push_str_modifier(hppa_ext, compare_cond_names[cond]); break; case HPPA_OP_TYPE_CMPBF: case HPPA_OP_TYPE_CMPIBF: push_str_modifier(hppa_ext, compare_cond_names[cond + 8]); break; case HPPA_OP_TYPE_CMPBDWT: push_str_modifier(hppa_ext, compare_cond_64_names[cond]); break; case HPPA_OP_TYPE_CMPBDWF: push_str_modifier(hppa_ext, compare_cond_64_names[cond + 8]); break; case HPPA_OP_TYPE_CMPIBDW: push_str_modifier(hppa_ext, cmpib_cond_64_names[cond]); break; case HPPA_OP_TYPE_ADDBT: case HPPA_OP_TYPE_ADDIBT: if (MODE_IS_HPPA_20W(mode)) { push_str_modifier(hppa_ext, wide_add_cond_names[cond]); } else { push_str_modifier(hppa_ext, add_cond_names[cond]); } break; case HPPA_OP_TYPE_ADDBF: case HPPA_OP_TYPE_ADDIBF: if (MODE_IS_HPPA_20W(mode)) { push_str_modifier( hppa_ext, wide_add_cond_names[cond + 8]); } else { push_str_modifier(hppa_ext, add_cond_names[cond + 8]); } break; case HPPA_OP_TYPE_BBS: case HPPA_OP_TYPE_BB: if (d == 0) { push_str_modifier(hppa_ext, shift_cond_names[cond]); } else { push_str_modifier(hppa_ext, shift_cond_64_names[cond]); } break; case HPPA_OP_TYPE_MOVB: case HPPA_OP_TYPE_MOVIB: push_str_modifier(hppa_ext, shift_cond_names[cond]); break; default: break; } if (n == 1) { push_str_modifier(hppa_ext, "n"); } return; } switch (opcode) { case HPPA_OP_TYPE_CMPBT: case HPPA_OP_TYPE_CMPBF: case HPPA_OP_TYPE_CMPIBT: case HPPA_OP_TYPE_CMPIBF: push_str_modifier(hppa_ext, compare_cond_names[cond]); break; case HPPA_OP_TYPE_ADDBT: case HPPA_OP_TYPE_ADDBF: case HPPA_OP_TYPE_ADDIBT: case HPPA_OP_TYPE_ADDIBF: push_str_modifier(hppa_ext, add_cond_names[cond]); break; case HPPA_OP_TYPE_MOVB: case HPPA_OP_TYPE_MOVIB: case HPPA_OP_TYPE_BBS: case HPPA_OP_TYPE_BB: push_str_modifier(hppa_ext, shift_cond_names[cond]); break; default: break; } if (n == 1) { push_str_modifier(hppa_ext, "n"); } } static bool fill_action_and_branch(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; uint32_t r1 = get_insn_field(insn, 6, 10); uint32_t r2 = get_insn_field(insn, 11, 15); if (MODE_IS_HPPA_20(ud->mode)) { switch (opcode) { case HPPA_OP_TYPE_CMPBT: case HPPA_OP_TYPE_CMPBF: case HPPA_OP_TYPE_CMPBDWT: case HPPA_OP_TYPE_CMPBDWF: case HPPA_OP_TYPE_ADDBT: case HPPA_OP_TYPE_ADDBF: case HPPA_OP_TYPE_MOVB: CREATE_GR_REG(MI, r2); CREATE_GR_REG(MI, r1); MCOperand_CreateImm0(MI, extract_12(insn)); break; case HPPA_OP_TYPE_CMPIBT: case HPPA_OP_TYPE_CMPIBF: case HPPA_OP_TYPE_CMPIBDW: case HPPA_OP_TYPE_ADDIBT: case HPPA_OP_TYPE_ADDIBF: case HPPA_OP_TYPE_MOVIB: MCOperand_CreateImm0(MI, LowSignExtend64(r2, 5)); CREATE_GR_REG(MI, r1); MCOperand_CreateImm0(MI, extract_12(insn)); break; case HPPA_OP_TYPE_BBS: case HPPA_OP_TYPE_BB: CREATE_GR_REG(MI, r2); if ((opcode & 1) == 1) { MCOperand_CreateImm0(MI, r1); } else { CREATE_CR_REG(MI, 11); } MCOperand_CreateImm0(MI, extract_12(insn)); break; default: return false; } fill_action_and_branch_mods(insn, opcode, HPPA_EXT_REF(MI), ud->mode); return true; } if ((opcode & 1) == 0 || opcode == HPPA_OP_TYPE_BB) { CREATE_GR_REG(MI, r2); } else { MCOperand_CreateImm0(MI, LowSignExtend64(r2, 5)); } if (opcode == HPPA_OP_TYPE_BB) { MCOperand_CreateImm0(MI, r1); } else if (opcode != HPPA_OP_TYPE_BBS) { CREATE_GR_REG(MI, r1); } MCOperand_CreateImm0(MI, extract_12(insn)); fill_action_and_branch_mods(insn, opcode, HPPA_EXT_REF(MI), ud->mode); return true; } static void fill_load_insn_name(MCInst *MI, uint32_t opcode) { switch (opcode) { case HPPA_OP_TYPE_LDB: MCInst_setOpcode(MI, HPPA_INS_LDB); break; case HPPA_OP_TYPE_LDH: MCInst_setOpcode(MI, HPPA_INS_LDH); break; case HPPA_OP_TYPE_LDW: MCInst_setOpcode(MI, HPPA_INS_LDW); break; case HPPA_OP_TYPE_LDWM: if (MODE_IS_HPPA_20(MI->csh->mode)) { MCInst_setOpcode(MI, HPPA_INS_LDW); } else { MCInst_setOpcode(MI, HPPA_INS_LDWM); } break; default: break; } } static void fill_store_insn_name(MCInst *MI, uint32_t opcode) { switch (opcode) { case HPPA_OP_TYPE_STB: MCInst_setOpcode(MI, HPPA_INS_STB); break; case HPPA_OP_TYPE_STH: MCInst_setOpcode(MI, HPPA_INS_STH); break; case HPPA_OP_TYPE_STW: MCInst_setOpcode(MI, HPPA_INS_STW); break; case HPPA_OP_TYPE_STWM: if (MODE_IS_HPPA_20(MI->csh->mode)) { MCInst_setOpcode(MI, HPPA_INS_STW); } else { MCInst_setOpcode(MI, HPPA_INS_STWM); } break; default: break; } } static bool decode_cmpclr(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t cond = (get_insn_bit(insn, 19) << 3) | get_insn_field(insn, 16, 18); uint32_t d = get_insn_bit(insn, 20); if (MODE_IS_HPPA_20(ud->mode)) { MCInst_setOpcode(MI, HPPA_INS_CMPICLR); } else { MCInst_setOpcode(MI, HPPA_INS_COMICLR); } MCOperand_CreateImm0(MI, LowSignExtend64(get_insn_field(insn, 21, 31), 11)); CREATE_GR_REG(MI, get_insn_field(insn, 6, 10)); CREATE_GR_REG(MI, get_insn_field(insn, 11, 15)); if (d == 0) { push_str_modifier(HPPA_EXT_REF(MI), compare_cond_names[cond]); } else { push_str_modifier(HPPA_EXT_REF(MI), compare_cond_64_names[cond]); } return true; } static bool decode_be(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; uint32_t n = get_insn_bit(insn, 30); bool mode = MODE_IS_HPPA_20(ud->mode); if (opcode == HPPA_OP_TYPE_BLE) { if (!mode) { MCInst_setOpcode(MI, HPPA_INS_BLE); } else { MCInst_setOpcode(MI, HPPA_INS_BE); push_str_modifier(HPPA_EXT_REF(MI), "l"); HPPA_EXT_REF(MI)->is_alternative = true; } } else { MCInst_setOpcode(MI, HPPA_INS_BE); } MCOperand_CreateImm0(MI, extract_17(insn)); CREATE_SR_REG(MI, extract_3(insn)); CREATE_GR_REG(MI, get_insn_field(insn, 6, 10)); if (opcode == HPPA_OP_TYPE_BLE && mode) { CREATE_SR_REG(MI, 0); CREATE_GR_REG(MI, 31); } if (n == 1) { push_str_modifier(HPPA_EXT_REF(MI), "n"); } return true; } static bool decode_float_ldst(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; uint32_t a = get_insn_bit(insn, 29); uint32_t disp = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); disp &= ~3; if (opcode == HPPA_OP_TYPE_FLDW) { MCInst_setOpcode(MI, HPPA_INS_FLDW); MCOperand_CreateImm0(MI, disp); CREATE_SR_REG(MI, get_insn_field(insn, 16, 17)); CREATE_GR_REG(MI, get_insn_field(insn, 6, 10)); CREATE_FPR_REG(MI, get_insn_field(insn, 11, 15)); } else { MCInst_setOpcode(MI, HPPA_INS_FSTW); CREATE_FPR_REG(MI, get_insn_field(insn, 11, 15)); MCOperand_CreateImm0(MI, disp); CREATE_SR_REG(MI, get_insn_field(insn, 16, 17)); CREATE_GR_REG(MI, get_insn_field(insn, 6, 10)); } if (a == 0) { push_str_modifier(HPPA_EXT_REF(MI), "ma"); } else { push_str_modifier(HPPA_EXT_REF(MI), "mb"); } return true; } static bool decode_fmpy(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; uint32_t rm1 = get_insn_field(insn, 6, 10); uint32_t rm2 = get_insn_field(insn, 11, 15); uint32_t ta = get_insn_field(insn, 16, 20); uint32_t ra = get_insn_field(insn, 21, 25); uint32_t tm = get_insn_field(insn, 27, 31); uint32_t fmt = get_insn_field(insn, 26, 26); if (opcode == HPPA_OP_TYPE_FMPYADD) { MCInst_setOpcode(MI, HPPA_INS_FMPYADD); } else { MCInst_setOpcode(MI, HPPA_INS_FMPYSUB); } if (fmt == 0) { push_str_modifier(HPPA_EXT_REF(MI), "dbl"); CREATE_FPR_REG(MI, rm1); CREATE_FPR_REG(MI, rm2); CREATE_FPR_REG(MI, tm); CREATE_FPR_REG(MI, ra); CREATE_FPR_REG(MI, ta); } else { push_str_modifier(HPPA_EXT_REF(MI), "sgl"); CREATE_SP_FPR_REG(MI, rm1); CREATE_SP_FPR_REG(MI, rm2); CREATE_SP_FPR_REG(MI, tm); CREATE_SP_FPR_REG(MI, ra); CREATE_SP_FPR_REG(MI, ta); } return true; } static bool decode_load(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; if (MODE_IS_HPPA_20(ud->mode)) { uint32_t d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); if (opcode == HPPA_OP_TYPE_LDWM) { if (d < 0) { push_str_modifier(HPPA_EXT_REF(MI), "mb"); } else { push_str_modifier(HPPA_EXT_REF(MI), "ma"); } } MCOperand_CreateImm0(MI, d); } else { MCOperand_CreateImm0(MI, extract_14(insn)); } CREATE_SR_REG(MI, get_insn_field(insn, 16, 17)); CREATE_GR_REG(MI, get_insn_field(insn, 6, 10)); CREATE_GR_REG(MI, get_insn_field(insn, 11, 15)); return true; } static bool decode_store(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; CREATE_GR_REG(MI, get_insn_field(insn, 11, 15)); if (MODE_IS_HPPA_20(ud->mode)) { uint32_t d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); if (opcode == HPPA_OP_TYPE_STWM) { if (d < 0) { push_str_modifier(HPPA_EXT_REF(MI), "mb"); } else { push_str_modifier(HPPA_EXT_REF(MI), "ma"); } } MCOperand_CreateImm0(MI, d); } else { MCOperand_CreateImm0(MI, extract_14(insn)); } CREATE_SR_REG(MI, get_insn_field(insn, 16, 17)); CREATE_GR_REG(MI, get_insn_field(insn, 6, 10)); return true; } static bool getInstruction(const cs_struct *ud, const uint8_t *code, size_t code_len, MCInst *MI) { if (code_len < 4) return false; MCInst_clear(MI); uint32_t full_insn = readBytes32(MI, code); uint8_t opcode = full_insn >> 26; if (MODE_IS_HPPA_20(ud->mode)) { switch (opcode) { case HPPA_OP_TYPE_LOADDW: case HPPA_OP_TYPE_STOREDW: fill_ldst_dw_insn_name(MI, full_insn); return decode_ldst_dw(ud, MI, full_insn); case HPPA_OP_TYPE_LOADW: case HPPA_OP_TYPE_STOREW: fill_ldst_w_insn_name(MI, full_insn); return decode_ldst_w(ud, MI, full_insn); case HPPA_OP_TYPE_SHEXDEP2: MCInst_setOpcode(MI, HPPA_INS_EXTRD); return decode_shexdep2(MI, full_insn); case HPPA_OP_TYPE_SHEXDEP3: case HPPA_OP_TYPE_SHEXDEP4: return decode_shexdep3(ud, MI, full_insn); case HPPA_OP_TYPE_MULTMED: fill_multmed_insn_name(MI, full_insn); return decode_multmed(MI, full_insn); case HPPA_OP_TYPE_FPFUSED: fill_fpfused_insn_name(MI, full_insn); return decode_fpfused(ud, MI, full_insn); case HPPA_OP_TYPE_FLDW: case HPPA_OP_TYPE_FSTW: return decode_float_ldst(ud, MI, full_insn); case HPPA_OP_TYPE_CMPBDWT: case HPPA_OP_TYPE_CMPBDWF: case HPPA_OP_TYPE_CMPIBDW: fill_action_and_branch_insn_name(MI, opcode); return fill_action_and_branch(ud, MI, full_insn); default: break; } } switch (opcode) { case HPPA_OP_TYPE_SYSOP: fill_sysop_insn_name(MI, full_insn); return decode_sysop(ud, MI, full_insn); case HPPA_OP_TYPE_MEMMGMT: fill_memmgmt_insn_name(MI, full_insn); return decode_memmgmt(ud, MI, full_insn); case HPPA_OP_TYPE_ALU: fill_alu_insn_name(MI, full_insn); return decode_alu(ud, MI, full_insn); case HPPA_OP_TYPE_IDXMEM: fill_idxmem_insn_name(MI, full_insn); return decode_idxmem(ud, MI, full_insn); case HPPA_OP_TYPE_ADDIT: case HPPA_OP_TYPE_ADDI: case HPPA_OP_TYPE_SUBI: fill_arith_imm_insn_name(MI, full_insn); return decode_arith_imm(ud, MI, full_insn); case HPPA_OP_TYPE_SHEXDEP0: fill_shexdep0_insn_name(MI, full_insn); return decode_shexdep0(ud, MI, full_insn); case HPPA_OP_TYPE_SHEXDEP1: fill_shexdep1_insn_name(MI, full_insn); return decode_shexdep1(ud, MI, full_insn); case HPPA_OP_TYPE_BRANCH: fill_branch_insn_name(MI, full_insn); return decode_branch(ud, MI, full_insn); case HPPA_OP_TYPE_COPRW: case HPPA_OP_TYPE_COPRDW: fill_corpdw_insn_name(MI, full_insn); return decode_corpdw(ud, MI, full_insn); case HPPA_OP_TYPE_SPOP: fill_spop_insn_name(MI, full_insn); return decode_spop(ud, MI, full_insn); case HPPA_OP_TYPE_COPR: fill_copr_insn_name(MI, full_insn); return decode_copr(ud, MI, full_insn); case HPPA_OP_TYPE_FLOAT: fill_float_insn_name(MI, full_insn); return decode_float(ud, MI, full_insn); case HPPA_OP_TYPE_DIAG: MCInst_setOpcode(MI, HPPA_INS_DIAG); MCOperand_CreateImm0(MI, get_insn_field(full_insn, 6, 31)); return true; case HPPA_OP_TYPE_FMPYADD: case HPPA_OP_TYPE_FMPYSUB: return decode_fmpy(ud, MI, full_insn); case HPPA_OP_TYPE_LDIL: case HPPA_OP_TYPE_ADDIL: if (opcode == HPPA_OP_TYPE_LDIL) { MCInst_setOpcode(MI, HPPA_INS_LDIL); } else { MCInst_setOpcode(MI, HPPA_INS_ADDIL); } MCOperand_CreateImm0(MI, extract_21(full_insn)); CREATE_GR_REG(MI, get_insn_field(full_insn, 6, 10)); return true; case HPPA_OP_TYPE_LDO: MCInst_setOpcode(MI, HPPA_INS_LDO); if (MODE_IS_HPPA_20(ud->mode)) { MCOperand_CreateImm0( MI, extract_16(full_insn, MODE_IS_HPPA_20W(ud->mode))); } else { MCOperand_CreateImm0(MI, extract_14(full_insn)); } CREATE_GR_REG(MI, get_insn_field(full_insn, 6, 10)); CREATE_GR_REG(MI, get_insn_field(full_insn, 11, 15)); return true; case HPPA_OP_TYPE_LDB: case HPPA_OP_TYPE_LDH: case HPPA_OP_TYPE_LDW: case HPPA_OP_TYPE_LDWM: fill_load_insn_name(MI, opcode); return decode_load(ud, MI, full_insn); case HPPA_OP_TYPE_STB: case HPPA_OP_TYPE_STH: case HPPA_OP_TYPE_STW: case HPPA_OP_TYPE_STWM: fill_store_insn_name(MI, opcode); return decode_store(ud, MI, full_insn); case HPPA_OP_TYPE_CMPBT: case HPPA_OP_TYPE_CMPBF: case HPPA_OP_TYPE_ADDBT: case HPPA_OP_TYPE_ADDBF: case HPPA_OP_TYPE_MOVB: case HPPA_OP_TYPE_CMPIBT: case HPPA_OP_TYPE_CMPIBF: case HPPA_OP_TYPE_ADDIBT: case HPPA_OP_TYPE_ADDIBF: case HPPA_OP_TYPE_MOVIB: case HPPA_OP_TYPE_BBS: case HPPA_OP_TYPE_BB: fill_action_and_branch_insn_name(MI, opcode); return fill_action_and_branch(ud, MI, full_insn); case HPPA_OP_TYPE_CMPICLR: return decode_cmpclr(ud, MI, full_insn); case HPPA_OP_TYPE_BE: case HPPA_OP_TYPE_BLE: return decode_be(ud, MI, full_insn); default: return false; } } void init_details(MCInst *MI) { cs_detail *detail = get_detail(MI); if (detail) { memset(detail, 0, offsetof(cs_detail, hppa) + sizeof(cs_hppa)); } } bool HPPA_getInstruction(csh ud, const uint8_t *code, size_t code_len, MCInst *instr, uint16_t *size, uint64_t address, void *info) { cs_struct *cs = (cs_struct *)ud; init_details(instr); if (!getInstruction(cs, code, code_len, instr)) { *size = 0; return false; } *size = 4; return true; } #endif