blob: 0793f43a3b55b10d87aceddca382e6d61a598f61 [file] [log] [blame]
//===------ 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