| //===-- 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: |
| case kOperandTypeARMDPRRegisterList: |
| case kOperandTypeARMSPRRegisterList: |
| break; |
| case kOperandTypeImmediate: |
| case kOperandTypeRegister: |
| case kOperandTypeARMBranchTarget: |
| case kOperandTypeARMSoImm: |
| case kOperandTypeARMRotImm: |
| case kOperandTypeThumb2SoImm: |
| case kOperandTypeARMSoImm2Part: |
| case kOperandTypeARMPredicate: |
| case kOperandTypeThumbITMask: |
| case kOperandTypeThumb2AddrModeImm8Offset: |
| case kOperandTypeARMTBAddrMode: |
| case kOperandTypeThumb2AddrModeImm8s4Offset: |
| case kOperandTypeARMAddrMode7: |
| case kOperandTypeThumb2AddrModeReg: |
| numMCOperands = 1; |
| break; |
| case kOperandTypeThumb2SoReg: |
| case kOperandTypeAddrModeImm12: |
| case kOperandTypeARMAddrMode2Offset: |
| case kOperandTypeARMAddrMode3Offset: |
| case kOperandTypeARMAddrMode4: |
| case kOperandTypeARMAddrMode5: |
| case kOperandTypeARMAddrModePC: |
| case kOperandTypeThumb2AddrModeImm8: |
| case kOperandTypeThumb2AddrModeImm12: |
| case kOperandTypeThumb2AddrModeImm8s4: |
| case kOperandTypeThumbAddrModeImmS1: |
| case kOperandTypeThumbAddrModeImmS2: |
| case kOperandTypeThumbAddrModeImmS4: |
| case kOperandTypeThumbAddrModeRR: |
| case kOperandTypeThumbAddrModeSP: |
| case kOperandTypeThumbAddrModePC: |
| numMCOperands = 2; |
| break; |
| case kOperandTypeARMSoReg: |
| case kOperandTypeLdStSOReg: |
| case kOperandTypeARMAddrMode2: |
| case kOperandTypeARMAddrMode3: |
| case kOperandTypeThumb2AddrModeSoReg: |
| case kOperandTypeThumbAddrModeRegS1: |
| case kOperandTypeThumbAddrModeRegS2: |
| case kOperandTypeThumbAddrModeRegS4: |
| 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 kOperandTypeThumbAddrModeRegS1: |
| case kOperandTypeThumbAddrModeRegS2: |
| case kOperandTypeThumbAddrModeRegS4: |
| 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 |