Index: lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h =================================================================== --- lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h +++ lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h @@ -16,6 +16,18 @@ namespace lldb_private { +class EmulateInstructionRISCV; + +struct InstrPattern { + const char *name; + /// Bit mask to check the type of a instruction (B-Type, I-Type, J-Type, etc.) + uint32_t type_mask; + /// Characteristic value after bitwise-and with type_mask. + uint32_t eigen; + bool (*exec)(EmulateInstructionRISCV *emulator, uint32_t inst, + bool ignore_cond); +}; + class EmulateInstructionRISCV : public EmulateInstruction { public: static llvm::StringRef GetPluginNameStatic() { return "riscv"; } @@ -32,6 +44,8 @@ case eInstructionTypePrologueEpilogue: case eInstructionTypeAll: return false; + default: + llvm_unreachable("Unhandled instruction type"); } llvm_unreachable("Fully covered switch above!"); } @@ -64,6 +78,8 @@ lldb::addr_t ReadPC(bool *success); bool WritePC(lldb::addr_t pc); + + const InstrPattern *Decode(uint32_t inst); bool DecodeAndExecute(uint32_t inst, bool ignore_cond); }; Index: lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp =================================================================== --- lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp +++ lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp @@ -32,12 +32,6 @@ namespace lldb_private { -// Masks for detecting instructions types. According to riscv-spec Chap 26. -constexpr uint32_t I_MASK = 0b111000001111111; -constexpr uint32_t J_MASK = 0b000000001111111; -// no funct3 in the b-mask because the logic executing B is quite similar. -constexpr uint32_t B_MASK = 0b000000001111111; - // The funct3 is the type of compare in B instructions. // funct3 means "3-bits function selector", which RISC-V ISA uses as minor // opcode. It reuses the major opcode encoding space. @@ -51,10 +45,25 @@ constexpr uint32_t DecodeRD(uint32_t inst) { return (inst & 0xF80) >> 7; } constexpr uint32_t DecodeRS1(uint32_t inst) { return (inst & 0xF8000) >> 15; } constexpr uint32_t DecodeRS2(uint32_t inst) { return (inst & 0x1F00000) >> 20; } +constexpr uint32_t DecodeSHAMT5(uint32_t inst) { return DecodeRS2(inst); } +constexpr uint32_t DecodeSHAMT7(uint32_t inst) { + return (inst & 0x7F00000) >> 20; +} constexpr uint32_t DecodeFunct3(uint32_t inst) { return (inst & 0x7000) >> 12; } +// used in decoder constexpr int32_t SignExt(uint32_t imm) { return int32_t(imm); } +// used in executor +template constexpr uint64_t SextW(T value) { + return uint64_t(int64_t(int32_t(value))); +} + +// used in executor +template constexpr uint64_t ZextD(T value) { + return uint64_t(value); +} + constexpr uint32_t DecodeJImm(uint32_t inst) { return (uint64_t(int64_t(int32_t(inst & 0x80000000)) >> 11)) // imm[20] | (inst & 0xff000) // imm[19:12] @@ -73,6 +82,15 @@ | ((inst >> 7) & 0x1e); // imm[4:1] } +constexpr uint32_t DecodeSImm(uint32_t inst) { + return (uint64_t(int64_t(int32_t(inst & 0xFE00000)) >> 20)) // imm[11:5] + | ((inst & 0xF80) >> 7); // imm[4:0] +} + +constexpr uint32_t DecodeUImm(uint32_t inst) { + return uint64_t(int64_t(int32_t(inst & 0xFFFFF000))); // imm[31:12] +} + static uint32_t GPREncodingToLLDB(uint32_t reg_encode) { if (reg_encode == 0) return gpr_x0_riscv; @@ -166,38 +184,563 @@ return true; } -struct InstrPattern { - const char *name; - /// Bit mask to check the type of a instruction (B-Type, I-Type, J-Type, etc.) - uint32_t type_mask; - /// Characteristic value after bitwise-and with type_mask. - uint32_t eigen; - bool (*exec)(EmulateInstructionRISCV *emulator, uint32_t inst, - bool ignore_cond); -}; +static bool ExecLUI(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + uint32_t imm = DecodeUImm(inst); + RegisterValue value; + value.SetUInt64(SignExt(imm)); + return WriteRegister(emulator, DecodeRD(inst), value); +} + +static bool ExecAUIPC(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + uint32_t imm = DecodeUImm(inst); + RegisterValue value; + bool success = false; + value.SetUInt64(SignExt(imm) + emulator->ReadPC(&success)); + return success && WriteRegister(emulator, DecodeRD(inst), value); +} + +// T should be primitive type (int32_t, int64_t, etc) +template +static T ReadMem(EmulateInstructionRISCV *emulator, uint64_t addr, + bool *success) { + + EmulateInstructionRISCV::Context ctx; + ctx.type = EmulateInstruction::eContextRegisterLoad; + ctx.SetNoArgs(); + return T(emulator->ReadMemoryUnsigned(ctx, addr, sizeof(T), T(), success)); +} + +template +static bool WriteMem(EmulateInstructionRISCV *emulator, uint64_t addr, + RegisterValue value) { + EmulateInstructionRISCV::Context ctx; + ctx.type = EmulateInstruction::eContextRegisterStore; + ctx.SetNoArgs(); + return emulator->WriteMemoryUnsigned(ctx, addr, value.GetAsUInt64(), + sizeof(T)); +} + +static uint64_t LoadStoreAddr(EmulateInstructionRISCV *emulator, + uint32_t inst) { + auto rs1 = DecodeRS1(inst); + int32_t imm = SignExt(DecodeSImm(inst)); + RegisterValue value; + if (!ReadRegister(emulator, rs1, value)) + return LLDB_INVALID_ADDRESS; + uint64_t addr = value.GetAsUInt64() + uint64_t(imm); + return addr; +} + +template +static bool Load(EmulateInstructionRISCV *emulator, uint32_t inst, + uint64_t (*extend)(E)) { + uint64_t addr = LoadStoreAddr(emulator, inst); + if (addr == LLDB_INVALID_ADDRESS) + return false; + bool success = false; + E value = E(ReadMem(emulator, addr, &success)); + if (!success) + return false; + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(extend(value))); +} + +template +static bool Store(EmulateInstructionRISCV *emulator, uint32_t inst) { + uint64_t addr = LoadStoreAddr(emulator, inst); + if (addr == LLDB_INVALID_ADDRESS) + return false; + RegisterValue value; + if (!ReadRegister(emulator, DecodeRS2(inst), value)) + return false; + + return WriteMem(emulator, addr, value); +} + +static bool ExecLB(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Load(emulator, inst, SextW); +} + +static bool ExecLH(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Load(emulator, inst, SextW); +} + +static bool ExecLW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Load(emulator, inst, SextW); +} + +static bool ExecLD(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Load(emulator, inst, ZextD); +} + +static bool ExecLBU(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Load(emulator, inst, ZextD); +} + +static bool ExecLHU(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Load(emulator, inst, ZextD); +} + +static bool ExecLWU(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Load(emulator, inst, ZextD); +} + +static bool ExecSB(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Store(emulator, inst); +} + +static bool ExecSH(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Store(emulator, inst); +} + +static bool ExecSW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Store(emulator, inst); +} + +static bool ExecSD(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + return Store(emulator, inst); +} + +static bool ExecADDI(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + int32_t imm = SignExt(DecodeSImm(inst)); + + RegisterValue value; + if (!ReadRegister(emulator, rs1, value)) + return false; + + uint64_t result = int64_t(value.GetAsUInt64()) + int64_t(imm); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSLTI(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + int32_t imm = SignExt(DecodeIImm(inst)); + + RegisterValue value; + if (!ReadRegister(emulator, rs1, value)) + return false; + + if (int64_t(value.GetAsUInt64()) < int64_t(imm)) + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(uint64_t(1))); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(uint64_t(0))); +} + +static bool ExecSLTIU(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + int32_t imm = SignExt(DecodeIImm(inst)); + + RegisterValue value; + if (!ReadRegister(emulator, rs1, value)) + return false; + + if (value.GetAsUInt64() < uint64_t(imm)) + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(uint64_t(1))); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(uint64_t(0))); +} + +static bool ExecXORI(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + int32_t imm = SignExt(DecodeIImm(inst)); + + RegisterValue value; + if (!ReadRegister(emulator, rs1, value)) + return false; + + uint64_t result = value.GetAsUInt64() ^ uint64_t(imm); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecORI(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + int32_t imm = SignExt(DecodeIImm(inst)); + + RegisterValue value; + if (!ReadRegister(emulator, rs1, value)) + return false; + + uint64_t result = value.GetAsUInt64() | uint64_t(imm); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecANDI(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + int32_t imm = SignExt(DecodeIImm(inst)); + + RegisterValue value; + if (!ReadRegister(emulator, rs1, value)) + return false; + + uint64_t result = value.GetAsUInt64() & uint64_t(imm); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSLLI(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto shamt = DecodeSHAMT7(inst); + + RegisterValue value; + if (!ReadRegister(emulator, rs1, value)) + return false; + + uint64_t result = value.GetAsUInt64() << shamt; + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSRLI(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto shamt = DecodeSHAMT7(inst); + + RegisterValue value; + if (!ReadRegister(emulator, rs1, value)) + return false; + + uint64_t result = value.GetAsUInt64() >> shamt; + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSRAI(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto shamt = DecodeSHAMT7(inst); + + RegisterValue value; + if (!ReadRegister(emulator, rs1, value)) + return false; + + uint64_t result = int64_t(value.GetAsUInt64()) >> shamt; + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecADD(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = value1.GetAsUInt64() + value2.GetAsUInt64(); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSUB(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = value1.GetAsUInt64() - value2.GetAsUInt64(); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSLL(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = value1.GetAsUInt64() << (value2.GetAsUInt64() & 0b111111); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSLT(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + if (int64_t(value1.GetAsUInt64()) < int64_t(value2.GetAsUInt64())) + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(uint64_t(1))); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(uint64_t(0))); +} + +static bool ExecSLTU(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + if (value1.GetAsUInt64() < value2.GetAsUInt64()) + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(uint64_t(1))); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(uint64_t(0))); +} + +static bool ExecXOR(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = value1.GetAsUInt64() ^ value2.GetAsUInt64(); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSRL(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = value1.GetAsUInt64() >> (value2.GetAsUInt64() & 0b111111); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSRA(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = + int64_t(value1.GetAsUInt64()) >> (value2.GetAsUInt64() & 0b111111); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecOR(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = value1.GetAsUInt64() | value2.GetAsUInt64(); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecAND(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = value1.GetAsUInt64() & value2.GetAsUInt64(); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecADDIW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + int32_t imm = SignExt(DecodeIImm(inst)); + + RegisterValue value1; + if (!ReadRegister(emulator, rs1, value1)) + return false; + + uint64_t result = SextW(int32_t(value1.GetAsUInt64()) + imm); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSLLIW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto shamt = DecodeSHAMT5(inst); + + RegisterValue value1; + if (!ReadRegister(emulator, rs1, value1)) + return false; + + uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) << shamt); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSRLIW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto shamt = DecodeSHAMT5(inst); + + RegisterValue value1; + if (!ReadRegister(emulator, rs1, value1)) + return false; + + uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) >> shamt); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSRAIW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto shamt = DecodeSHAMT5(inst); + + RegisterValue value1; + if (!ReadRegister(emulator, rs1, value1)) + return false; + + uint64_t result = SextW(int32_t(value1.GetAsUInt64()) >> shamt); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecADDW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = SextW(value1.GetAsUInt64() + value2.GetAsUInt64()); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSUBW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = SextW(value1.GetAsUInt64() - value2.GetAsUInt64()); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSLLW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) + << (value2.GetAsUInt64() & 0b111111)); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSRLW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) >> + (value2.GetAsUInt64() & 0b111111)); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} + +static bool ExecSRAW(EmulateInstructionRISCV *emulator, uint32_t inst, bool) { + auto rs1 = DecodeRS1(inst); + auto rs2 = DecodeRS2(inst); + + RegisterValue value1; + RegisterValue value2; + if (!ReadRegister(emulator, rs1, value1) || + !ReadRegister(emulator, rs2, value2)) + return false; + + uint64_t result = + SextW(int32_t(value1.GetAsUInt64()) >> (value2.GetAsUInt64() & 0b111111)); + return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result)); +} static InstrPattern PATTERNS[] = { - {"JAL", J_MASK, 0b1101111, ExecJAL}, - {"JALR", I_MASK, 0b000000001100111, ExecJALR}, - {"B", B_MASK, 0b1100011, ExecB}, - // TODO: {LR/SC}.{W/D} and ECALL + {"LUI", 0x7F, 0x37, ExecLUI}, + {"AUIPC", 0x7F, 0x17, ExecAUIPC}, + {"JAL", 0x7F, 0x6F, ExecJAL}, + {"JALR", 0x707F, 0x67, ExecJALR}, + {"B", 0x7F, 0x63, ExecB}, + {"LB", 0x707F, 0x3, ExecLB}, + {"LH", 0x707F, 0x1003, ExecLH}, + {"LW", 0x707F, 0x2003, ExecLW}, + {"LBU", 0x707F, 0x4003, ExecLBU}, + {"LHU", 0x707F, 0x5003, ExecLHU}, + {"SB", 0x707F, 0x23, ExecSB}, + {"SH", 0x707F, 0x1023, ExecSH}, + {"SW", 0x707F, 0x2023, ExecSW}, + {"ADDI", 0x707F, 0x13, ExecADDI}, + {"SLTI", 0x707F, 0x2013, ExecSLTI}, + {"SLTIU", 0x707F, 0x3013, ExecSLTIU}, + {"XORI", 0x707F, 0x4013, ExecXORI}, + {"ORI", 0x707F, 0x6013, ExecORI}, + {"ANDI", 0x707F, 0x7013, ExecANDI}, + {"SLLI", 0xF800707F, 0x1013, ExecSLLI}, + {"SRLI", 0xF800707F, 0x5013, ExecSRLI}, + {"SRAI", 0xF800707F, 0x40005013, ExecSRAI}, + {"ADD", 0xFE00707F, 0x33, ExecADD}, + {"SUB", 0xFE00707F, 0x40000033, ExecSUB}, + {"SLL", 0xFE00707F, 0x1033, ExecSLL}, + {"SLT", 0xFE00707F, 0x2033, ExecSLT}, + {"SLTU", 0xFE00707F, 0x3033, ExecSLTU}, + {"XOR", 0xFE00707F, 0x4033, ExecXOR}, + {"SRL", 0xFE00707F, 0x5033, ExecSRL}, + {"SRA", 0xFE00707F, 0x40005033, ExecSRA}, + {"OR", 0xFE00707F, 0x6033, ExecOR}, + {"AND", 0xFE00707F, 0x7033, ExecAND}, + {"LWU", 0x707F, 0x6003, ExecLWU}, + {"LD", 0x707F, 0x3003, ExecLD}, + {"SD", 0x707F, 0x3023, ExecSD}, + {"ADDIW", 0x707F, 0x1B, ExecADDIW}, + {"SLLIW", 0xFE00707F, 0x101B, ExecSLLIW}, + {"SRLIW", 0xFE00707F, 0x501B, ExecSRLIW}, + {"SRAIW", 0xFE00707F, 0x4000501B, ExecSRAIW}, + {"ADDW", 0xFE00707F, 0x3B, ExecADDW}, + {"SUBW", 0xFE00707F, 0x4000003B, ExecSUBW}, + {"SLLW", 0xFE00707F, 0x103B, ExecSLLW}, + {"SRLW", 0xFE00707F, 0x503B, ExecSRLW}, + {"SRAW", 0xFE00707F, 0x4000503B, ExecSRAW}, }; -/// This function only determines the next instruction address for software -/// sigle stepping by emulating branching instructions including: -/// - from Base Instruction Set : JAL, JALR, B, ECALL -/// - from Atomic Instruction Set: LR -> BNE -> SC -> BNE -/// We will get rid of this tedious code when the riscv debug spec is ratified. -bool EmulateInstructionRISCV::DecodeAndExecute(uint32_t inst, - bool ignore_cond) { - Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); +const InstrPattern *EmulateInstructionRISCV::Decode(uint32_t inst) { for (const InstrPattern &pat : PATTERNS) { if ((inst & pat.type_mask) == pat.eigen) { - LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(%x) was decoded to %s", - __FUNCTION__, inst, pat.name); - return pat.exec(this, inst, ignore_cond); + return &pat; } } + return nullptr; +} + +/// This function only determines the next instruction address for software +/// sigle stepping by emulating instructions +bool EmulateInstructionRISCV::DecodeAndExecute(uint32_t inst, + bool ignore_cond) { + Log *log = GetLog(LLDBLog::Unwind); + const InstrPattern *pattern = this->Decode(inst); + if (pattern) { + LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(%x) was decoded to %s", + __FUNCTION__, inst, pattern->name); + return pattern->exec(this, inst, ignore_cond); + } LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(0x%x) does not branch: " @@ -213,7 +756,7 @@ bool ignore_cond = options & eEmulateInstructionOptionIgnoreConditions; bool success = false; - lldb::addr_t old_pc = 0; + lldb::addr_t old_pc = LLDB_INVALID_ADDRESS; if (increase_pc) { old_pc = ReadPC(&success); if (!success) @@ -253,15 +796,14 @@ Context ctx; ctx.type = eContextReadOpcode; ctx.SetNoArgs(); - uint32_t inst = (uint32_t)ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success); - uint16_t try_rvc = (uint16_t)(inst & 0x0000ffff); + uint32_t inst = uint32_t(ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success)); + uint16_t try_rvc = uint16_t(inst & 0x0000ffff); // check whether the compressed encode could be valid uint16_t mask = try_rvc & 0b11; - if (try_rvc != 0 && mask != 3) { + if (try_rvc != 0 && mask != 3) m_opcode.SetOpcode16(try_rvc, GetByteOrder()); - } else { + else m_opcode.SetOpcode32(inst, GetByteOrder()); - } return true; } Index: lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp =================================================================== --- lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp +++ lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp @@ -167,30 +167,43 @@ GEN_BRANCH_TEST(BLTU, -2, -1, 1) GEN_BRANCH_TEST(BGEU, -2, 1, -1) -void testNothing(RISCVEmulatorTester *tester, uint32_t inst) { - lldb::addr_t old_pc = 0x114514; - tester->WritePC(old_pc); - tester->SetInstruction(Opcode(inst, tester->GetByteOrder()), - LLDB_INVALID_ADDRESS, nullptr); - ASSERT_TRUE(tester->EvaluateInstruction(0)); - bool success = false; - auto pc = tester->ReadPC(&success); - ASSERT_TRUE(success); - ASSERT_EQ(pc, old_pc); - ASSERT_TRUE( - tester->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC)); - pc = tester->ReadPC(&success); - ASSERT_TRUE(success); - ASSERT_EQ(pc, old_pc + 4); +TEST_F(RISCVEmulatorTester, testDecode) { + std::unordered_map map{ + {0x00010113, "ADDI"}, {0x00023517, "AUIPC"}, {0x00050503, "LB"}, + {0x00053283, "LD"}, {0x00054503, "LBU"}, {0x00056503, "LWU"}, + {0x0006079b, "ADDIW"}, {0x0009b503, "LD"}, {0x00110513, "ADDI"}, + {0x00110837, "LUI"}, {0x00147513, "ANDI"}, {0x00150603, "LB"}, + {0x00153513, "SLTIU"}, {0x00168913, "ADDI"}, {0x00256513, "ORI"}, + {0x00447513, "ANDI"}, {0x00451a13, "SLLI"}, {0x00455693, "SRLI"}, + {0x00491593, "SLLI"}, {0x00814503, "LBU"}, {0x00858493, "ADDI"}, + {0x0089b503, "LD"}, {0x00910583, "LB"}, {0x00a035b3, "SLTU"}, + {0x00a10423, "SB"}, {0x00a51963, "B"}, {0x00a58023, "SB"}, + {0x00a96863, "B"}, {0x00b10723, "SB"}, {0x00b50563, "B"}, + {0x00b50633, "ADD"}, {0x00b50963, "B"}, {0x00b51463, "B"}, + {0x00b51863, "B"}, {0x00b53533, "SLTU"}, {0x00c107a3, "SB"}, + {0x00d036b3, "SLTU"}, {0x00d50733, "ADD"}, {0x00e03733, "SLTU"}, + {0x00e66b63, "B"}, {0x00f14503, "LBU"}, {0x010080e7, "JALR"}, + {0x01050593, "ADDI"}, {0x01078963, "B"}, {0x01093503, "LD"}, + {0x01350cb3, "ADD"}, {0x01450613, "ADDI"}, {0x01710503, "LB"}, + {0x01893503, "LD"}, {0x02700513, "ADDI"}, {0x02714503, "LBU"}, + {0x0285b983, "LD"}, {0x02a10023, "SB"}, {0x02a97163, "B"}, + {0x02b51263, "B"}, {0x02b51563, "B"}, {0x02c103a3, "SB"}, + {0x02e080e7, "JALR"}, {0x02f6f363, "B"}, {0x0305051b, "ADDIW"}, + {0x030c6403, "LWU"}, {0x03714503, "LBU"}, {0x05110583, "LB"}, + {0x058080e7, "JALR"}, {0x05e10603, "LB"}, {0x06300693, "ADDI"}, + {0x06b10ba3, "SB"}, {0x07e50513, "ADDI"}, {0x08a080e7, "JALR"}, + {0x08b10ba3, "SB"}, {0x0a4080e7, "JALR"}, {0x0aa6e963, "B"}, + {0x0c710503, "LB"}, {0x0ec57763, "B"}, {0x0f2080e7, "JALR"}, + {0x0f710503, "LB"}, {0x0fa080e7, "JALR"}, {0x10000537, "LUI"}, + {0x16069d63, "B"}, {0x22256513, "ORI"}, {0x2cc080e7, "JALR"}, + {0x40d507b3, "SUB"}, {0x7eae8e93, "ADDI"}, {0x7ff5859b, "ADDIW"}, + {0x8a6080e7, "JALR"}, {0xfc0a1ee3, "B"}, {0xfc8080e7, "JALR"}, + + }; + for (auto i : map) { + const InstrPattern *pattern = this->Decode(i.first); + ASSERT_TRUE(pattern != nullptr); + std::string name = pattern->name; + ASSERT_EQ(name, i.second); + } } - -#define GEN_NOTHING_TEST(name, inst) \ - TEST_F(RISCVEmulatorTester, testDoNothing_##name) { testNothing(this, inst); } - -// GEN_NOTHING_TEST(name, inst): -// It should do nothing (except increasing pc) for instruction `inst` -GEN_NOTHING_TEST(mv, 0x01813083) // mv a0, a5 -GEN_NOTHING_TEST(li, 0x00078513) // li a5, 0 -GEN_NOTHING_TEST(sd, 0x02010413) // sd s0, sp(16) -GEN_NOTHING_TEST(lw, 0x0007879b) // lw a5, s0(-20) -GEN_NOTHING_TEST(addi, 0x00113423) // addi sp, sp, -16