mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-23 15:29:51 +00:00
863f84648f
MCInst operands for ARM. This allows it to be more tolerant of malformed MCInsts or incorrect instruction metadata. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@129840 91177308-0d34-0410-b5e6-96231b3b80d8
307 lines
8.5 KiB
C++
307 lines
8.5 KiB
C++
//===-- EDOperand.cpp - LLVM Enhanced Disassembler ------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the Enhanced Disassembly library's operand class. The
|
|
// operand is responsible for allowing evaluation given a particular register
|
|
// context.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "EDOperand.h"
|
|
#include "EDDisassembler.h"
|
|
#include "EDInst.h"
|
|
#include "llvm/MC/EDInstInfo.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
using namespace llvm;
|
|
|
|
EDOperand::EDOperand(const EDDisassembler &disassembler,
|
|
const EDInst &inst,
|
|
unsigned int opIndex,
|
|
unsigned int &mcOpIndex) :
|
|
Disassembler(disassembler),
|
|
Inst(inst),
|
|
OpIndex(opIndex),
|
|
MCOpIndex(mcOpIndex) {
|
|
unsigned int numMCOperands = 0;
|
|
|
|
if (Disassembler.Key.Arch == Triple::x86 ||
|
|
Disassembler.Key.Arch == Triple::x86_64) {
|
|
uint8_t operandType = inst.ThisInstInfo->operandTypes[opIndex];
|
|
|
|
switch (operandType) {
|
|
default:
|
|
break;
|
|
case kOperandTypeImmediate:
|
|
numMCOperands = 1;
|
|
break;
|
|
case kOperandTypeRegister:
|
|
numMCOperands = 1;
|
|
break;
|
|
case kOperandTypeX86Memory:
|
|
numMCOperands = 5;
|
|
break;
|
|
case kOperandTypeX86EffectiveAddress:
|
|
numMCOperands = 4;
|
|
break;
|
|
case kOperandTypeX86PCRelative:
|
|
numMCOperands = 1;
|
|
break;
|
|
}
|
|
}
|
|
else if (Disassembler.Key.Arch == Triple::arm ||
|
|
Disassembler.Key.Arch == Triple::thumb) {
|
|
uint8_t operandType = inst.ThisInstInfo->operandTypes[opIndex];
|
|
|
|
switch (operandType) {
|
|
default:
|
|
case kOperandTypeARMRegisterList:
|
|
break;
|
|
case kOperandTypeImmediate:
|
|
case kOperandTypeRegister:
|
|
case kOperandTypeARMBranchTarget:
|
|
case kOperandTypeARMSoImm:
|
|
case kOperandTypeThumb2SoImm:
|
|
case kOperandTypeARMSoImm2Part:
|
|
case kOperandTypeARMPredicate:
|
|
case kOperandTypeThumbITMask:
|
|
case kOperandTypeThumb2AddrModeImm8Offset:
|
|
case kOperandTypeARMTBAddrMode:
|
|
case kOperandTypeThumb2AddrModeImm8s4Offset:
|
|
case kOperandTypeARMAddrMode7:
|
|
case kOperandTypeThumb2AddrModeReg:
|
|
numMCOperands = 1;
|
|
break;
|
|
case kOperandTypeThumb2SoReg:
|
|
case kOperandTypeARMAddrMode2Offset:
|
|
case kOperandTypeARMAddrMode3Offset:
|
|
case kOperandTypeARMAddrMode4:
|
|
case kOperandTypeARMAddrMode5:
|
|
case kOperandTypeARMAddrModePC:
|
|
case kOperandTypeThumb2AddrModeImm8:
|
|
case kOperandTypeThumb2AddrModeImm12:
|
|
case kOperandTypeThumb2AddrModeImm8s4:
|
|
case kOperandTypeThumbAddrModeRR:
|
|
case kOperandTypeThumbAddrModeSP:
|
|
numMCOperands = 2;
|
|
break;
|
|
case kOperandTypeARMSoReg:
|
|
case kOperandTypeARMAddrMode2:
|
|
case kOperandTypeARMAddrMode3:
|
|
case kOperandTypeThumb2AddrModeSoReg:
|
|
case kOperandTypeThumbAddrModeS1:
|
|
case kOperandTypeThumbAddrModeS2:
|
|
case kOperandTypeThumbAddrModeS4:
|
|
case kOperandTypeARMAddrMode6Offset:
|
|
numMCOperands = 3;
|
|
break;
|
|
case kOperandTypeARMAddrMode6:
|
|
numMCOperands = 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
mcOpIndex += numMCOperands;
|
|
}
|
|
|
|
EDOperand::~EDOperand() {
|
|
}
|
|
|
|
int EDOperand::evaluate(uint64_t &result,
|
|
EDRegisterReaderCallback callback,
|
|
void *arg) {
|
|
uint8_t operandType = Inst.ThisInstInfo->operandTypes[OpIndex];
|
|
|
|
switch (Disassembler.Key.Arch) {
|
|
default:
|
|
return -1;
|
|
case Triple::x86:
|
|
case Triple::x86_64:
|
|
switch (operandType) {
|
|
default:
|
|
return -1;
|
|
case kOperandTypeImmediate:
|
|
result = Inst.Inst->getOperand(MCOpIndex).getImm();
|
|
return 0;
|
|
case kOperandTypeRegister:
|
|
{
|
|
unsigned reg = Inst.Inst->getOperand(MCOpIndex).getReg();
|
|
return callback(&result, reg, arg);
|
|
}
|
|
case kOperandTypeX86PCRelative:
|
|
{
|
|
int64_t displacement = Inst.Inst->getOperand(MCOpIndex).getImm();
|
|
|
|
uint64_t ripVal;
|
|
|
|
// TODO fix how we do this
|
|
|
|
if (callback(&ripVal, Disassembler.registerIDWithName("RIP"), arg))
|
|
return -1;
|
|
|
|
result = ripVal + displacement;
|
|
return 0;
|
|
}
|
|
case kOperandTypeX86Memory:
|
|
case kOperandTypeX86EffectiveAddress:
|
|
{
|
|
unsigned baseReg = Inst.Inst->getOperand(MCOpIndex).getReg();
|
|
uint64_t scaleAmount = Inst.Inst->getOperand(MCOpIndex+1).getImm();
|
|
unsigned indexReg = Inst.Inst->getOperand(MCOpIndex+2).getReg();
|
|
int64_t displacement = Inst.Inst->getOperand(MCOpIndex+3).getImm();
|
|
|
|
uint64_t addr = 0;
|
|
|
|
unsigned segmentReg = Inst.Inst->getOperand(MCOpIndex+4).getReg();
|
|
|
|
if (segmentReg != 0 && Disassembler.Key.Arch == Triple::x86_64) {
|
|
unsigned fsID = Disassembler.registerIDWithName("FS");
|
|
unsigned gsID = Disassembler.registerIDWithName("GS");
|
|
|
|
if (segmentReg == fsID ||
|
|
segmentReg == gsID) {
|
|
uint64_t segmentBase;
|
|
if (!callback(&segmentBase, segmentReg, arg))
|
|
addr += segmentBase;
|
|
}
|
|
}
|
|
|
|
if (baseReg) {
|
|
uint64_t baseVal;
|
|
if (callback(&baseVal, baseReg, arg))
|
|
return -1;
|
|
addr += baseVal;
|
|
}
|
|
|
|
if (indexReg) {
|
|
uint64_t indexVal;
|
|
if (callback(&indexVal, indexReg, arg))
|
|
return -1;
|
|
addr += (scaleAmount * indexVal);
|
|
}
|
|
|
|
addr += displacement;
|
|
|
|
result = addr;
|
|
return 0;
|
|
}
|
|
} // switch (operandType)
|
|
break;
|
|
case Triple::arm:
|
|
case Triple::thumb:
|
|
switch (operandType) {
|
|
default:
|
|
return -1;
|
|
case kOperandTypeImmediate:
|
|
if (!Inst.Inst->getOperand(MCOpIndex).isImm())
|
|
return -1;
|
|
|
|
result = Inst.Inst->getOperand(MCOpIndex).getImm();
|
|
return 0;
|
|
case kOperandTypeRegister:
|
|
{
|
|
if (!Inst.Inst->getOperand(MCOpIndex).isReg())
|
|
return -1;
|
|
|
|
unsigned reg = Inst.Inst->getOperand(MCOpIndex).getReg();
|
|
return callback(&result, reg, arg);
|
|
}
|
|
case kOperandTypeARMBranchTarget:
|
|
{
|
|
if (!Inst.Inst->getOperand(MCOpIndex).isImm())
|
|
return -1;
|
|
|
|
int64_t displacement = Inst.Inst->getOperand(MCOpIndex).getImm();
|
|
|
|
uint64_t pcVal;
|
|
|
|
if (callback(&pcVal, Disassembler.registerIDWithName("PC"), arg))
|
|
return -1;
|
|
|
|
result = pcVal + displacement;
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int EDOperand::isRegister() {
|
|
return(Inst.ThisInstInfo->operandFlags[OpIndex] == kOperandTypeRegister);
|
|
}
|
|
|
|
unsigned EDOperand::regVal() {
|
|
return Inst.Inst->getOperand(MCOpIndex).getReg();
|
|
}
|
|
|
|
int EDOperand::isImmediate() {
|
|
return(Inst.ThisInstInfo->operandFlags[OpIndex] == kOperandTypeImmediate);
|
|
}
|
|
|
|
uint64_t EDOperand::immediateVal() {
|
|
return Inst.Inst->getOperand(MCOpIndex).getImm();
|
|
}
|
|
|
|
int EDOperand::isMemory() {
|
|
uint8_t operandType = Inst.ThisInstInfo->operandTypes[OpIndex];
|
|
|
|
switch (operandType) {
|
|
default:
|
|
return 0;
|
|
case kOperandTypeX86Memory:
|
|
case kOperandTypeX86PCRelative:
|
|
case kOperandTypeX86EffectiveAddress:
|
|
case kOperandTypeARMSoReg:
|
|
case kOperandTypeARMSoImm:
|
|
case kOperandTypeARMAddrMode2:
|
|
case kOperandTypeARMAddrMode2Offset:
|
|
case kOperandTypeARMAddrMode3:
|
|
case kOperandTypeARMAddrMode3Offset:
|
|
case kOperandTypeARMAddrMode4:
|
|
case kOperandTypeARMAddrMode5:
|
|
case kOperandTypeARMAddrMode6:
|
|
case kOperandTypeARMAddrMode7:
|
|
case kOperandTypeARMAddrModePC:
|
|
case kOperandTypeARMBranchTarget:
|
|
case kOperandTypeThumbAddrModeS1:
|
|
case kOperandTypeThumbAddrModeS2:
|
|
case kOperandTypeThumbAddrModeS4:
|
|
case kOperandTypeThumbAddrModeRR:
|
|
case kOperandTypeThumbAddrModeSP:
|
|
case kOperandTypeThumb2SoImm:
|
|
case kOperandTypeThumb2AddrModeImm8:
|
|
case kOperandTypeThumb2AddrModeImm8Offset:
|
|
case kOperandTypeThumb2AddrModeImm12:
|
|
case kOperandTypeThumb2AddrModeSoReg:
|
|
case kOperandTypeThumb2AddrModeImm8s4:
|
|
case kOperandTypeThumb2AddrModeReg:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
#ifdef __BLOCKS__
|
|
namespace {
|
|
struct RegisterReaderWrapper {
|
|
EDOperand::EDRegisterBlock_t regBlock;
|
|
};
|
|
}
|
|
|
|
static int readerWrapperCallback(uint64_t *value, unsigned regID, void *arg) {
|
|
RegisterReaderWrapper *wrapper = (RegisterReaderWrapper *)arg;
|
|
return wrapper->regBlock(value, regID);
|
|
}
|
|
|
|
int EDOperand::evaluate(uint64_t &result, EDRegisterBlock_t regBlock) {
|
|
RegisterReaderWrapper wrapper;
|
|
wrapper.regBlock = regBlock;
|
|
return evaluate(result, readerWrapperCallback, (void*)&wrapper);
|
|
}
|
|
#endif
|