From e255d6e0c395f07c48b0d40d419c6432bbb2919b Mon Sep 17 00:00:00 2001 From: Sunny Shah Date: Thu, 6 Oct 2016 11:11:47 -0500 Subject: [PATCH] Added ability to convert the ARM64 SIMD/FP registers between ROSE(semantics) and Dyninst. - getROSERegister() supports computing the different values of a RegisterDescriptor for ARM64 SIMD/FP registers - RegisterDescriptors for all accessible parts of a SIMD/FP register (8-bit, 16-bit, 32-bit, upper and lower 64-bit and 128-bit) are added to the RegisterDictionary for ARM64 in ROSE semantics - SymEvalSemantics now converts from SIMD/FP registers to Dyninst::MachRegisters. --- common/src/dyn_regs.C | 24 +++++++ dataflowAPI/rose/semantics/Registers.C | 69 +++++++++++++------ dataflowAPI/rose/semantics/SymEvalSemantics.C | 44 ++++++++---- external/rose/armv8InstructionEnum.h | 36 ++++++++++ 4 files changed, 139 insertions(+), 34 deletions(-) diff --git a/common/src/dyn_regs.C b/common/src/dyn_regs.C index ab0cc1a7d7..b253b6163b 100644 --- a/common/src/dyn_regs.C +++ b/common/src/dyn_regs.C @@ -870,6 +870,30 @@ void MachRegister::getROSERegister(int &c, int &n, int &p) } } break; + case aarch64::FPR: { + c = armv8_regclass_simd_fpr; + + int firstRegId; + switch(reg & 0xFF00) { + case aarch64::Q_REG: firstRegId = (aarch64::q0 & 0xFF); + break; + case aarch64::HQ_REG: firstRegId = (aarch64::hq0 & 0xFF); + p = 64; + break; + case aarch64::FULL: firstRegId = (aarch64::d0 & 0xFF); + break; + case aarch64::D_REG: firstRegId = (aarch64::s0 & 0xFF); + break; + case aarch64::W_REG: firstRegId = (aarch64::h0 & 0xFF); + break; + case aarch64::B_REG: firstRegId = (aarch64::b0 & 0xFF); + break; + default:assert(!"invalid register subcategory for ARM64!"); + break; + } + n = armv8_simdfpr_v0 + (baseID - firstRegId); + } + break; case aarch64::FLAG: { c = armv8_regclass_pstate; n = 0; diff --git a/dataflowAPI/rose/semantics/Registers.C b/dataflowAPI/rose/semantics/Registers.C index f167de350e..bf0d3943d7 100644 --- a/dataflowAPI/rose/semantics/Registers.C +++ b/dataflowAPI/rose/semantics/Registers.C @@ -648,31 +648,58 @@ RegisterDictionary::print(std::ostream &o) const { const RegisterDictionary * RegisterDictionary::dictionary_armv8() { static RegisterDictionary *regs = NULL; - if(!regs) { + if (!regs) { regs = new RegisterDictionary("armv8"); - /* All 60 variations (32- and 64-bit) of the 32 general purpose registers */ - for(unsigned idx = 0; idx < 31; idx++) { - regs->insert("x"+StringUtility::numberToString(idx), armv8_regclass_gpr, armv8_gpr_r0 + idx, 0, 64); - regs->insert("w"+StringUtility::numberToString(idx), armv8_regclass_gpr, armv8_gpr_r0 + idx, 0, 32); + /* All 60 variations (32- and 64-bit) of the 32 general purpose registers */ + for (unsigned idx = 0; idx < 31; idx++) { + regs->insert("x" + StringUtility::numberToString(idx), armv8_regclass_gpr, armv8_gpr_r0 + idx, 0, 64); + regs->insert("w" + StringUtility::numberToString(idx), armv8_regclass_gpr, armv8_gpr_r0 + idx, 0, 32); } - /* 32-bit section of the stack pointer register */ - regs->insert("wsp", armv8_regclass_sp, 0, 0, 32); - /* Complete stack pointer regiser */ - regs->insert("sp", armv8_regclass_sp, 0, 0, 64); - - /* 64-bit program counter register */ - regs->insert("pc", armv8_regclass_pc, 0, 0, 64); - - /* 32-bit pstate register and the four relevant flags.*/ - /* Each flag is added as a separate register for individual access. Only allowed minor is 0 (since there is only one pstate register); - * the different offsets indicate the positions of the flags within the pstate register. */ - regs->insert("pstate", armv8_regclass_pstate, 0, armv8_pstatefield_pstate, 32); - regs->insert("n", armv8_regclass_pstate, 0, armv8_pstatefield_n, 1); - regs->insert("z", armv8_regclass_pstate, 0, armv8_pstatefield_z, 1); - regs->insert("c", armv8_regclass_pstate, 0, armv8_pstatefield_c, 1); - regs->insert("v", armv8_regclass_pstate, 0, armv8_pstatefield_v, 1); + /* We have 32 SIMD/FP registers V0 - V31. In ARMv8-A, all of these are 128 bits wide. + * Not considering those instructions that treat each of these registers as an array of fixed-length units, + * each SIMD/FP register is divided can be accessed as the following: + * - A 128-bit register (Q0 - Q31) + * - A 64-bit register with its LSB being bit 0 of the register (D0 - D31) + * - A 64-bit register with its LDB being bit 64 of the register (HQ0 - HQ31) + * - A 32-bit register (S0 - S31) + * - A 16-bit register (H0 - H31) + * - An 8-bit register (B0 - B31) */ + for(unsigned idx = 0; idx < 32; idx++) { + /* 128-bit parts of V0 - V31 */ + regs->insert("q" + StringUtility::numberToString(idx), armv8_regclass_simd_fpr, armv8_simdfpr_v0 + idx, 0, 128); + + /* 64-bit parts of V0 - V31 */ + regs->insert("d" + StringUtility::numberToString(idx), armv8_regclass_simd_fpr, armv8_simdfpr_v0 + idx, 0, 64); + regs->insert("hq" + StringUtility::numberToString(idx), armv8_regclass_simd_fpr, armv8_simdfpr_v0 + idx, 64, 64); + + /* 32-bit parts of V0 - V31 */ + regs->insert("s" + StringUtility::numberToString(idx), armv8_regclass_simd_fpr, armv8_simdfpr_v0 + idx, 0, 32); + + /* 16-bit parts of V0 - V31 */ + regs->insert("h" + StringUtility::numberToString(idx), armv8_regclass_simd_fpr, armv8_simdfpr_v0 + idx, 0, 16); + + /* 8-bit parts of V0 - V31 */ + regs->insert("b" + StringUtility::numberToString(idx), armv8_regclass_simd_fpr, armv8_simdfpr_v0 + idx, 0, 8); + } + + /* 32-bit section of the stack pointer register */ + regs->insert("wsp", armv8_regclass_sp, 0, 0, 32); + /* Complete stack pointer regiser */ + regs->insert("sp", armv8_regclass_sp, 0, 0, 64); + + /* 64-bit program counter register */ + regs->insert("pc", armv8_regclass_pc, 0, 0, 64); + + /* 32-bit pstate register and the four relevant flags.*/ + /* Each flag is added as a separate register for individual access. Only allowed minor is 0 (since there is only one pstate register); + * the different offsets indicate the positions of the flags within the pstate register. */ + regs->insert("pstate", armv8_regclass_pstate, 0, armv8_pstatefield_pstate, 32); + regs->insert("n", armv8_regclass_pstate, 0, armv8_pstatefield_n, 1); + regs->insert("z", armv8_regclass_pstate, 0, armv8_pstatefield_z, 1); + regs->insert("c", armv8_regclass_pstate, 0, armv8_pstatefield_c, 1); + regs->insert("v", armv8_regclass_pstate, 0, armv8_pstatefield_v, 1); } return regs; } diff --git a/dataflowAPI/rose/semantics/SymEvalSemantics.C b/dataflowAPI/rose/semantics/SymEvalSemantics.C index c566a86079..ee1cd2215f 100644 --- a/dataflowAPI/rose/semantics/SymEvalSemantics.C +++ b/dataflowAPI/rose/semantics/SymEvalSemantics.C @@ -53,11 +53,7 @@ void SymEvalSemantics::StateARM64::writeMemory(const BaseSemantics::SValuePtr &a BaseSemantics::SValuePtr SymEvalSemantics::RegisterStateARM64::readRegister(const RegisterDescriptor ®, Dyninst::Address addr) { - if(reg.get_major() != armv8_regclass_simd_fpr) { - return SymEvalSemantics::SValue::instance(wrap(convert(reg), addr)); - } else { - ASSERT_not_implemented("readRegister not yet implemented for categories other than GPR"); - } + return SymEvalSemantics::SValue::instance(wrap(convert(reg), addr)); } BaseSemantics::SValuePtr SymEvalSemantics::RegisterStateARM64::readRegister(const RegisterDescriptor ®, @@ -70,14 +66,10 @@ void SymEvalSemantics::RegisterStateARM64::writeRegister(const RegisterDescripto const BaseSemantics::SValuePtr &value, Dyninst::DataflowAPI::Result_t &res, std::map &aaMap) { - if(reg.get_major() != armv8_regclass_simd_fpr) { - std::map::iterator i = aaMap.find(convert(reg)); - if (i != aaMap.end()) { - SymEvalSemantics::SValuePtr value_ = SymEvalSemantics::SValue::promote(value); - res[i->second] = value_->get_expression(); - } - } else { - ASSERT_not_implemented("writeRegister not yet implemented for categories other than GPR"); + std::map::iterator i = aaMap.find(convert(reg)); + if (i != aaMap.end()) { + SymEvalSemantics::SValuePtr value_ = SymEvalSemantics::SValue::promote(value); + res[i->second] = value_->get_expression(); } } @@ -105,6 +97,32 @@ Dyninst::Absloc SymEvalSemantics::RegisterStateARM64::convert(const RegisterDesc } } break; + case armv8_regclass_simd_fpr: { + Dyninst::MachRegister base; + unsigned int minor = reg.get_minor(); + + switch(size) { + case 8: base = Dyninst::aarch64::b0; + break; + case 16: base = Dyninst::aarch64::h0; + break; + case 32: base = Dyninst::aarch64::s0; + break; + case 64: + if (reg.get_offset() == 64) { + base = Dyninst::aarch64::hq0; + } else { + base = Dyninst::aarch64::d0; + } + break; + case 128: base = Dyninst::aarch64::q0; + break; + default:assert(!"invalid size of RegisterDescriptor!"); + break; + } + mreg = Dyninst::MachRegister(base.val() + (minor - armv8_simdfpr_v0)); + } + break; case armv8_regclass_pc: mreg = Dyninst::MachRegister(Dyninst::aarch64::pc); break; diff --git a/external/rose/armv8InstructionEnum.h b/external/rose/armv8InstructionEnum.h index 83041683e5..b5e0c62957 100644 --- a/external/rose/armv8InstructionEnum.h +++ b/external/rose/armv8InstructionEnum.h @@ -50,6 +50,42 @@ enum ARMv8GeneralPurposeRegister { armv8_gpr_zr }; +/** ARMv8-A SIMD & FP registers */ +enum ARMv8SimdFpRegister { + armv8_simdfpr_v0, + armv8_simdfpr_v1, + armv8_simdfpr_v2, + armv8_simdfpr_v3, + armv8_simdfpr_v4, + armv8_simdfpr_v5, + armv8_simdfpr_v6, + armv8_simdfpr_v7, + armv8_simdfpr_v8, + armv8_simdfpr_v9, + armv8_simdfpr_v10, + armv8_simdfpr_v11, + armv8_simdfpr_v12, + armv8_simdfpr_v13, + armv8_simdfpr_v14, + armv8_simdfpr_v15, + armv8_simdfpr_v16, + armv8_simdfpr_v17, + armv8_simdfpr_v18, + armv8_simdfpr_v19, + armv8_simdfpr_v20, + armv8_simdfpr_v21, + armv8_simdfpr_v22, + armv8_simdfpr_v23, + armv8_simdfpr_v24, + armv8_simdfpr_v25, + armv8_simdfpr_v26, + armv8_simdfpr_v27, + armv8_simdfpr_v28, + armv8_simdfpr_v29, + armv8_simdfpr_v30, + armv8_simdfpr_v31 +}; + /** ARMv8-A fields of the Pstate register */ enum ARMv8PstateFields { armv8_pstatefield_pstate = 0, /* The entire 32-bit pstate register */