Stefan Pintilie 11fbd0c6ab [PowerPC] Remove asserts from the disassembler.
My previous patch had added a couple of asserts to the disassembler.
The problem with this is that the disassembler is not just used for the
text section it is also used to disassemble the data section of an
object where the bytes do not necessarily represent instructions. If the
data in the data section happens to look like an illegal instruction
then llvm-objdump will assert on data because it is finding an illegal
instruction that is not actually an instruction at all.

Reviewed By: nemanjai, #powerpc

Differential Revision: https://reviews.llvm.org/D149711
2023-05-24 13:22:23 -04:00

407 lines
16 KiB
C++

//===------ PPCDisassembler.cpp - Disassembler for PowerPC ------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "TargetInfo/PowerPCTargetInfo.h"
#include "llvm/MC/MCDecoderOps.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
DEFINE_PPC_REGCLASSES
#define DEBUG_TYPE "ppc-disassembler"
typedef MCDisassembler::DecodeStatus DecodeStatus;
namespace {
class PPCDisassembler : public MCDisassembler {
bool IsLittleEndian;
public:
PPCDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
bool IsLittleEndian)
: MCDisassembler(STI, Ctx), IsLittleEndian(IsLittleEndian) {}
DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &CStream) const override;
};
} // end anonymous namespace
static MCDisassembler *createPPCDisassembler(const Target &T,
const MCSubtargetInfo &STI,
MCContext &Ctx) {
return new PPCDisassembler(STI, Ctx, /*IsLittleEndian=*/false);
}
static MCDisassembler *createPPCLEDisassembler(const Target &T,
const MCSubtargetInfo &STI,
MCContext &Ctx) {
return new PPCDisassembler(STI, Ctx, /*IsLittleEndian=*/true);
}
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCDisassembler() {
// Register the disassembler for each target.
TargetRegistry::RegisterMCDisassembler(getThePPC32Target(),
createPPCDisassembler);
TargetRegistry::RegisterMCDisassembler(getThePPC32LETarget(),
createPPCLEDisassembler);
TargetRegistry::RegisterMCDisassembler(getThePPC64Target(),
createPPCDisassembler);
TargetRegistry::RegisterMCDisassembler(getThePPC64LETarget(),
createPPCLEDisassembler);
}
static DecodeStatus decodeCondBrTarget(MCInst &Inst, unsigned Imm,
uint64_t /*Address*/,
const MCDisassembler * /*Decoder*/) {
Inst.addOperand(MCOperand::createImm(SignExtend32<14>(Imm)));
return MCDisassembler::Success;
}
static DecodeStatus decodeDirectBrTarget(MCInst &Inst, unsigned Imm,
uint64_t /*Address*/,
const MCDisassembler * /*Decoder*/) {
int32_t Offset = SignExtend32<24>(Imm);
Inst.addOperand(MCOperand::createImm(Offset));
return MCDisassembler::Success;
}
// FIXME: These can be generated by TableGen from the existing register
// encoding values!
template <std::size_t N>
static DecodeStatus decodeRegisterClass(MCInst &Inst, uint64_t RegNo,
const MCPhysReg (&Regs)[N]) {
if (RegNo >= N)
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createReg(Regs[RegNo]));
return MCDisassembler::Success;
}
static DecodeStatus DecodeCRRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, CRRegs);
}
static DecodeStatus DecodeCRBITRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, CRBITRegs);
}
static DecodeStatus DecodeF4RCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, FRegs);
}
static DecodeStatus DecodeF8RCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, FRegs);
}
static DecodeStatus DecodeFpRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
if (RegNo > 30 || (RegNo & 1))
return MCDisassembler::Fail;
return decodeRegisterClass(Inst, RegNo >> 1, FpRegs);
}
static DecodeStatus DecodeVFRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, VFRegs);
}
static DecodeStatus DecodeVRRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, VRegs);
}
static DecodeStatus DecodeVSRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, VSRegs);
}
static DecodeStatus DecodeVSFRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, VSFRegs);
}
static DecodeStatus DecodeVSSRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, VSSRegs);
}
static DecodeStatus DecodeGPRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, RRegs);
}
static DecodeStatus
DecodeGPRC_NOR0RegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, RRegsNoR0);
}
static DecodeStatus DecodeG8RCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, XRegs);
}
static DecodeStatus DecodeG8pRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, XRegs);
}
static DecodeStatus
DecodeG8RC_NOX0RegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, XRegsNoX0);
}
#define DecodePointerLikeRegClass0 DecodeGPRCRegisterClass
#define DecodePointerLikeRegClass1 DecodeGPRC_NOR0RegisterClass
static DecodeStatus DecodeSPERCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, SPERegs);
}
static DecodeStatus DecodeACCRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, ACCRegs);
}
static DecodeStatus DecodeWACCRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, WACCRegs);
}
static DecodeStatus DecodeWACC_HIRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, WACC_HIRegs);
}
// TODO: Make this function static when the register class is used by a new
// instruction.
DecodeStatus DecodeDMRROWRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, DMRROWRegs);
}
static DecodeStatus DecodeDMRROWpRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, DMRROWpRegs);
}
static DecodeStatus DecodeDMRRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, DMRRegs);
}
// TODO: Make this function static when the register class is used by a new
// instruction.
DecodeStatus DecodeDMRpRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address, const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, DMRpRegs);
}
static DecodeStatus DecodeVSRpRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return decodeRegisterClass(Inst, RegNo, VSRpRegs);
}
#define DecodeQSRCRegisterClass DecodeQFRCRegisterClass
#define DecodeQBRCRegisterClass DecodeQFRCRegisterClass
template <unsigned N>
static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
if (!isUInt<N>(Imm))
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createImm(Imm));
return MCDisassembler::Success;
}
template <unsigned N>
static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
if (!isUInt<N>(Imm))
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm)));
return MCDisassembler::Success;
}
static DecodeStatus decodeImmZeroOperand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
if (Imm != 0)
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createImm(Imm));
return MCDisassembler::Success;
}
static DecodeStatus decodeVSRpEvenOperands(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
if (RegNo & 1)
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createReg(VSRpRegs[RegNo >> 1]));
return MCDisassembler::Success;
}
static DecodeStatus decodeDispRIXOperand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
// The rix displacement is an immediate shifted by 2
Inst.addOperand(MCOperand::createImm(SignExtend64<16>(Imm << 2)));
return MCDisassembler::Success;
}
static DecodeStatus decodeDispRIHashOperand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
// Decode the disp field for a hash store or hash check operation.
// The field is composed of an immediate value that is 6 bits
// and covers the range -8 to -512. The immediate is always negative and 2s
// complement which is why we sign extend a 7 bit value.
const int64_t Disp = SignExtend64<7>((Imm & 0x3F) + 64) * 8;
Inst.addOperand(MCOperand::createImm(Disp));
return MCDisassembler::Success;
}
static DecodeStatus decodeDispRIX16Operand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
// The rix16 displacement has 12-bits which are shifted by 4.
Inst.addOperand(MCOperand::createImm(SignExtend64<16>(Imm << 4)));
return MCDisassembler::Success;
}
static DecodeStatus decodeDispSPE8Operand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
// Decode the dispSPE8 field, which has 5-bits, 8-byte aligned.
uint64_t Disp = Imm & 0x1F;
Inst.addOperand(MCOperand::createImm(Disp << 3));
return MCDisassembler::Success;
}
static DecodeStatus decodeDispSPE4Operand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
// Decode the dispSPE8 field, which has 5-bits, 4-byte aligned.
uint64_t Disp = Imm & 0x1F;
Inst.addOperand(MCOperand::createImm(Disp << 2));
return MCDisassembler::Success;
}
static DecodeStatus decodeDispSPE2Operand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
// Decode the dispSPE8 field, which has 5-bits, 2-byte aligned.
uint64_t Disp = Imm & 0x1F;
Inst.addOperand(MCOperand::createImm(Disp << 1));
return MCDisassembler::Success;
}
static DecodeStatus decodeCRBitMOperand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
// The cr bit encoding is 0x80 >> cr_reg_num.
unsigned Zeros = llvm::countr_zero(Imm);
if (Zeros >= 8)
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createReg(CRRegs[7 - Zeros]));
return MCDisassembler::Success;
}
#include "PPCGenDisassemblerTables.inc"
DecodeStatus PPCDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
ArrayRef<uint8_t> Bytes,
uint64_t Address,
raw_ostream &CS) const {
auto *ReadFunc = IsLittleEndian ? support::endian::read32le
: support::endian::read32be;
// If this is an 8-byte prefixed instruction, handle it here.
// Note: prefixed instructions aren't technically 8-byte entities - the prefix
// appears in memory at an address 4 bytes prior to that of the base
// instruction regardless of endianness. So we read the two pieces and
// rebuild the 8-byte instruction.
// TODO: In this function we call decodeInstruction several times with
// different decoder tables. It may be possible to only call once by
// looking at the top 6 bits of the instruction.
if (STI.hasFeature(PPC::FeaturePrefixInstrs) && Bytes.size() >= 8) {
uint32_t Prefix = ReadFunc(Bytes.data());
uint32_t BaseInst = ReadFunc(Bytes.data() + 4);
uint64_t Inst = BaseInst | (uint64_t)Prefix << 32;
DecodeStatus result = decodeInstruction(DecoderTable64, MI, Inst, Address,
this, STI);
if (result != MCDisassembler::Fail) {
Size = 8;
return result;
}
}
// Get the four bytes of the instruction.
Size = 4;
if (Bytes.size() < 4) {
Size = 0;
return MCDisassembler::Fail;
}
// Read the instruction in the proper endianness.
uint64_t Inst = ReadFunc(Bytes.data());
if (STI.hasFeature(PPC::FeatureSPE)) {
DecodeStatus result =
decodeInstruction(DecoderTableSPE32, MI, Inst, Address, this, STI);
if (result != MCDisassembler::Fail)
return result;
}
return decodeInstruction(DecoderTable32, MI, Inst, Address, this, STI);
}