553 lines
20 KiB
C++
553 lines
20 KiB
C++
//===- MipsDisassembler.cpp - Disassembler for Mips -------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file is part of the Mips Disassembler.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Mips.h"
|
|
#include "MipsSubtarget.h"
|
|
#include "llvm/MC/EDInstInfo.h"
|
|
#include "llvm/MC/MCDisassembler.h"
|
|
#include "llvm/Support/MemoryObject.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
|
|
#include "MipsGenEDInfo.inc"
|
|
|
|
using namespace llvm;
|
|
|
|
typedef MCDisassembler::DecodeStatus DecodeStatus;
|
|
|
|
/// MipsDisassembler - a disasembler class for Mips32.
|
|
class MipsDisassembler : public MCDisassembler {
|
|
public:
|
|
/// Constructor - Initializes the disassembler.
|
|
///
|
|
MipsDisassembler(const MCSubtargetInfo &STI, bool bigEndian) :
|
|
MCDisassembler(STI), isBigEndian(bigEndian) {
|
|
}
|
|
|
|
~MipsDisassembler() {
|
|
}
|
|
|
|
/// getInstruction - See MCDisassembler.
|
|
DecodeStatus getInstruction(MCInst &instr,
|
|
uint64_t &size,
|
|
const MemoryObject ®ion,
|
|
uint64_t address,
|
|
raw_ostream &vStream,
|
|
raw_ostream &cStream) const;
|
|
|
|
/// getEDInfo - See MCDisassembler.
|
|
const EDInstInfo *getEDInfo() const;
|
|
|
|
private:
|
|
bool isBigEndian;
|
|
};
|
|
|
|
|
|
/// Mips64Disassembler - a disasembler class for Mips64.
|
|
class Mips64Disassembler : public MCDisassembler {
|
|
public:
|
|
/// Constructor - Initializes the disassembler.
|
|
///
|
|
Mips64Disassembler(const MCSubtargetInfo &STI, bool bigEndian) :
|
|
MCDisassembler(STI), isBigEndian(bigEndian) {
|
|
}
|
|
|
|
~Mips64Disassembler() {
|
|
}
|
|
|
|
/// getInstruction - See MCDisassembler.
|
|
DecodeStatus getInstruction(MCInst &instr,
|
|
uint64_t &size,
|
|
const MemoryObject ®ion,
|
|
uint64_t address,
|
|
raw_ostream &vStream,
|
|
raw_ostream &cStream) const;
|
|
|
|
/// getEDInfo - See MCDisassembler.
|
|
const EDInstInfo *getEDInfo() const;
|
|
|
|
private:
|
|
bool isBigEndian;
|
|
};
|
|
|
|
const EDInstInfo *MipsDisassembler::getEDInfo() const {
|
|
return instInfoMips;
|
|
}
|
|
|
|
const EDInstInfo *Mips64Disassembler::getEDInfo() const {
|
|
return instInfoMips;
|
|
}
|
|
|
|
// Decoder tables for Mips register
|
|
static const unsigned CPURegsTable[] = {
|
|
Mips::ZERO, Mips::AT, Mips::V0, Mips::V1,
|
|
Mips::A0, Mips::A1, Mips::A2, Mips::A3,
|
|
Mips::T0, Mips::T1, Mips::T2, Mips::T3,
|
|
Mips::T4, Mips::T5, Mips::T6, Mips::T7,
|
|
Mips::S0, Mips::S1, Mips::S2, Mips::S3,
|
|
Mips::S4, Mips::S5, Mips::S6, Mips::S7,
|
|
Mips::T8, Mips::T9, Mips::K0, Mips::K1,
|
|
Mips::GP, Mips::SP, Mips::FP, Mips::RA
|
|
};
|
|
|
|
static const unsigned FGR32RegsTable[] = {
|
|
Mips::F0, Mips::F1, Mips::F2, Mips::F3,
|
|
Mips::F4, Mips::F5, Mips::F6, Mips::F7,
|
|
Mips::F8, Mips::F9, Mips::F10, Mips::F11,
|
|
Mips::F12, Mips::F13, Mips::F14, Mips::F15,
|
|
Mips::F16, Mips::F17, Mips::F18, Mips::F18,
|
|
Mips::F20, Mips::F21, Mips::F22, Mips::F23,
|
|
Mips::F24, Mips::F25, Mips::F26, Mips::F27,
|
|
Mips::F28, Mips::F29, Mips::F30, Mips::F31
|
|
};
|
|
|
|
static const unsigned CPU64RegsTable[] = {
|
|
Mips::ZERO_64, Mips::AT_64, Mips::V0_64, Mips::V1_64,
|
|
Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64,
|
|
Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64,
|
|
Mips::T4_64, Mips::T5_64, Mips::T6_64, Mips::T7_64,
|
|
Mips::S0_64, Mips::S1_64, Mips::S2_64, Mips::S3_64,
|
|
Mips::S4_64, Mips::S5_64, Mips::S6_64, Mips::S7_64,
|
|
Mips::T8_64, Mips::T9_64, Mips::K0_64, Mips::K1_64,
|
|
Mips::GP_64, Mips::SP_64, Mips::FP_64, Mips::RA_64
|
|
};
|
|
|
|
static const unsigned FGR64RegsTable[] = {
|
|
Mips::D0_64, Mips::D1_64, Mips::D2_64, Mips::D3_64,
|
|
Mips::D4_64, Mips::D5_64, Mips::D6_64, Mips::D7_64,
|
|
Mips::D8_64, Mips::D9_64, Mips::D10_64, Mips::D11_64,
|
|
Mips::D12_64, Mips::D13_64, Mips::D14_64, Mips::D15_64,
|
|
Mips::D16_64, Mips::D17_64, Mips::D18_64, Mips::D19_64,
|
|
Mips::D20_64, Mips::D21_64, Mips::D22_64, Mips::D23_64,
|
|
Mips::D24_64, Mips::D25_64, Mips::D26_64, Mips::D27_64,
|
|
Mips::D28_64, Mips::D29_64, Mips::D30_64, Mips::D31_64
|
|
};
|
|
|
|
static const unsigned AFGR64RegsTable[] = {
|
|
Mips::D0, Mips::D1, Mips::D2, Mips::D3,
|
|
Mips::D4, Mips::D5, Mips::D6, Mips::D7,
|
|
Mips::D8, Mips::D9, Mips::D10, Mips::D11,
|
|
Mips::D12, Mips::D13, Mips::D14, Mips::D15
|
|
};
|
|
|
|
// Forward declare these because the autogenerated code will reference them.
|
|
// Definitions are further down.
|
|
static DecodeStatus DecodeCPU64RegsRegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeCPURegsRegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeFGR64RegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeFGR32RegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeCCRRegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeAFGR64RegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeHWRegs64RegisterClass(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeBranchTarget(MCInst &Inst,
|
|
unsigned Offset,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeBC1(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
|
|
static DecodeStatus DecodeJumpTarget(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeMem(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeFMem(MCInst &Inst, unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeSimm16(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeCondCode(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeInsSize(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
static DecodeStatus DecodeExtSize(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder);
|
|
|
|
namespace llvm {
|
|
extern Target TheMipselTarget, TheMipsTarget, TheMips64Target,
|
|
TheMips64elTarget;
|
|
}
|
|
|
|
static MCDisassembler *createMipsDisassembler(
|
|
const Target &T,
|
|
const MCSubtargetInfo &STI) {
|
|
return new MipsDisassembler(STI,true);
|
|
}
|
|
|
|
static MCDisassembler *createMipselDisassembler(
|
|
const Target &T,
|
|
const MCSubtargetInfo &STI) {
|
|
return new MipsDisassembler(STI,false);
|
|
}
|
|
|
|
static MCDisassembler *createMips64Disassembler(
|
|
const Target &T,
|
|
const MCSubtargetInfo &STI) {
|
|
return new Mips64Disassembler(STI,true);
|
|
}
|
|
|
|
static MCDisassembler *createMips64elDisassembler(
|
|
const Target &T,
|
|
const MCSubtargetInfo &STI) {
|
|
return new Mips64Disassembler(STI, false);
|
|
}
|
|
|
|
extern "C" void LLVMInitializeMipsDisassembler() {
|
|
// Register the disassembler.
|
|
TargetRegistry::RegisterMCDisassembler(TheMipsTarget,
|
|
createMipsDisassembler);
|
|
TargetRegistry::RegisterMCDisassembler(TheMipselTarget,
|
|
createMipselDisassembler);
|
|
TargetRegistry::RegisterMCDisassembler(TheMips64Target,
|
|
createMips64Disassembler);
|
|
TargetRegistry::RegisterMCDisassembler(TheMips64elTarget,
|
|
createMips64elDisassembler);
|
|
}
|
|
|
|
|
|
#include "MipsGenDisassemblerTables.inc"
|
|
|
|
/// readInstruction - read four bytes from the MemoryObject
|
|
/// and return 32 bit word sorted according to the given endianess
|
|
static DecodeStatus readInstruction32(const MemoryObject ®ion,
|
|
uint64_t address,
|
|
uint64_t &size,
|
|
uint32_t &insn,
|
|
bool isBigEndian) {
|
|
uint8_t Bytes[4];
|
|
|
|
// We want to read exactly 4 Bytes of data.
|
|
if (region.readBytes(address, 4, (uint8_t*)Bytes, NULL) == -1) {
|
|
size = 0;
|
|
return MCDisassembler::Fail;
|
|
}
|
|
|
|
if (isBigEndian) {
|
|
// Encoded as a big-endian 32-bit word in the stream.
|
|
insn = (Bytes[3] << 0) |
|
|
(Bytes[2] << 8) |
|
|
(Bytes[1] << 16) |
|
|
(Bytes[0] << 24);
|
|
}
|
|
else {
|
|
// Encoded as a small-endian 32-bit word in the stream.
|
|
insn = (Bytes[0] << 0) |
|
|
(Bytes[1] << 8) |
|
|
(Bytes[2] << 16) |
|
|
(Bytes[3] << 24);
|
|
}
|
|
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
DecodeStatus
|
|
MipsDisassembler::getInstruction(MCInst &instr,
|
|
uint64_t &Size,
|
|
const MemoryObject &Region,
|
|
uint64_t Address,
|
|
raw_ostream &vStream,
|
|
raw_ostream &cStream) const {
|
|
uint32_t Insn;
|
|
|
|
DecodeStatus Result = readInstruction32(Region, Address, Size,
|
|
Insn, isBigEndian);
|
|
if (Result == MCDisassembler::Fail)
|
|
return MCDisassembler::Fail;
|
|
|
|
// Calling the auto-generated decoder function.
|
|
Result = decodeMipsInstruction32(instr, Insn, Address, this, STI);
|
|
if (Result != MCDisassembler::Fail) {
|
|
Size = 4;
|
|
return Result;
|
|
}
|
|
|
|
return MCDisassembler::Fail;
|
|
}
|
|
|
|
DecodeStatus
|
|
Mips64Disassembler::getInstruction(MCInst &instr,
|
|
uint64_t &Size,
|
|
const MemoryObject &Region,
|
|
uint64_t Address,
|
|
raw_ostream &vStream,
|
|
raw_ostream &cStream) const {
|
|
uint32_t Insn;
|
|
|
|
DecodeStatus Result = readInstruction32(Region, Address, Size,
|
|
Insn, isBigEndian);
|
|
if (Result == MCDisassembler::Fail)
|
|
return MCDisassembler::Fail;
|
|
|
|
// Calling the auto-generated decoder function.
|
|
Result = decodeMips64Instruction32(instr, Insn, Address, this, STI);
|
|
if (Result != MCDisassembler::Fail) {
|
|
Size = 4;
|
|
return Result;
|
|
}
|
|
// If we fail to decode in Mips64 decoder space we can try in Mips32
|
|
Result = decodeMipsInstruction32(instr, Insn, Address, this, STI);
|
|
if (Result != MCDisassembler::Fail) {
|
|
Size = 4;
|
|
return Result;
|
|
}
|
|
|
|
return MCDisassembler::Fail;
|
|
}
|
|
|
|
static DecodeStatus DecodeCPU64RegsRegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateReg(CPU64RegsTable[RegNo]));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeCPURegsRegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateReg(CPURegsTable[RegNo]));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeFGR64RegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateReg(FGR64RegsTable[RegNo]));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeFGR32RegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateReg(FGR32RegsTable[RegNo]));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeCCRRegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
Inst.addOperand(MCOperand::CreateReg(RegNo));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeMem(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
int Offset = SignExtend32<16>(Insn & 0xffff);
|
|
int Reg = (int)fieldFromInstruction32(Insn, 16, 5);
|
|
int Base = (int)fieldFromInstruction32(Insn, 21, 5);
|
|
|
|
if(Inst.getOpcode() == Mips::SC){
|
|
Inst.addOperand(MCOperand::CreateReg(CPURegsTable[Reg]));
|
|
}
|
|
|
|
Inst.addOperand(MCOperand::CreateReg(CPURegsTable[Reg]));
|
|
Inst.addOperand(MCOperand::CreateReg(CPURegsTable[Base]));
|
|
Inst.addOperand(MCOperand::CreateImm(Offset));
|
|
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeFMem(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
int Offset = SignExtend32<16>(Insn & 0xffff);
|
|
int Reg = (int)fieldFromInstruction32(Insn, 16, 5);
|
|
int Base = (int)fieldFromInstruction32(Insn, 21, 5);
|
|
|
|
Inst.addOperand(MCOperand::CreateReg(FGR64RegsTable[Reg]));
|
|
Inst.addOperand(MCOperand::CreateReg(CPURegsTable[Base]));
|
|
Inst.addOperand(MCOperand::CreateImm(Offset));
|
|
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
|
|
static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
// Currently only hardware register 29 is supported.
|
|
if (RegNo != 29)
|
|
return MCDisassembler::Fail;
|
|
Inst.addOperand(MCOperand::CreateReg(Mips::HWR29));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeCondCode(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
int CondCode = Insn & 0xf;
|
|
Inst.addOperand(MCOperand::CreateImm(CondCode));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeAFGR64RegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
if (RegNo > 31)
|
|
return MCDisassembler::Fail;
|
|
|
|
Inst.addOperand(MCOperand::CreateReg(AFGR64RegsTable[RegNo]));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeHWRegs64RegisterClass(MCInst &Inst,
|
|
unsigned RegNo,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
//Currently only hardware register 29 is supported
|
|
if (RegNo != 29)
|
|
return MCDisassembler::Fail;
|
|
Inst.addOperand(MCOperand::CreateReg(Mips::HWR29));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeBranchTarget(MCInst &Inst,
|
|
unsigned Offset,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
unsigned BranchOffset = Offset & 0xffff;
|
|
BranchOffset = SignExtend32<18>(BranchOffset << 2) + 4;
|
|
Inst.addOperand(MCOperand::CreateImm(BranchOffset));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeBC1(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
unsigned BranchOffset = Insn & 0xffff;
|
|
BranchOffset = SignExtend32<18>(BranchOffset << 2) + 4;
|
|
Inst.addOperand(MCOperand::CreateImm(BranchOffset));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeJumpTarget(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
|
|
unsigned JumpOffset = fieldFromInstruction32(Insn, 0, 26) << 2;
|
|
Inst.addOperand(MCOperand::CreateImm(JumpOffset));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
|
|
static DecodeStatus DecodeSimm16(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
Inst.addOperand(MCOperand::CreateImm(SignExtend32<16>(Insn)));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeInsSize(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
// First we need to grab the pos(lsb) from MCInst.
|
|
int Pos = Inst.getOperand(2).getImm();
|
|
int Size = (int) Insn - Pos + 1;
|
|
Inst.addOperand(MCOperand::CreateImm(SignExtend32<16>(Size)));
|
|
return MCDisassembler::Success;
|
|
}
|
|
|
|
static DecodeStatus DecodeExtSize(MCInst &Inst,
|
|
unsigned Insn,
|
|
uint64_t Address,
|
|
const void *Decoder) {
|
|
int Size = (int) Insn + 1;
|
|
Inst.addOperand(MCOperand::CreateImm(SignExtend32<16>(Size)));
|
|
return MCDisassembler::Success;
|
|
}
|