| //===------ PPCDisassembler.cpp - Disassembler for PowerPC ------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| /* Capstone Disassembly Engine */ |
| /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 */ |
| |
| #ifdef CAPSTONE_HAS_POWERPC |
| |
| #include <stdio.h> // DEBUG |
| #include <stdlib.h> |
| |
| #include "../../cs_priv.h" |
| |
| #include "../../MCInst.h" |
| #include "../../MCInstrDesc.h" |
| #include "../../MCFixedLenDisassembler.h" |
| #include "../../MCRegisterInfo.h" |
| #include "../../MCDisassembler.h" |
| #include "../../MathExtras.h" |
| |
| #define GET_REGINFO_ENUM |
| #include "PPCGenRegisterInfo.inc" |
| |
| |
| // FIXME: These can be generated by TableGen from the existing register |
| // encoding values! |
| |
| static const unsigned CRRegs[] = { |
| PPC_CR0, PPC_CR1, PPC_CR2, PPC_CR3, |
| PPC_CR4, PPC_CR5, PPC_CR6, PPC_CR7 |
| }; |
| |
| static const unsigned CRBITRegs[] = { |
| PPC_CR0LT, PPC_CR0GT, PPC_CR0EQ, PPC_CR0UN, |
| PPC_CR1LT, PPC_CR1GT, PPC_CR1EQ, PPC_CR1UN, |
| PPC_CR2LT, PPC_CR2GT, PPC_CR2EQ, PPC_CR2UN, |
| PPC_CR3LT, PPC_CR3GT, PPC_CR3EQ, PPC_CR3UN, |
| PPC_CR4LT, PPC_CR4GT, PPC_CR4EQ, PPC_CR4UN, |
| PPC_CR5LT, PPC_CR5GT, PPC_CR5EQ, PPC_CR5UN, |
| PPC_CR6LT, PPC_CR6GT, PPC_CR6EQ, PPC_CR6UN, |
| PPC_CR7LT, PPC_CR7GT, PPC_CR7EQ, PPC_CR7UN |
| }; |
| |
| static const unsigned FRegs[] = { |
| PPC_F0, PPC_F1, PPC_F2, PPC_F3, |
| PPC_F4, PPC_F5, PPC_F6, PPC_F7, |
| PPC_F8, PPC_F9, PPC_F10, PPC_F11, |
| PPC_F12, PPC_F13, PPC_F14, PPC_F15, |
| PPC_F16, PPC_F17, PPC_F18, PPC_F19, |
| PPC_F20, PPC_F21, PPC_F22, PPC_F23, |
| PPC_F24, PPC_F25, PPC_F26, PPC_F27, |
| PPC_F28, PPC_F29, PPC_F30, PPC_F31 |
| }; |
| |
| static const unsigned VRegs[] = { |
| PPC_V0, PPC_V1, PPC_V2, PPC_V3, |
| PPC_V4, PPC_V5, PPC_V6, PPC_V7, |
| PPC_V8, PPC_V9, PPC_V10, PPC_V11, |
| PPC_V12, PPC_V13, PPC_V14, PPC_V15, |
| PPC_V16, PPC_V17, PPC_V18, PPC_V19, |
| PPC_V20, PPC_V21, PPC_V22, PPC_V23, |
| PPC_V24, PPC_V25, PPC_V26, PPC_V27, |
| PPC_V28, PPC_V29, PPC_V30, PPC_V31 |
| }; |
| |
| static const unsigned GPRegs[] = { |
| PPC_R0, PPC_R1, PPC_R2, PPC_R3, |
| PPC_R4, PPC_R5, PPC_R6, PPC_R7, |
| PPC_R8, PPC_R9, PPC_R10, PPC_R11, |
| PPC_R12, PPC_R13, PPC_R14, PPC_R15, |
| PPC_R16, PPC_R17, PPC_R18, PPC_R19, |
| PPC_R20, PPC_R21, PPC_R22, PPC_R23, |
| PPC_R24, PPC_R25, PPC_R26, PPC_R27, |
| PPC_R28, PPC_R29, PPC_R30, PPC_R31 |
| }; |
| |
| static const unsigned GP0Regs[] = { |
| PPC_ZERO, PPC_R1, PPC_R2, PPC_R3, |
| PPC_R4, PPC_R5, PPC_R6, PPC_R7, |
| PPC_R8, PPC_R9, PPC_R10, PPC_R11, |
| PPC_R12, PPC_R13, PPC_R14, PPC_R15, |
| PPC_R16, PPC_R17, PPC_R18, PPC_R19, |
| PPC_R20, PPC_R21, PPC_R22, PPC_R23, |
| PPC_R24, PPC_R25, PPC_R26, PPC_R27, |
| PPC_R28, PPC_R29, PPC_R30, PPC_R31 |
| }; |
| |
| static const unsigned G8Regs[] = { |
| PPC_X0, PPC_X1, PPC_X2, PPC_X3, |
| PPC_X4, PPC_X5, PPC_X6, PPC_X7, |
| PPC_X8, PPC_X9, PPC_X10, PPC_X11, |
| PPC_X12, PPC_X13, PPC_X14, PPC_X15, |
| PPC_X16, PPC_X17, PPC_X18, PPC_X19, |
| PPC_X20, PPC_X21, PPC_X22, PPC_X23, |
| PPC_X24, PPC_X25, PPC_X26, PPC_X27, |
| PPC_X28, PPC_X29, PPC_X30, PPC_X31 |
| }; |
| |
| static uint64_t getFeatureBits(int feature) |
| { |
| // enable all features |
| return (uint64_t)-1; |
| } |
| |
| static DecodeStatus decodeRegisterClass(MCInst *Inst, uint64_t RegNo, |
| const unsigned *Regs) |
| { |
| // assert(RegNo < N && "Invalid register number"); |
| MCInst_addOperand(Inst, MCOperand_CreateReg(Regs[RegNo])); |
| return MCDisassembler_Success; |
| } |
| |
| static DecodeStatus DecodeCRRCRegisterClass(MCInst *Inst, uint64_t RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| return decodeRegisterClass(Inst, RegNo, CRRegs); |
| } |
| |
| static DecodeStatus DecodeCRBITRCRegisterClass(MCInst *Inst, uint64_t RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| return decodeRegisterClass(Inst, RegNo, CRBITRegs); |
| } |
| |
| static DecodeStatus DecodeF4RCRegisterClass(MCInst *Inst, uint64_t RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| return decodeRegisterClass(Inst, RegNo, FRegs); |
| } |
| |
| static DecodeStatus DecodeF8RCRegisterClass(MCInst *Inst, uint64_t RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| return decodeRegisterClass(Inst, RegNo, FRegs); |
| } |
| |
| static DecodeStatus DecodeVRRCRegisterClass(MCInst *Inst, uint64_t RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| return decodeRegisterClass(Inst, RegNo, VRegs); |
| } |
| |
| static DecodeStatus DecodeGPRCRegisterClass(MCInst *Inst, uint64_t RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| return decodeRegisterClass(Inst, RegNo, GPRegs); |
| } |
| |
| static DecodeStatus DecodeGPRC_NOR0RegisterClass(MCInst *Inst, uint64_t RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| return decodeRegisterClass(Inst, RegNo, GP0Regs); |
| } |
| |
| static DecodeStatus DecodeG8RCRegisterClass(MCInst *Inst, uint64_t RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| return decodeRegisterClass(Inst, RegNo, G8Regs); |
| } |
| |
| #define DecodePointerLikeRegClass0 DecodeGPRCRegisterClass |
| #define DecodePointerLikeRegClass1 DecodeGPRC_NOR0RegisterClass |
| |
| static DecodeStatus decodeUImmOperand(MCInst *Inst, uint64_t Imm, |
| int64_t Address, const void *Decoder, unsigned N) |
| { |
| //assert(isUInt<N>(Imm) && "Invalid immediate"); |
| MCInst_addOperand(Inst, MCOperand_CreateImm(Imm)); |
| return MCDisassembler_Success; |
| } |
| |
| static DecodeStatus decodeSImmOperand(MCInst *Inst, uint64_t Imm, |
| int64_t Address, const void *Decoder, unsigned N) |
| { |
| // assert(isUInt<N>(Imm) && "Invalid immediate"); |
| MCInst_addOperand(Inst, MCOperand_CreateImm(SignExtend64(Imm, N))); |
| return MCDisassembler_Success; |
| } |
| |
| |
| #define GET_INSTRINFO_ENUM |
| #include "PPCGenInstrInfo.inc" |
| |
| static DecodeStatus decodeMemRIOperands(MCInst *Inst, uint64_t Imm, |
| int64_t Address, const void *Decoder) |
| { |
| // Decode the memri field (imm, reg), which has the low 16-bits as the |
| // displacement and the next 5 bits as the register #. |
| |
| uint64_t Base = Imm >> 16; |
| uint64_t Disp = Imm & 0xFFFF; |
| |
| // assert(Base < 32 && "Invalid base register"); |
| |
| switch (MCInst_getOpcode(Inst)) { |
| default: break; |
| case PPC_LBZU: |
| case PPC_LHAU: |
| case PPC_LHZU: |
| case PPC_LWZU: |
| case PPC_LFSU: |
| case PPC_LFDU: |
| // Add the tied output operand. |
| MCInst_addOperand(Inst, MCOperand_CreateReg(GP0Regs[Base])); |
| break; |
| case PPC_STBU: |
| case PPC_STHU: |
| case PPC_STWU: |
| case PPC_STFSU: |
| case PPC_STFDU: |
| MCInst_insert(Inst, 0, MCOperand_CreateReg(GP0Regs[Base])); |
| break; |
| } |
| |
| MCInst_addOperand(Inst, MCOperand_CreateImm(SignExtend64(Disp, 16))); |
| MCInst_addOperand(Inst, MCOperand_CreateReg(GP0Regs[Base])); |
| return MCDisassembler_Success; |
| } |
| |
| static DecodeStatus decodeMemRIXOperands(MCInst *Inst, uint64_t Imm, |
| int64_t Address, const void *Decoder) |
| { |
| // Decode the memrix field (imm, reg), which has the low 14-bits as the |
| // displacement and the next 5 bits as the register #. |
| |
| uint64_t Base = Imm >> 14; |
| uint64_t Disp = Imm & 0x3FFF; |
| |
| // assert(Base < 32 && "Invalid base register"); |
| |
| if (MCInst_getOpcode(Inst) == PPC_LDU) |
| // Add the tied output operand. |
| MCInst_addOperand(Inst, MCOperand_CreateReg(GP0Regs[Base])); |
| else if (MCInst_getOpcode(Inst) == PPC_STDU) |
| MCInst_insert(Inst, 0, MCOperand_CreateReg(GP0Regs[Base])); |
| |
| MCInst_addOperand(Inst, MCOperand_CreateImm(SignExtend64(Disp << 2, 16))); |
| MCInst_addOperand(Inst, MCOperand_CreateReg(GP0Regs[Base])); |
| return MCDisassembler_Success; |
| } |
| |
| static DecodeStatus decodeCRBitMOperand(MCInst *Inst, uint64_t Imm, |
| int64_t Address, const void *Decoder) |
| { |
| // The cr bit encoding is 0x80 >> cr_reg_num. |
| |
| unsigned Zeros = CountTrailingZeros_64(Imm); |
| // assert(Zeros < 8 && "Invalid CR bit value"); |
| |
| MCInst_addOperand(Inst, MCOperand_CreateReg(CRRegs[7 - Zeros])); |
| return MCDisassembler_Success; |
| } |
| |
| #include "PPCGenDisassemblerTables.inc" |
| |
| static DecodeStatus getInstruction(MCInst *MI, |
| const uint8_t *code, size_t code_len, |
| uint16_t *Size, |
| uint64_t Address, MCRegisterInfo *MRI) |
| { |
| uint32_t insn; |
| DecodeStatus result; |
| // Get the four bytes of the instruction. |
| if (code_len < 4) { |
| // not enough data |
| *Size = 0; |
| return MCDisassembler_Fail; |
| } |
| |
| // The instruction is big-endian encoded. |
| if (MI->csh->mode & CS_MODE_BIG_ENDIAN) |
| insn = (code[0] << 24) | (code[1] << 16) | |
| (code[2] << 8) | (code[3] << 0); |
| else |
| insn = (code[3] << 24) | (code[2] << 16) | |
| (code[1] << 8) | (code[0] << 0); |
| |
| result = decodeInstruction_4(DecoderTable32, MI, insn, Address, 4); |
| if (result != MCDisassembler_Fail) { |
| *Size = 4; |
| return result; |
| } |
| |
| // report error |
| MCInst_clear(MI); |
| *Size = 0; |
| return MCDisassembler_Fail; |
| } |
| |
| bool PPC_getInstruction(csh ud, const uint8_t *code, size_t code_len, |
| MCInst *instr, uint16_t *size, uint64_t address, void *info) |
| { |
| DecodeStatus status = getInstruction(instr, |
| code, code_len, |
| size, |
| address, (MCRegisterInfo *)info); |
| |
| return status == MCDisassembler_Success; |
| } |
| |
| #define GET_REGINFO_MC_DESC |
| #include "PPCGenRegisterInfo.inc" |
| void PPC_init(MCRegisterInfo *MRI) |
| { |
| /* |
| InitMCRegisterInfo( PPCRegDesc, 182, RA, PC, |
| PPCMCRegisterClasses, 15, |
| PPCRegUnitRoots, |
| 138, |
| PPCRegDiffLists, |
| PPCRegStrings, |
| PPCSubRegIdxLists, |
| 6, |
| PPCSubRegIdxRanges, |
| PPCRegEncodingTable); |
| */ |
| |
| MCRegisterInfo_InitMCRegisterInfo(MRI, PPCRegDesc, 182, |
| 0, 0, |
| PPCMCRegisterClasses, 15, |
| 0, 0, |
| PPCRegDiffLists, |
| 0, |
| PPCSubRegIdxLists, 6, |
| 0); |
| } |
| |
| #endif |