diff --git a/arch/Sparc/SparcDisassembler.c b/arch/Sparc/SparcDisassembler.c index 3e6d0e0b9e..0773dcef24 100644 --- a/arch/Sparc/SparcDisassembler.c +++ b/arch/Sparc/SparcDisassembler.c @@ -32,6 +32,9 @@ #define GET_REGINFO_MC_DESC #define GET_REGINFO_ENUM #include "SparcGenRegisterInfo.inc" + +#define GET_INSTRINFO_ENUM +#include "SparcGenInstrInfo.inc" static const unsigned IntRegDecoderTable[] = { SP_G0, SP_G1, SP_G2, SP_G3, SP_G4, SP_G5, SP_G6, SP_G7, @@ -203,6 +206,8 @@ static DecodeStatus DecodeSWAP(MCInst *Inst, unsigned insn, uint64_t Address, #include "SparcGenSubtargetInfo.inc" #include "SparcGenDisassemblerTables.inc" +static DecodeStatus decodeIntPairMem(MCInst *MI, uint32_t insn, uint64_t Address); + /// readInstruction - read four bytes and return 32 bit word. static DecodeStatus readInstruction32(const uint8_t *code, size_t len, uint32_t *Insn) { @@ -235,6 +240,8 @@ bool Sparc_getInstruction(csh ud, const uint8_t *code, size_t code_len, MCInst * Result = decodeInstruction_4(DecoderTableSparc32, MI, Insn, address, (MCRegisterInfo *)info, 0); + if (Result == MCDisassembler_Fail) + Result = decodeIntPairMem(MI, Insn, address); if (Result != MCDisassembler_Fail) { *size = 4; return true; @@ -298,6 +305,34 @@ static DecodeStatus DecodeLoadInt(MCInst *Inst, unsigned insn, uint64_t Address, DecodeIntRegsRegisterClass); } +// An odd register pair is undefined; round it down like LLVM does. +static DecodeStatus DecodeIntPairRegisterClass(MCInst *Inst, unsigned RegNo, + uint64_t Address, const void *Decoder) +{ + return DecodeIntRegsRegisterClass(Inst, RegNo & ~1U, Address, Decoder); +} + +// The generated table predates LLVM's integer LDD and STD. +static DecodeStatus decodeIntPairMem(MCInst *MI, uint32_t insn, uint64_t Address) +{ + bool isImm = fieldFromInstruction_4(insn, 13, 1); + if (fieldFromInstruction_4(insn, 30, 2) != 3) + return MCDisassembler_Fail; + if (!isImm && fieldFromInstruction_4(insn, 5, 8)) + return MCDisassembler_Fail; + + switch (fieldFromInstruction_4(insn, 19, 6)) { + case 0x03: + MCInst_setOpcode(MI, isImm ? SP_LDDri : SP_LDDrr); + return DecodeMem(MI, insn, Address, NULL, true, DecodeIntPairRegisterClass); + case 0x07: + MCInst_setOpcode(MI, isImm ? SP_STDri : SP_STDrr); + return DecodeMem(MI, insn, Address, NULL, false, DecodeIntPairRegisterClass); + default: + return MCDisassembler_Fail; + } +} + static DecodeStatus DecodeLoadFP(MCInst *Inst, unsigned insn, uint64_t Address, const void *Decoder) { diff --git a/arch/Sparc/SparcGenInstrInfo.inc b/arch/Sparc/SparcGenInstrInfo.inc index 89bf034785..99c48d2626 100644 --- a/arch/Sparc/SparcGenInstrInfo.inc +++ b/arch/Sparc/SparcGenInstrInfo.inc @@ -508,7 +508,11 @@ enum { SP_XORXrr = 491, SP_XORri = 492, SP_XORrr = 493, - SP_INSTRUCTION_LIST_END = 494 + SP_LDDri = 494, + SP_LDDrr = 495, + SP_STDri = 496, + SP_STDrr = 497, + SP_INSTRUCTION_LIST_END = 498 }; #endif // GET_INSTRINFO_ENUM diff --git a/arch/Sparc/SparcInstPrinter.c b/arch/Sparc/SparcInstPrinter.c index e6878b5617..d38742bae6 100644 --- a/arch/Sparc/SparcInstPrinter.c +++ b/arch/Sparc/SparcInstPrinter.c @@ -103,6 +103,21 @@ static bool printSparcAliasInstr(MCInst *MI, SStream *O) { switch (MCInst_getOpcode(MI)) { default: return false; + case SP_LDDri: + case SP_LDDrr: + SStream_concat0(O, "ldd\t["); + printMemOperand(MI, 1, O, NULL); + SStream_concat0(O, "], "); + printOperand(MI, 0, O); + return true; + case SP_STDri: + case SP_STDrr: + SStream_concat0(O, "std\t"); + printOperand(MI, 2, O); + SStream_concat0(O, ", ["); + printMemOperand(MI, 0, O, NULL); + SStream_concat0(O, "]"); + return true; case SP_JMPLrr: case SP_JMPLri: if (MCInst_getNumOperands(MI) != 3) diff --git a/arch/Sparc/SparcMappingInsn.inc b/arch/Sparc/SparcMappingInsn.inc index 6c97afc79d..5a9c2f6dcf 100644 --- a/arch/Sparc/SparcMappingInsn.inc +++ b/arch/Sparc/SparcMappingInsn.inc @@ -2641,3 +2641,27 @@ { 0 }, { 0 }, { 0 }, 0, 0 #endif }, +{ + SP_LDDri, SPARC_INS_LDD, +#ifndef CAPSTONE_DIET + { 0 }, { 0 }, { 0 }, 0, 0 +#endif +}, +{ + SP_LDDrr, SPARC_INS_LDD, +#ifndef CAPSTONE_DIET + { 0 }, { 0 }, { 0 }, 0, 0 +#endif +}, +{ + SP_STDri, SPARC_INS_STD, +#ifndef CAPSTONE_DIET + { 0 }, { 0 }, { 0 }, 0, 0 +#endif +}, +{ + SP_STDrr, SPARC_INS_STD, +#ifndef CAPSTONE_DIET + { 0 }, { 0 }, { 0 }, 0, 0 +#endif +}, diff --git a/suite/MC/Sparc/sparc-mem-instructions.s.cs b/suite/MC/Sparc/sparc-mem-instructions.s.cs index fd0651a390..0969ff103d 100644 --- a/suite/MC/Sparc/sparc-mem-instructions.s.cs +++ b/suite/MC/Sparc/sparc-mem-instructions.s.cs @@ -14,6 +14,10 @@ 0xd4,0x06,0x00,0x16 = ld [%i0+%l6], %o2 0xd4,0x06,0x20,0x20 = ld [%i0+32], %o2 0xd4,0x00,0x60,0x00 = ld [%g1], %o2 +0xd4,0x1e,0x00,0x16 = ldd [%i0+%l6], %o2 +0xd4,0x1e,0x20,0x20 = ldd [%i0+32], %o2 +0xd4,0x18,0x60,0x00 = ldd [%g1], %o2 +0xda,0x18,0x63,0xd8 = ldd [%g1+0x3d8], %o4 0xd4,0x2e,0x00,0x16 = stb %o2, [%i0+%l6] 0xd4,0x2e,0x20,0x20 = stb %o2, [%i0+32] 0xd4,0x28,0x60,0x00 = stb %o2, [%g1] @@ -23,3 +27,7 @@ 0xd4,0x26,0x00,0x16 = st %o2, [%i0+%l6] 0xd4,0x26,0x20,0x20 = st %o2, [%i0+32] 0xd4,0x20,0x60,0x00 = st %o2, [%g1] +0xd4,0x3e,0x00,0x16 = std %o2, [%i0+%l6] +0xd4,0x3e,0x20,0x20 = std %o2, [%i0+32] +0xd4,0x38,0x60,0x00 = std %o2, [%g1] +0xd8,0x38,0x63,0xd8 = std %o4, [%g1+0x3d8]