llvm-project/llvm/tools/edis/EDOperand.cpp

169 lines
4.7 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 "EDDisassembler.h"
#include "EDInst.h"
#include "EDOperand.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 operandFlags = inst.ThisInstInfo->operandFlags[opIndex];
if (operandFlags & kOperandFlagImmediate) {
numMCOperands = 1;
}
else if (operandFlags & kOperandFlagRegister) {
numMCOperands = 1;
}
else if (operandFlags & kOperandFlagMemory) {
if (operandFlags & kOperandFlagPCRelative) {
numMCOperands = 1;
}
else {
numMCOperands = 5;
}
}
else if (operandFlags & kOperandFlagEffectiveAddress) {
numMCOperands = 4;
}
}
mcOpIndex += numMCOperands;
}
EDOperand::~EDOperand() {
}
int EDOperand::evaluate(uint64_t &result,
EDRegisterReaderCallback callback,
void *arg) {
if (Disassembler.Key.Arch == Triple::x86 ||
Disassembler.Key.Arch == Triple::x86_64) {
uint8_t operandFlags = Inst.ThisInstInfo->operandFlags[OpIndex];
if (operandFlags & kOperandFlagImmediate) {
result = Inst.Inst->getOperand(MCOpIndex).getImm();
return 0;
}
if (operandFlags & kOperandFlagRegister) {
unsigned reg = Inst.Inst->getOperand(MCOpIndex).getReg();
return callback(&result, reg, arg);
}
if (operandFlags & kOperandFlagMemory ||
operandFlags & kOperandFlagEffectiveAddress){
if(operandFlags & kOperandFlagPCRelative) {
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;
}
else {
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();
//unsigned segmentReg = Inst.Inst->getOperand(MCOpIndex+4).getReg();
uint64_t addr = 0;
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;
}
}
return -1;
}
return -1;
}
int EDOperand::isRegister() {
return(Inst.ThisInstInfo->operandFlags[OpIndex] & kOperandFlagRegister);
}
unsigned EDOperand::regVal() {
return Inst.Inst->getOperand(MCOpIndex).getReg();
}
int EDOperand::isImmediate() {
return(Inst.ThisInstInfo->operandFlags[OpIndex] & kOperandFlagImmediate);
}
uint64_t EDOperand::immediateVal() {
return Inst.Inst->getOperand(MCOpIndex).getImm();
}
int EDOperand::isMemory() {
return(Inst.ThisInstInfo->operandFlags[OpIndex] & kOperandFlagMemory);
}
#ifdef __BLOCKS__
struct RegisterReaderWrapper {
EDRegisterBlock_t regBlock;
};
int readerWrapperCallback(uint64_t *value,
unsigned regID,
void *arg) {
struct RegisterReaderWrapper *wrapper = (struct RegisterReaderWrapper *)arg;
return wrapper->regBlock(value, regID);
}
int EDOperand::evaluate(uint64_t &result,
EDRegisterBlock_t regBlock) {
struct RegisterReaderWrapper wrapper;
wrapper.regBlock = regBlock;
return evaluate(result,
readerWrapperCallback,
(void*)&wrapper);
}
#endif