|  | //===-- 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; | 
|  |  | 
|  | Triple::ArchType arch = Disassembler.TgtTriple.getArch(); | 
|  |  | 
|  | if (arch == Triple::x86 || | 
|  | 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 (arch == Triple::arm || | 
|  | 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]; | 
|  |  | 
|  | Triple::ArchType arch = Disassembler.TgtTriple.getArch(); | 
|  |  | 
|  | switch (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 && 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) | 
|  | 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; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | 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 |