mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/GP-0_Dan_movePcodeEmulatePackages'
This commit is contained in:
commit
520c77e77d
126 changed files with 5 additions and 6 deletions
|
@ -1,63 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import ghidra.pcode.pcoderaw.PcodeOpRaw;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
/// \brief A breakpoint object
|
||||
///
|
||||
/// This is a base class for breakpoint objects in an emulator. The breakpoints are implemented
|
||||
/// as callback method, which is overridden for the particular behavior needed by the emulator.
|
||||
/// Each derived class must override either
|
||||
/// - pcodeCallback()
|
||||
/// - addressCallback()
|
||||
///
|
||||
/// depending on whether the breakpoint is tailored for a particular pcode op or for
|
||||
/// a machine address.
|
||||
public class BreakCallBack {
|
||||
protected Emulate emulate; ///< The emulator currently associated with this breakpoint
|
||||
|
||||
public BreakCallBack() { ///< Generic breakpoint constructor
|
||||
emulate = null;
|
||||
}
|
||||
|
||||
/// This routine is invoked during emulation, if this breakpoint has somehow been associated with
|
||||
/// this kind of pcode op. The callback can perform any operation on the emulator context it wants.
|
||||
/// It then returns \b true if these actions are intended to replace the action of the pcode op itself.
|
||||
/// Or it returns \b false if the pcode op should still have its normal effect on the emulator context.
|
||||
/// \param op is the particular pcode operation where the break occurs.
|
||||
/// \return \b true if the normal pcode op action should not occur
|
||||
public boolean pcodeCallback(PcodeOpRaw op) { ///< Call back method for pcode based breakpoints
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// This routine is invoked during emulation, if this breakpoint has somehow been associated with
|
||||
/// this address. The callback can perform any operation on the emulator context it wants. It then
|
||||
/// returns \b true if these actions are intended to replace the action of the \b entire machine
|
||||
/// instruction at this address. Or it returns \b false if the machine instruction should still be
|
||||
/// executed normally.
|
||||
/// \param addr is the address where the break has occurred
|
||||
/// \return \b true if the machine instruction should not be executed
|
||||
public boolean addressCallback(Address addr) { ///< Call back method for address based breakpoints
|
||||
return false;
|
||||
}
|
||||
public void setEmulate(Emulate emu) { ///< Associate a particular emulator with this breakpoint
|
||||
emulate = emu;
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import ghidra.pcode.pcoderaw.PcodeOpRaw;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
|
||||
/// \brief A collection of breakpoints for the emulator
|
||||
///
|
||||
/// A BreakTable keeps track of an arbitrary number of breakpoints for an emulator.
|
||||
/// Breakpoints are either associated with a particular user-defined pcode op,
|
||||
/// or with a specific machine address (as in a standard debugger). Through the BreakTable
|
||||
/// object, an emulator can invoke breakpoints through the two methods
|
||||
/// - doPcodeOpBreak()
|
||||
/// - doAddressBreak()
|
||||
///
|
||||
/// depending on the type of breakpoint they currently want to invoke
|
||||
|
||||
public interface BreakTable {
|
||||
|
||||
/// \brief Associate a particular emulator with breakpoints in this table
|
||||
///
|
||||
/// Breakpoints may need access to the context in which they are invoked. This
|
||||
/// routine provides the context for all breakpoints in the table.
|
||||
/// \param emu is the Emulate context
|
||||
public abstract void setEmulate(Emulate emu);
|
||||
|
||||
/// \brief Invoke any breakpoints associated with this particular pcodeop
|
||||
///
|
||||
/// Within the table, the first breakpoint which is designed to work with this particular
|
||||
/// kind of pcode operation is invoked. If there was a breakpoint and it was designed
|
||||
/// to \e replace the action of the pcode op, then \b true is returned.
|
||||
/// \param curop is the instance of a pcode op to test for breakpoints
|
||||
/// \return \b true if the action of the pcode op is performed by the breakpoint
|
||||
public abstract boolean doPcodeOpBreak(PcodeOpRaw curop);
|
||||
|
||||
/// \brief Invoke any breakpoints associated with this machine address
|
||||
///
|
||||
/// Within the table, the first breakpoint which is designed to work with at this address
|
||||
/// is invoked. If there was a breakpoint, and if it was designed to \e replace
|
||||
/// the action of the machine instruction, then \b true is returned.
|
||||
/// \param addr is address to test for breakpoints
|
||||
/// \return \b true is the machine instruction has been replaced by a breakpoint
|
||||
public abstract boolean doAddressBreak(Address addr);
|
||||
}
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import generic.stl.*;
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.pcode.pcoderaw.PcodeOpRaw;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
/// \brief A basic instantiation of a breakpoint table
|
||||
///
|
||||
/// This object allows breakpoints to registered in the table via either
|
||||
/// - registerPcodeCallback() or
|
||||
/// = registerAddressCallback()
|
||||
///
|
||||
/// Breakpoints are stored in map containers, and the core BreakTable methods
|
||||
/// are implemented to search in these containers
|
||||
public class BreakTableCallBack implements BreakTable {
|
||||
|
||||
public static final String DEFAULT_NAME = "*";
|
||||
|
||||
private Emulate emulate;
|
||||
private SleighLanguage language;
|
||||
// a container of address based breakpoints
|
||||
private MapSTL<Address, BreakCallBack> addressCallback =
|
||||
new ComparableMapSTL<>();
|
||||
// a container of pcode based breakpoints
|
||||
private MapSTL<Long, BreakCallBack> pcodeCallback = new ComparableMapSTL<>();
|
||||
private BreakCallBack defaultPcodeCallback;
|
||||
|
||||
/// The break table needs a translator object so user-defined pcode ops can be registered against
|
||||
/// by name.
|
||||
/// \param t is the translator object
|
||||
public BreakTableCallBack(SleighLanguage language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
/// Any time the emulator is about to execute a user-defined pcode op with the given name,
|
||||
/// the indicated breakpoint is invoked first. The break table does \e not assume responsibility
|
||||
/// for freeing the breakpoint object.
|
||||
/// \param name is the name of the user-defined pcode op
|
||||
/// \param func is the breakpoint object to associate with the pcode op
|
||||
public void registerPcodeCallback(String name, BreakCallBack func) {
|
||||
func.setEmulate(emulate);
|
||||
if (DEFAULT_NAME.equals(name)) {
|
||||
defaultPcodeCallback = func;
|
||||
return;
|
||||
}
|
||||
int numUserOps = language.getNumberOfUserDefinedOpNames();
|
||||
for (int i = 0; i < numUserOps; i++) {
|
||||
if (name.equals(language.getUserDefinedOpName(i))) {
|
||||
pcodeCallback.add((long) i, func);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// tell them what names are valid, probably not worth doing, but hate just getting no context on an error...
|
||||
StringBuilder names = new StringBuilder();
|
||||
for (int i = 0; i < numUserOps; i++) {
|
||||
names.append(language.getUserDefinedOpName(i));
|
||||
if (i < (numUserOps - 1))
|
||||
names.append(", ");
|
||||
}
|
||||
throw new LowlevelError("Bad userop name: " + name + "\n" + "Must be one of:\n" + names);
|
||||
}
|
||||
|
||||
/// Unregister the currently registered PcodeCallback handler for the
|
||||
/// specified name
|
||||
/// \param name is the name of the user-defined pcode op
|
||||
public void unregisterPcodeCallback(String name) {
|
||||
if (DEFAULT_NAME.equals(name)) {
|
||||
defaultPcodeCallback = null;
|
||||
return;
|
||||
}
|
||||
int numUserOps = language.getNumberOfUserDefinedOpNames();
|
||||
for (int i = 0; i < numUserOps; i++) {
|
||||
if (name.equals(language.getUserDefinedOpName(i))) {
|
||||
pcodeCallback.remove((long) i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new LowlevelError("Bad userop name: " + name);
|
||||
}
|
||||
|
||||
/// Any time the emulator is about to execute (the pcode translation of) a particular machine
|
||||
/// instruction at this address, the indicated breakpoint is invoked first. The break table
|
||||
/// does \e not assume responsibility for freeing the breakpoint object.
|
||||
/// \param addr is the address associated with the breakpoint
|
||||
/// \param func is the breakpoint being registered
|
||||
public void registerAddressCallback(Address addr, BreakCallBack func) {
|
||||
func.setEmulate(emulate);
|
||||
addressCallback.add(addr, func);
|
||||
}
|
||||
|
||||
public void unregisterAddressCallback(Address addr) {
|
||||
addressCallback.remove(addr);
|
||||
}
|
||||
|
||||
/// This routine invokes the setEmulate method on each breakpoint currently in the table
|
||||
/// \param emu is the emulator to be associated with the breakpoints
|
||||
@Override
|
||||
public void setEmulate(Emulate emu) {
|
||||
// Make sure all callbbacks are aware of new emulator
|
||||
emulate = emu;
|
||||
IteratorSTL<Pair<Address, BreakCallBack>> iter1;
|
||||
|
||||
for (iter1 = addressCallback.begin(); !iter1.isEnd(); iter1.increment()) {
|
||||
iter1.get().second.setEmulate(emu);
|
||||
}
|
||||
if (defaultPcodeCallback != null) {
|
||||
defaultPcodeCallback.setEmulate(emu);
|
||||
}
|
||||
IteratorSTL<Pair<Long, BreakCallBack>> iter2;
|
||||
for (iter2 = pcodeCallback.begin(); !iter2.isEnd(); iter2.increment()) {
|
||||
iter2.get().second.setEmulate(emu);
|
||||
}
|
||||
}
|
||||
|
||||
/// This routine examines the pcode-op based container for any breakpoints associated with the
|
||||
/// given op. If one is found, its pcodeCallback method is invoked.
|
||||
/// \param curop is pcode op being checked for breakpoints
|
||||
/// \return \b true if the breakpoint exists and returns \b true, otherwise return \b false
|
||||
@Override
|
||||
public boolean doPcodeOpBreak(PcodeOpRaw curop) {
|
||||
long val = curop.getInput(0).getOffset();
|
||||
IteratorSTL<Pair<Long, BreakCallBack>> iter = pcodeCallback.find(val);
|
||||
if (iter.isEnd()) {
|
||||
if (defaultPcodeCallback != null) {
|
||||
return defaultPcodeCallback.pcodeCallback(curop);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return iter.get().second.pcodeCallback(curop);
|
||||
}
|
||||
|
||||
/// This routine examines the address based container for any breakpoints associated with the
|
||||
/// given address. If one is found, its addressCallback method is invoked.
|
||||
/// \param addr is the address being checked for breakpoints
|
||||
/// \return \b true if the breakpoint exists and returns \b true, otherwise return \b false
|
||||
@Override
|
||||
public boolean doAddressBreak(Address addr) {
|
||||
IteratorSTL<Pair<Address, BreakCallBack>> iter = addressCallback.find(addr);
|
||||
if (iter.isEnd()) {
|
||||
return false;
|
||||
}
|
||||
return iter.get().second.addressCallback(addr);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,774 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.pcode.memstate.MemoryState;
|
||||
import ghidra.pcode.memstate.UniqueMemoryBank;
|
||||
import ghidra.pcode.opbehavior.*;
|
||||
import ghidra.pcode.pcoderaw.PcodeOpRaw;
|
||||
import ghidra.program.disassemble.Disassembler;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
/// \brief A SLEIGH based implementation of the Emulate interface
|
||||
///
|
||||
/// This implementation uses a Translate object to translate machine instructions into
|
||||
/// pcode and caches pcode ops for later use by the emulator. The pcode is cached as soon
|
||||
/// as the execution address is set, either explicitly, or via branches and fallthrus. There
|
||||
/// are additional methods for inspecting the pcode ops in the current instruction as a sequence.
|
||||
|
||||
public class Emulate {
|
||||
|
||||
private MemoryState memstate; // the memory state of the emulator.
|
||||
private UniqueMemoryBank uniqueBank;
|
||||
|
||||
private BreakTable breaktable; ///< The table of breakpoints
|
||||
private Address current_address; ///< Address of current instruction being executed
|
||||
private Address last_execute_address;
|
||||
private volatile EmulateExecutionState executionState = EmulateExecutionState.STOPPED;
|
||||
private RuntimeException faultCause;
|
||||
private int current_op; ///< Index of current pcode op within machine instruction
|
||||
private int last_op; /// index of last pcode op executed
|
||||
private int instruction_length; ///< Length of current instruction in bytes (must include any delay slots)
|
||||
|
||||
private final SleighLanguage language;
|
||||
private final AddressFactory addrFactory;
|
||||
private Register pcReg;
|
||||
|
||||
private InstructionBlock lastPseudoInstructionBlock;
|
||||
private Disassembler pseudoDisassembler;
|
||||
private Instruction pseudoInstruction;
|
||||
private PcodeOp[] pcode; ///< The cache of current pcode ops
|
||||
|
||||
private RegisterValue nextContextRegisterValue = null;
|
||||
|
||||
private EmulateMemoryStateBuffer memBuffer; // used for instruction parsing
|
||||
|
||||
private EmulateInstructionStateModifier instructionStateModifier;
|
||||
|
||||
/// \param t is the SLEIGH translator
|
||||
/// \param s is the MemoryState the emulator should manipulate
|
||||
/// \param b is the table of breakpoints the emulator should invoke
|
||||
public Emulate(SleighLanguage lang, MemoryState s, BreakTable b) {
|
||||
memstate = s;
|
||||
this.language = lang;
|
||||
this.addrFactory = lang.getAddressFactory();
|
||||
pcReg = lang.getProgramCounter();
|
||||
breaktable = b;
|
||||
breaktable.setEmulate(this);
|
||||
memBuffer =
|
||||
new EmulateMemoryStateBuffer(s, addrFactory.getDefaultAddressSpace().getMinAddress());
|
||||
|
||||
uniqueBank =
|
||||
new UniqueMemoryBank(lang.getAddressFactory().getUniqueSpace(), lang.isBigEndian());
|
||||
memstate.setMemoryBank(uniqueBank);
|
||||
|
||||
// emitterContext = new EmulateDisassemblerContext(lang, s);
|
||||
|
||||
pseudoDisassembler =
|
||||
Disassembler.getDisassembler(lang, addrFactory, TaskMonitor.DUMMY, null);
|
||||
|
||||
initInstuctionStateModifier();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
executionState = EmulateExecutionState.STOPPED;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void initInstuctionStateModifier() {
|
||||
String classname = language
|
||||
.getProperty(GhidraLanguagePropertyKeys.EMULATE_INSTRUCTION_STATE_MODIFIER_CLASS);
|
||||
if (classname == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Class<?> c = Class.forName(classname);
|
||||
if (!EmulateInstructionStateModifier.class.isAssignableFrom(c)) {
|
||||
Msg.error(this,
|
||||
"Language " + language.getLanguageID() + " does not specify a valid " +
|
||||
GhidraLanguagePropertyKeys.EMULATE_INSTRUCTION_STATE_MODIFIER_CLASS);
|
||||
throw new RuntimeException(classname + " does not implement interface " +
|
||||
EmulateInstructionStateModifier.class.getName());
|
||||
}
|
||||
Class<? extends EmulateInstructionStateModifier> instructionStateModifierClass =
|
||||
(Class<? extends EmulateInstructionStateModifier>) c;
|
||||
Constructor<? extends EmulateInstructionStateModifier> constructor =
|
||||
instructionStateModifierClass.getConstructor(Emulate.class);
|
||||
instructionStateModifier = constructor.newInstance(this);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, "Language " + language.getLanguageID() + " does not specify a valid " +
|
||||
GhidraLanguagePropertyKeys.EMULATE_INSTRUCTION_STATE_MODIFIER_CLASS);
|
||||
throw new RuntimeException(
|
||||
"Failed to instantiate " + classname + " for language " + language.getLanguageID(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
public Language getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
/// Since the emulator can single step through individual pcode operations, the machine state
|
||||
/// may be halted in the \e middle of a single machine instruction, unlike conventional debuggers.
|
||||
/// This routine can be used to determine if execution is actually at the beginning of a machine
|
||||
/// instruction.
|
||||
/// \return \b true if the next pcode operation is at the start of the instruction translation
|
||||
public boolean isInstructionStart() {
|
||||
return executionState == EmulateExecutionState.STOPPED ||
|
||||
executionState == EmulateExecutionState.BREAKPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current emulator execution state
|
||||
*/
|
||||
public EmulateExecutionState getExecutionState() {
|
||||
return executionState;
|
||||
}
|
||||
|
||||
/// \return the currently executing machine address
|
||||
public Address getExecuteAddress() {
|
||||
return current_address;
|
||||
}
|
||||
|
||||
/// \return the last address
|
||||
public Address getLastExecuteAddress() {
|
||||
return last_execute_address;
|
||||
}
|
||||
|
||||
public EmulateDisassemblerContext getNewDisassemblerContext() {
|
||||
return new EmulateDisassemblerContext(language, getContextRegisterValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get length of instruction including any delay-slotted instructions.
|
||||
* Must be called by emitPcode with lastPseudoInstructionBlock properly set.
|
||||
* @param instr
|
||||
* @return length of instruction in bytes for use in computing fall-through location
|
||||
*/
|
||||
private int getInstructionLength(Instruction instr) throws InstructionDecodeException {
|
||||
int length = instr.getLength();
|
||||
int delaySlots = instr.getDelaySlotDepth();
|
||||
while (delaySlots != 0) {
|
||||
try {
|
||||
Address nextAddr = instr.getAddress().addNoWrap(instr.getLength());
|
||||
Instruction nextInstr = lastPseudoInstructionBlock.getInstructionAt(nextAddr);
|
||||
if (nextInstr == null) {
|
||||
throw new InstructionDecodeException("Failed to parse delay slot instruction",
|
||||
nextAddr);
|
||||
}
|
||||
instr = nextInstr;
|
||||
length += instr.getLength();
|
||||
--delaySlots;
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
throw new InstructionDecodeException(
|
||||
"Failed to parse delay slot instruction at end of address space",
|
||||
instr.getAddress());
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
private PcodeOp[] emitPcode(Address addr) throws InstructionDecodeException {
|
||||
|
||||
memBuffer.setAddress(addr);
|
||||
pcode = null;
|
||||
pseudoInstruction = null;
|
||||
|
||||
if (lastPseudoInstructionBlock != null) {
|
||||
pseudoInstruction = lastPseudoInstructionBlock.getInstructionAt(addr);
|
||||
if (pseudoInstruction != null) {
|
||||
instruction_length = getInstructionLength(pseudoInstruction);
|
||||
return pseudoInstruction.getPcode(false);
|
||||
}
|
||||
|
||||
InstructionError error = lastPseudoInstructionBlock.getInstructionConflict();
|
||||
if (error != null && addr.equals(error.getInstructionAddress())) {
|
||||
throw new InstructionDecodeException(error.getConflictMessage(), addr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lastPseudoInstructionBlock =
|
||||
pseudoDisassembler.pseudoDisassembleBlock(memBuffer, nextContextRegisterValue, 1);
|
||||
nextContextRegisterValue = null;
|
||||
if (lastPseudoInstructionBlock != null) {
|
||||
pseudoInstruction = lastPseudoInstructionBlock.getInstructionAt(addr);
|
||||
if (pseudoInstruction != null) {
|
||||
instruction_length = getInstructionLength(pseudoInstruction);
|
||||
return pseudoInstruction.getPcode(false);
|
||||
}
|
||||
InstructionError error = lastPseudoInstructionBlock.getInstructionConflict();
|
||||
if (error != null && addr.equals(error.getInstructionAddress())) {
|
||||
throw new InstructionDecodeException(error.getConflictMessage(), addr);
|
||||
}
|
||||
}
|
||||
|
||||
throw new InstructionDecodeException("unknown reason", addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current context register value. The context value returned reflects
|
||||
* its state when the previously executed instruction was
|
||||
* parsed/executed. The context value returned will feed into the next
|
||||
* instruction to be parsed with its non-flowing bits cleared and
|
||||
* any future context state merged in. If no instruction has been executed,
|
||||
* the explicitly set context will be returned. A null value is returned
|
||||
* if no context register is defined by the language or initial context has
|
||||
* not been set.
|
||||
*/
|
||||
public RegisterValue getContextRegisterValue() {
|
||||
Register contextReg = language.getContextBaseRegister();
|
||||
if (contextReg == Register.NO_CONTEXT) {
|
||||
return null;
|
||||
}
|
||||
if (pseudoInstruction != null) {
|
||||
return pseudoInstruction.getRegisterValue(contextReg);
|
||||
}
|
||||
return nextContextRegisterValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context register value at the current execute address.
|
||||
* The Emulator should not be running when this method is invoked.
|
||||
* Only flowing context bits should be set, as non-flowing bits
|
||||
* will be cleared prior to parsing on instruction. In addition,
|
||||
* any future context state set by the pcode emitter will
|
||||
* take precedence over context set using this method. This method
|
||||
* is primarily intended to be used to establish the initial
|
||||
* context state.
|
||||
* @param regValue
|
||||
*/
|
||||
public void setContextRegisterValue(RegisterValue regValue) {
|
||||
if (executionState != EmulateExecutionState.STOPPED &&
|
||||
executionState != EmulateExecutionState.BREAKPOINT) {
|
||||
throw new IllegalStateException("emulator is not STOPPED");
|
||||
}
|
||||
if (regValue != null) {
|
||||
Register reg = regValue.getRegister();
|
||||
if (!reg.isProcessorContext()) {
|
||||
throw new IllegalArgumentException("processor context register required");
|
||||
}
|
||||
if (!reg.isBaseRegister()) {
|
||||
regValue = regValue.getBaseRegisterValue();
|
||||
reg = regValue.getRegister();
|
||||
if (nextContextRegisterValue != null) {
|
||||
regValue = nextContextRegisterValue.combineValues(regValue);
|
||||
}
|
||||
}
|
||||
if (!reg.equals(language.getContextBaseRegister())) {
|
||||
throw new IllegalArgumentException("invalid processor context register");
|
||||
}
|
||||
}
|
||||
nextContextRegisterValue = regValue;
|
||||
lastPseudoInstructionBlock = null;
|
||||
pseudoInstruction = null;
|
||||
}
|
||||
|
||||
/// Update the iterator into the current pcode cache, and if necessary, generate
|
||||
/// the pcode for the fallthru instruction and reset the iterator.
|
||||
public void fallthruOp() {
|
||||
current_op += 1;
|
||||
if (current_op >= pcode.length) {
|
||||
last_op = -1;
|
||||
setCurrentAddress(current_address.addWrap(instruction_length));
|
||||
}
|
||||
}
|
||||
|
||||
public void executeConditionalBranch(PcodeOpRaw op) {
|
||||
Varnode condVar = op.getInput(1);
|
||||
boolean takeBranch = false;
|
||||
if (condVar.getSize() > 8) {
|
||||
takeBranch = !memstate.getBigInteger(condVar, false).equals(BigInteger.ZERO);
|
||||
}
|
||||
else {
|
||||
takeBranch = memstate.getValue(condVar) != 0;
|
||||
}
|
||||
if (takeBranch) {
|
||||
executeBranch(op);
|
||||
}
|
||||
else {
|
||||
fallthruOp();
|
||||
}
|
||||
}
|
||||
|
||||
/// Since the full instruction is cached, we can do relative branches properly
|
||||
/// \param op is the particular branch op being executed
|
||||
public void executeBranch(PcodeOpRaw op) {
|
||||
Address destaddr = op.getInput(0).getAddress();
|
||||
if (destaddr.getAddressSpace().isConstantSpace()) {
|
||||
long id = destaddr.getOffset();
|
||||
id = id + current_op;
|
||||
current_op = (int) id;
|
||||
if (current_op == pcode.length) {
|
||||
fallthruOp();
|
||||
}
|
||||
else if ((current_op < 0) || (current_op >= pcode.length)) {
|
||||
throw new LowlevelError("Bad intra-instruction branch");
|
||||
}
|
||||
}
|
||||
else {
|
||||
setCurrentAddress(destaddr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Give instuctionStateModifier first shot at executing custom pcodeop,
|
||||
/// if not supported look for a breakpoint for the given user-defined op and invoke it.
|
||||
/// If it doesn't exist, or doesn't replace the action, throw an exception
|
||||
/// \param op is the particular user-defined op being executed
|
||||
public void executeCallother(PcodeOpRaw op) throws UnimplementedCallOtherException {
|
||||
if ((instructionStateModifier == null || !instructionStateModifier.executeCallOther(op)) &&
|
||||
!breaktable.doPcodeOpBreak(op)) {
|
||||
int userOp = (int) op.getInput(0).getOffset();
|
||||
String pcodeOpName = language.getUserDefinedOpName(userOp);
|
||||
throw new UnimplementedCallOtherException(op, pcodeOpName);
|
||||
}
|
||||
fallthruOp();
|
||||
}
|
||||
|
||||
/// Set the current execution address and cache the pcode translation of the machine instruction
|
||||
/// at that address
|
||||
/// \param addr is the address where execution should continue
|
||||
public void setExecuteAddress(Address addr) {
|
||||
if (addr != null && addr.equals(current_address)) {
|
||||
return;
|
||||
}
|
||||
last_execute_address = null;
|
||||
setCurrentAddress(addr);
|
||||
}
|
||||
|
||||
private void setCurrentAddress(Address addr) {
|
||||
current_address = addr;
|
||||
memstate.setValue(pcReg, current_address.getAddressableWordOffset());
|
||||
executionState = EmulateExecutionState.STOPPED;
|
||||
faultCause = null;
|
||||
}
|
||||
|
||||
/// This routine executes an entire machine instruction at once, as a conventional debugger step
|
||||
/// function would do. If execution is at the start of an instruction, the breakpoints are checked
|
||||
/// and invoked as needed for the current address. If this routine is invoked while execution is
|
||||
/// in the middle of a machine instruction, execution is continued until the current instruction
|
||||
/// completes.
|
||||
public void executeInstruction(boolean stopAtBreakpoint, TaskMonitor monitor)
|
||||
throws CancelledException, LowlevelError, InstructionDecodeException {
|
||||
if (monitor == null) {
|
||||
monitor = TaskMonitor.DUMMY;
|
||||
}
|
||||
if (executionState == EmulateExecutionState.STOPPED) {
|
||||
if (last_execute_address == null && instructionStateModifier != null) {
|
||||
instructionStateModifier.initialExecuteCallback(this, current_address,
|
||||
nextContextRegisterValue);
|
||||
}
|
||||
if (breaktable.doAddressBreak(current_address) && stopAtBreakpoint) {
|
||||
executionState = EmulateExecutionState.BREAKPOINT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (executionState == EmulateExecutionState.FAULT) {
|
||||
// re-throw fault
|
||||
throw faultCause;
|
||||
}
|
||||
else if (executionState != EmulateExecutionState.BREAKPOINT) {
|
||||
// state is either INSTRUCTION_DECODE or EXECUTE
|
||||
throw new LowlevelError("Already executing");
|
||||
}
|
||||
try {
|
||||
executionState = EmulateExecutionState.INSTRUCTION_DECODE;
|
||||
if (language.numSections() == 0) {
|
||||
uniqueBank.clear(); // OK to clear if named sections and crossbuilds do not exist in language
|
||||
}
|
||||
pcode = emitPcode(current_address);
|
||||
last_execute_address = current_address;
|
||||
current_op = 0;
|
||||
if (pcode == null) {
|
||||
throw new InstructionDecodeException("Unexpected instruction pcode error",
|
||||
current_address);
|
||||
}
|
||||
executionState = EmulateExecutionState.EXECUTE;
|
||||
do {
|
||||
monitor.checkCanceled();
|
||||
executeCurrentOp();
|
||||
}
|
||||
while (executionState == EmulateExecutionState.EXECUTE);
|
||||
if (instructionStateModifier != null) {
|
||||
instructionStateModifier.postExecuteCallback(this, last_execute_address, pcode,
|
||||
last_op, current_address);
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
faultCause = e;
|
||||
executionState = EmulateExecutionState.FAULT;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/// \return the memory state object which this emulator uses
|
||||
public MemoryState getMemoryState() {
|
||||
return memstate;
|
||||
}
|
||||
|
||||
/// This method executes a single pcode operation, the current one (returned by getCurrentOp()).
|
||||
/// The MemoryState of the emulator is queried and changed as needed to accomplish this.
|
||||
private void executeCurrentOp() throws LowlevelError {
|
||||
|
||||
if (current_op >= pcode.length) {
|
||||
fallthruOp();
|
||||
return;
|
||||
}
|
||||
|
||||
last_op = current_op;
|
||||
|
||||
PcodeOp op = pcode[current_op];
|
||||
if (op.getOpcode() == PcodeOp.UNIMPLEMENTED) {
|
||||
throw new UnimplementedInstructionException(current_address);
|
||||
}
|
||||
|
||||
PcodeOpRaw raw = new PcodeOpRaw(op);
|
||||
|
||||
OpBehavior behave = raw.getBehavior();
|
||||
if (behave == null) {
|
||||
// unsupported opcode
|
||||
throw new LowlevelError(
|
||||
"Unsupported pcode op (opcode=" + op.getOpcode() + ", seq=" + op.getSeqnum() + ")");
|
||||
}
|
||||
if (behave instanceof UnaryOpBehavior) {
|
||||
UnaryOpBehavior unaryBehave = (UnaryOpBehavior) behave;
|
||||
Varnode in1var = op.getInput(0);
|
||||
Varnode outvar = op.getOutput();
|
||||
if (in1var.getSize() > 8 || outvar.getSize() > 8) {
|
||||
BigInteger in1 = memstate.getBigInteger(op.getInput(0), false);
|
||||
BigInteger out = unaryBehave.evaluateUnary(op.getOutput().getSize(),
|
||||
op.getInput(0).getSize(), in1);
|
||||
memstate.setValue(op.getOutput(), out);
|
||||
}
|
||||
else {
|
||||
long in1 = memstate.getValue(op.getInput(0));
|
||||
long out = unaryBehave.evaluateUnary(op.getOutput().getSize(),
|
||||
op.getInput(0).getSize(), in1);
|
||||
memstate.setValue(op.getOutput(), out);
|
||||
}
|
||||
fallthruOp();
|
||||
}
|
||||
else if (behave instanceof BinaryOpBehavior) {
|
||||
BinaryOpBehavior binaryBehave = (BinaryOpBehavior) behave;
|
||||
Varnode in1var = op.getInput(0);
|
||||
Varnode in2var = op.getInput(1);
|
||||
Varnode outvar = op.getOutput();
|
||||
if (in1var.getSize() > 8 || in2var.getSize() > 8 || outvar.getSize() > 8) {
|
||||
BigInteger in1 = memstate.getBigInteger(op.getInput(0), false);
|
||||
BigInteger in2 = memstate.getBigInteger(op.getInput(1), false);
|
||||
BigInteger out = binaryBehave.evaluateBinary(outvar.getSize(),
|
||||
op.getInput(0).getSize(), in1, in2);
|
||||
memstate.setValue(outvar, out);
|
||||
}
|
||||
else {
|
||||
long in1 = memstate.getValue(op.getInput(0));
|
||||
long in2 = memstate.getValue(op.getInput(1));
|
||||
long out = binaryBehave.evaluateBinary(outvar.getSize(), op.getInput(0).getSize(),
|
||||
in1, in2);
|
||||
memstate.setValue(outvar, out);
|
||||
}
|
||||
fallthruOp(); // All binary ops are fallthrus
|
||||
}
|
||||
else {
|
||||
switch (behave.getOpCode()) {
|
||||
case PcodeOp.LOAD:
|
||||
executeLoad(raw);
|
||||
fallthruOp();
|
||||
break;
|
||||
case PcodeOp.STORE:
|
||||
executeStore(raw);
|
||||
fallthruOp();
|
||||
break;
|
||||
case PcodeOp.BRANCH:
|
||||
executeBranch(raw);
|
||||
break;
|
||||
case PcodeOp.CBRANCH:
|
||||
executeConditionalBranch(raw);
|
||||
break;
|
||||
case PcodeOp.BRANCHIND:
|
||||
executeBranchind(raw);
|
||||
break;
|
||||
case PcodeOp.CALL:
|
||||
executeCall(raw);
|
||||
break;
|
||||
case PcodeOp.CALLIND:
|
||||
executeCallind(raw);
|
||||
break;
|
||||
case PcodeOp.CALLOTHER:
|
||||
executeCallother(raw);
|
||||
break;
|
||||
case PcodeOp.RETURN:
|
||||
executeBranchind(raw);
|
||||
break;
|
||||
case PcodeOp.MULTIEQUAL:
|
||||
executeMultiequal(raw);
|
||||
fallthruOp();
|
||||
break;
|
||||
case PcodeOp.INDIRECT:
|
||||
executeIndirect(raw);
|
||||
fallthruOp();
|
||||
break;
|
||||
default:
|
||||
throw new LowlevelError("Unsupported op (opcode=" + behave.getOpCode() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This routine performs a standard pcode \b load operation on the memory state
|
||||
/// \param op is the particular \e load op being executed
|
||||
public void executeLoad(PcodeOpRaw op) {
|
||||
|
||||
AddressSpace space =
|
||||
addrFactory.getAddressSpace((int) op.getInput(0).getAddress().getOffset()); // Space to read from
|
||||
|
||||
long offset = memstate.getValue(op.getInput(1)); // Offset to read from
|
||||
long byteOffset =
|
||||
space.truncateAddressableWordOffset(offset) * space.getAddressableUnitSize();
|
||||
|
||||
Varnode outvar = op.getOutput();
|
||||
if (outvar.getSize() > 8) {
|
||||
BigInteger res =
|
||||
memstate.getBigInteger(space, byteOffset, op.getOutput().getSize(), false);
|
||||
memstate.setValue(outvar, res);
|
||||
}
|
||||
else {
|
||||
long res = memstate.getValue(space, byteOffset, op.getOutput().getSize());
|
||||
memstate.setValue(op.getOutput(), res);
|
||||
}
|
||||
}
|
||||
|
||||
/// This routine performs a standard pcode \b store operation on the memory state
|
||||
/// \param op is the particular \e store op being executed
|
||||
public void executeStore(PcodeOpRaw op) {
|
||||
|
||||
AddressSpace space =
|
||||
addrFactory.getAddressSpace((int) op.getInput(0).getAddress().getOffset()); // Space to store in
|
||||
|
||||
long offset = memstate.getValue(op.getInput(1)); // Offset to store at
|
||||
long byteOffset =
|
||||
space.truncateAddressableWordOffset(offset) * space.getAddressableUnitSize();
|
||||
|
||||
Varnode storedVar = op.getInput(2); // Value being stored
|
||||
if (storedVar.getSize() > 8) {
|
||||
BigInteger val = memstate.getBigInteger(storedVar, false);
|
||||
memstate.setValue(space, byteOffset, op.getInput(2).getSize(), val);
|
||||
}
|
||||
else {
|
||||
long val = memstate.getValue(storedVar);
|
||||
memstate.setValue(space, byteOffset, op.getInput(2).getSize(), val);
|
||||
}
|
||||
}
|
||||
|
||||
/// This routine performs a standard pcode \b branch \b indirect operation on the memory state
|
||||
/// \param op is the particular \e branchind op being executed
|
||||
public void executeBranchind(PcodeOpRaw op) {
|
||||
long offset = memstate.getValue(op.getInput(0));
|
||||
AddressSpace space = op.getAddress().getAddressSpace();
|
||||
setCurrentAddress(space.getTruncatedAddress(offset, true));
|
||||
}
|
||||
|
||||
/// This routine performs a standard pcode \b call operation on the memory state
|
||||
/// \param op is the particular \e call op being executed
|
||||
public void executeCall(PcodeOpRaw op) {
|
||||
setCurrentAddress(op.getInput(0).getAddress());
|
||||
}
|
||||
|
||||
/// This routine performs a standard pcode \b call \b indirect operation on the memory state
|
||||
/// \param op is the particular \e callind op being executed
|
||||
public void executeCallind(PcodeOpRaw op) {
|
||||
executeBranchind(op); // same behavior as branch indirect
|
||||
}
|
||||
|
||||
/// This kind of pcode op should not come up in ordinary emulation, so this routine
|
||||
/// throws an exception.
|
||||
/// \param op is the particular \e multiequal op being executed
|
||||
public void executeMultiequal(PcodeOpRaw op) {
|
||||
throw new LowlevelError("MULTIEQUAL appearing in unheritaged code?");
|
||||
}
|
||||
|
||||
/// This kind of pcode op should not come up in ordinary emulation, so this routine
|
||||
/// throws an exception.
|
||||
/// \param op is the particular \e indirect op being executed
|
||||
public void executeIndirect(PcodeOpRaw op) {
|
||||
throw new LowlevelError("INDIRECT appearing in unheritaged code?");
|
||||
}
|
||||
|
||||
}
|
||||
/** \page sleighAPIemulate The SLEIGH Emulator
|
||||
|
||||
\section emu_overview Overview
|
||||
|
||||
\b SLEIGH provides a framework for emulating the processors which have a specification written
|
||||
for them. The key classes in this framework are:
|
||||
|
||||
\b Key \b Classes
|
||||
- \ref MemoryState
|
||||
- \ref MemoryBank
|
||||
- \ref BreakTable
|
||||
- \ref BreakCallBack
|
||||
- \ref Emulate
|
||||
- \ref EmulatePcodeCache
|
||||
|
||||
The MemoryState object holds the representation of registers and memory during emulation. It
|
||||
understands the address spaces defined in the \b SLEIGH specification and how data is encoded
|
||||
in these spaces. It also knows any register names defined by the specification, so these
|
||||
can be used to set or query the state of these registers naturally.
|
||||
|
||||
The emulation framework can be tailored to a particular environment by creating \b breakpoint
|
||||
objects, which derive off the BreakCallBack interface. These can be used to create callbacks
|
||||
during emulation that have full access to the memory state and the emulator, so any action
|
||||
can be accomplished. The breakpoint callbacks can be designed to either augment or replace
|
||||
the instruction at a particular address, or the callback can be used to implement the action
|
||||
of a user-defined pcode op. The BreakCallBack objects are managed by the BreakTable object,
|
||||
which takes care of invoking the callback at the appropriate time.
|
||||
|
||||
The Emulate object serves as a basic execution engine. Its main method is
|
||||
Emulate::executeCurrentOp() which executes a single pcode operation on the memory state.
|
||||
Methods exist for querying and setting the current execution address and examining the pcode
|
||||
op being executed.
|
||||
|
||||
The main implementation of the Emulate interface is the EmulatePcodeCache object. It uses
|
||||
SLEIGH to translate machine instructions as they are executed. The currently executing instruction
|
||||
is translated into a cached sequence of pcode operations. Additional methods allow this entire
|
||||
sequence to be inspected, and there is another stepping function which allows the emulator
|
||||
to be stepped through an entire machine instruction at a time. The single pcode stepping methods
|
||||
are of course still available and the two methods can be used together without conflict.
|
||||
|
||||
\section emu_membuild Building a Memory State
|
||||
|
||||
Assuming the SLEIGH Translate object and the LoadImage object have already been built
|
||||
(see \ref sleighAPIbasic), the only required step left before instantiating an emulator
|
||||
is to create a MemoryState object. The MemoryState object can be instantiated simply by
|
||||
passing the constructor the Translate object, but before it will work properly, you need
|
||||
to register individual MemoryBank objects with it, for each address space that might
|
||||
get used by the emulator.
|
||||
|
||||
A MemoryBank is a representation of data stored in a single address space
|
||||
There are some choices for the type of MemoryBank associated with an address space.
|
||||
A MemoryImage is a read-only memory bank that gets its data from a LoadImage. In order
|
||||
to make this writeable, or to create a writeable memory bank which starts with its bytes
|
||||
initialized to zero, you can use a MemoryPageOverlay.
|
||||
|
||||
A MemoryPageOverlay overlays another memory bank as well. But it implements writes to the bank
|
||||
by caching memory \e pages. Any write creates an aligned page to hold the new data. The class
|
||||
takes care of loading and filling in pages as needed.
|
||||
|
||||
The Emulate constructor always adds a unique space memory bank using the UniqueMemoryBank,
|
||||
the user needs not add this space.
|
||||
|
||||
All the memory bank constructors need a page size, which is most relevant to the page implementation. The
|
||||
null pointers passed in, in place of a real memory bank, indicate that the memory bank has no initial
|
||||
memory image. Once the memory banks are instantiated, they are registered with the memory state
|
||||
via the MemoryState::setMemoryBank() method.
|
||||
|
||||
\section emu_breakpoints Breakpoints
|
||||
|
||||
In order to provide behavior within the emulator beyond just what the core instruction emulation
|
||||
provides, the framework supports \b breakpoint classes. A breakpoint is created by deriving a
|
||||
class from the BreakCallBack class and overriding either BreakCallBack::addressCallback() or
|
||||
BreakCallBack::pcodeCallback(). Here is an example of a breakpoint that implements a
|
||||
standard C library \e puts call an the x86 architecture. When the breakpoint is invoked,
|
||||
a call to \e puts has just been made, so the stack pointer is pointing to the return address
|
||||
and the next 4 bytes on the stack are a pointer to the string being passed in.
|
||||
|
||||
\code
|
||||
class PutsCallBack : public BreakCallBack {
|
||||
public:
|
||||
virtual bool addressCallback(const Address &addr);
|
||||
};
|
||||
|
||||
bool PutsCallBack::addressCallback(const Address &addr)
|
||||
|
||||
{
|
||||
MemoryState *mem = emulate->getMemoryState();
|
||||
uint1 buffer[256];
|
||||
uint4 esp = mem->getValue("ESP");
|
||||
AddrSpace *ram = mem->getTranslate()->getSpaceByName("ram");
|
||||
|
||||
uint4 param1 = mem->getValue(ram,esp+4,4);
|
||||
mem->getChunk(buffer,ram,param1,255);
|
||||
|
||||
cout << (char *)&buffer << endl;
|
||||
|
||||
uint4 returnaddr = mem->getValue(ram,esp,4);
|
||||
mem->setValue("ESP",esp+8);
|
||||
emulate->setExecuteAddress(Address(ram,returnaddr));
|
||||
|
||||
return true; // This replaces the indicated instruction
|
||||
}
|
||||
|
||||
\endcode
|
||||
|
||||
Notice that the callback retrieves the value of the stack pointer by name. Using this
|
||||
value, the string pointer is retrieved, then the data for the actual string is retrieved.
|
||||
After dumping the string to standard out, the return address is recovered and the \e return
|
||||
instruction is emulated by explicitly setting the next execution address to be the return value.
|
||||
|
||||
\section emu_finalsetup Running the Emulator
|
||||
Here is an example of instantiating an EmulatePcodeCache object. A breakpoint is also instantiated
|
||||
and registered with the BreakTable.
|
||||
|
||||
\code
|
||||
...
|
||||
Sleigh trans(&loader,&context); // Instantiate the translator
|
||||
...
|
||||
MemoryState memstate(&trans); // Instantiate the memory state
|
||||
...
|
||||
BreakTableCallBack breaktable(&trans); // Instantiate a breakpoint table
|
||||
EmulatePcodeCache emulator(&trans,&memstate,&breaktable); // Instantiate the emulator
|
||||
|
||||
// Set up the initial stack pointer
|
||||
memstate.setValue("ESP",0xbffffffc);
|
||||
emulator.setExecuteAddress(Address(trans.getDefaultSpace(),0x1D00114)); // Initial execution address
|
||||
|
||||
PutsCallBack putscallback;
|
||||
breaktable.registerAddressCallback(Address(trans.getDefaultSpace(),0x1D00130),&putscallback);
|
||||
|
||||
AssemblyRaw assememit;
|
||||
for(;;) {
|
||||
Address addr = emulator.getExecuteAddress();
|
||||
trans.printAssembly(assememit,addr);
|
||||
emulator.executeInstruction();
|
||||
}
|
||||
|
||||
\endcode
|
||||
|
||||
Notice how the initial stack pointer and initial execute address is set up. The breakpoint
|
||||
is registered with the BreakTable, giving it a specific address. The executeInstruction method
|
||||
is called inside the loop, to actually run the emulator. Notice that a disassembly of each
|
||||
instruction is printed after each step of the emulator.
|
||||
|
||||
Other information can be examined from within this execution loop or in other tailored breakpoints.
|
||||
In particular, the Emulate::getCurrentOp() method can be used to retrieve the an instance
|
||||
of the currently executing pcode operation. From this starting point, you can examine the
|
||||
low-level objects:
|
||||
- PcodeOpRaw and
|
||||
- VarnodeData
|
||||
*/
|
|
@ -1,209 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.util.ProgramContextImpl;
|
||||
|
||||
public class EmulateDisassemblerContext implements DisassemblerContext {
|
||||
|
||||
private final Language language;
|
||||
private final Map<Address, RegisterValue> futureContextMap;
|
||||
private final Register contextReg;
|
||||
|
||||
private RegisterValue contextRegValue;
|
||||
private byte[] flowingContextRegisterMask;
|
||||
private boolean hasNonFlowingContext;
|
||||
|
||||
EmulateDisassemblerContext(Language language) {
|
||||
this.language = language;
|
||||
this.contextReg = language.getContextBaseRegister();
|
||||
this.futureContextMap = new HashMap<Address, RegisterValue>();
|
||||
initContext();
|
||||
}
|
||||
|
||||
public EmulateDisassemblerContext(Language language, RegisterValue initialContextValue) {
|
||||
this(language);
|
||||
this.contextRegValue = initialContextValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Register getBaseContextRegister() {
|
||||
return contextReg;
|
||||
}
|
||||
|
||||
public RegisterValue getCurrentContextRegisterValue() {
|
||||
if (contextRegValue == null) {
|
||||
return null;
|
||||
}
|
||||
return new RegisterValue(contextRegValue.getRegister(), contextRegValue.toBytes());
|
||||
}
|
||||
|
||||
public void setCurrentAddress(Address addr) {
|
||||
|
||||
if (contextReg == Register.NO_CONTEXT) {
|
||||
return;
|
||||
}
|
||||
RegisterValue partialValue = null;
|
||||
if (contextRegValue != null && contextRegValue.getRegister() != contextReg) {
|
||||
if (contextRegValue.getRegister().getBaseRegister() == contextReg) {
|
||||
partialValue = contextRegValue;
|
||||
}
|
||||
contextRegValue = null;
|
||||
}
|
||||
if (contextRegValue == null) {
|
||||
ProgramContextImpl defaultContext = new ProgramContextImpl(language);
|
||||
language.applyContextSettings(defaultContext);
|
||||
contextRegValue = defaultContext.getDefaultValue(contextReg, addr);
|
||||
if (contextRegValue == null) {
|
||||
contextRegValue = new RegisterValue(contextReg);
|
||||
}
|
||||
if (partialValue != null) {
|
||||
contextRegValue = contextRegValue.combineValues(partialValue);
|
||||
}
|
||||
}
|
||||
if (hasNonFlowingContext) {
|
||||
byte[] contextBytes = contextRegValue.toBytes();
|
||||
int valMaskLen = contextBytes.length >> 1;
|
||||
|
||||
for (int i = 0; i < valMaskLen; i++) {
|
||||
contextBytes[i] &= flowingContextRegisterMask[i]; // clear non-flowing mask bits
|
||||
contextBytes[valMaskLen + i] &= flowingContextRegisterMask[i]; // clear non-flowing value bits
|
||||
}
|
||||
contextRegValue = new RegisterValue(contextReg, contextBytes);
|
||||
}
|
||||
|
||||
// WARNING: futureContextMap could accumulate a significant amount of context if it never gets purged
|
||||
// although we may need it later (e.g., end-of-loop)
|
||||
RegisterValue newContext = futureContextMap.get(addr);
|
||||
if (newContext != null) {
|
||||
contextRegValue = contextRegValue.combineValues(newContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void initContext() {
|
||||
if (contextReg == Register.NO_CONTEXT) {
|
||||
return;
|
||||
}
|
||||
flowingContextRegisterMask = contextReg.getBaseMask().clone();
|
||||
Arrays.fill(flowingContextRegisterMask, (byte) 0);
|
||||
initContextBitMasks(contextReg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set those bits in the nonFlowingContextRegisterMask which should not
|
||||
* flow with context.
|
||||
* @param reg context register piece
|
||||
*/
|
||||
private void initContextBitMasks(Register reg) {
|
||||
byte[] subMask = reg.getBaseMask();
|
||||
if (!reg.followsFlow()) {
|
||||
hasNonFlowingContext = true;
|
||||
for (int i = 0; i < flowingContextRegisterMask.length; i++) {
|
||||
flowingContextRegisterMask[i] &= ~subMask[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < flowingContextRegisterMask.length; i++) {
|
||||
flowingContextRegisterMask[i] |= subMask[i];
|
||||
}
|
||||
if (reg.hasChildren()) {
|
||||
for (Register childReg : reg.getChildRegisters()) {
|
||||
initContextBitMasks(childReg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRegister(Register register) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Register getRegister(String name) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterValue getRegisterValue(Register register) {
|
||||
if (!register.isProcessorContext()) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if (register.equals(contextReg)) {
|
||||
return contextRegValue;
|
||||
}
|
||||
return new RegisterValue(register, contextRegValue.toBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Register> getRegisters() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getValue(Register register, boolean signed) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasValue(Register register) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegisterValue(RegisterValue value) {
|
||||
Register reg = value.getRegister();
|
||||
if (!reg.isProcessorContext()) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if (contextRegValue == null) {
|
||||
contextRegValue = value.getBaseRegisterValue();
|
||||
}
|
||||
else {
|
||||
contextRegValue = contextRegValue.combineValues(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Register register, BigInteger value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFutureRegisterValue(Address address, RegisterValue value) {
|
||||
Register reg = value.getRegister();
|
||||
if (!reg.isProcessorContext()) {
|
||||
throw new UnsupportedOperationException();
|
||||
// Msg.warn(this, "Setting register " + reg.getName() + " during emulator disassembly ignored!");
|
||||
// return;
|
||||
}
|
||||
RegisterValue registerValue = futureContextMap.get(address);
|
||||
if (registerValue != null) {
|
||||
value = registerValue.combineValues(value);
|
||||
}
|
||||
futureContextMap.put(address, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFutureRegisterValue(Address fromAddr, Address toAddr, RegisterValue value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
public enum EmulateExecutionState {
|
||||
|
||||
/**
|
||||
* Currently stopped
|
||||
*/
|
||||
STOPPED,
|
||||
|
||||
/**
|
||||
* Currently stopped at a breakpoint
|
||||
*/
|
||||
BREAKPOINT,
|
||||
|
||||
/**
|
||||
* Currently decoding instruction (i.e., generating pcode ops)
|
||||
*/
|
||||
INSTRUCTION_DECODE,
|
||||
|
||||
/**
|
||||
* Currently executing instruction pcode
|
||||
*/
|
||||
EXECUTE,
|
||||
|
||||
/**
|
||||
* Execution stopped due to a fault/error
|
||||
*/
|
||||
FAULT
|
||||
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import ghidra.pcode.emulate.callother.OpBehaviorOther;
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <code>EmulateInstructionStateModifier</code> defines a language specific
|
||||
* handler to assist emulation with adjusting the current execution state,
|
||||
* providing support for custom pcodeop's (i.e., CALLOTHER).
|
||||
* The implementation of this interface must provide a public constructor which
|
||||
* takes a single Emulate argument.
|
||||
*/
|
||||
public abstract class EmulateInstructionStateModifier {
|
||||
|
||||
protected final Emulate emu;
|
||||
protected final Language language;
|
||||
|
||||
private Map<Integer, OpBehaviorOther> pcodeOpMap;
|
||||
|
||||
protected EmulateInstructionStateModifier(Emulate emu) {
|
||||
this.emu = emu;
|
||||
this.language = emu.getLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a pcodeop behavior corresponding to a CALLOTHER opcode.
|
||||
* @param opName name as defined within language via "define pcodeop"
|
||||
* @param pcodeOpBehavior
|
||||
*/
|
||||
protected final void registerPcodeOpBehavior(String opName, OpBehaviorOther pcodeOpBehavior) {
|
||||
if (pcodeOpMap == null) {
|
||||
pcodeOpMap = new HashMap<Integer, OpBehaviorOther>();
|
||||
}
|
||||
int numUserOps = language.getNumberOfUserDefinedOpNames();
|
||||
for (int i = 0; i < numUserOps; i++) {
|
||||
if (opName.equals(language.getUserDefinedOpName(i))) {
|
||||
pcodeOpMap.put(i, pcodeOpBehavior);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new LowlevelError("Undefined pcodeop name: " + opName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a CALLOTHER op
|
||||
* @param op
|
||||
* @return true if corresponding pcodeop was registered and emulation support is
|
||||
* performed, or false if corresponding pcodeop is not supported by this class.
|
||||
* @throws LowlevelError
|
||||
*/
|
||||
public final boolean executeCallOther(PcodeOp op) throws LowlevelError {
|
||||
if (pcodeOpMap == null) {
|
||||
return false;
|
||||
}
|
||||
Varnode[] inputs = op.getInputs();
|
||||
OpBehaviorOther opBehaviorOther = pcodeOpMap.get((int) inputs[0].getOffset());
|
||||
if (opBehaviorOther == null) {
|
||||
return false;
|
||||
}
|
||||
opBehaviorOther.evaluate(emu, op.getOutput(), inputs);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emulation callback immediately before the first instruction is executed.
|
||||
* This callback permits any language specific initializations to be performed.
|
||||
* @param emulate
|
||||
* @param current_address intial execute address
|
||||
* @param contextRegisterValue initial context value or null if not applicable or unknown
|
||||
* @throws LowlevelError
|
||||
*/
|
||||
public void initialExecuteCallback(Emulate emulate, Address current_address, RegisterValue contextRegisterValue) throws LowlevelError {
|
||||
// no default implementation
|
||||
}
|
||||
|
||||
/**
|
||||
* Emulation callback immediately following execution of the lastExecuteAddress.
|
||||
* One use of this callback is to modify the flowing/future context state.
|
||||
* @param emulate
|
||||
* @param lastExecuteAddress
|
||||
* @param lastExecutePcode
|
||||
* @param lastPcodeIndex pcode index of last op or -1 if no pcode or fall-through occurred.
|
||||
* @param currentAddress
|
||||
* @throws LowlevelError
|
||||
*/
|
||||
public void postExecuteCallback(Emulate emulate, Address lastExecuteAddress,
|
||||
PcodeOp[] lastExecutePcode, int lastPcodeIndex, Address currentAddress)
|
||||
throws LowlevelError {
|
||||
// no default implementation
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.pcode.memstate.MemoryState;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.*;
|
||||
|
||||
/**
|
||||
* <code>MemoryStateBuffer</code> provides a MemBuffer for instruction parsing use
|
||||
* which wraps an emulator MemoryState. This implementation wraps all specified
|
||||
* memory offsets within the associated address space.
|
||||
*/
|
||||
public class EmulateMemoryStateBuffer implements MemBuffer {
|
||||
|
||||
private final MemoryState memState;
|
||||
private Address address;
|
||||
|
||||
public EmulateMemoryStateBuffer(MemoryState memState, Address addr) {
|
||||
this.memState = memState;
|
||||
setAddress(addr);
|
||||
}
|
||||
|
||||
public void setAddress(Address addr) {
|
||||
address = addr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
private long availableInSpace(Address startAddr) {
|
||||
return address.getAddressSpace().getMaxAddress().subtract(startAddr) + 1;
|
||||
}
|
||||
|
||||
private Address getWrappedAddress(int offset) {
|
||||
return address.addWrap(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if request is valid and compute wrapped memory offset relative to
|
||||
* current buffer address. A request is invalid if too close to the end of the
|
||||
* memory space to read the requested number of bytes.
|
||||
* @param offset relative offset
|
||||
* @param size read request size
|
||||
* @return absolute memory offset (wrapped)
|
||||
* @throws MemoryAccessException
|
||||
*/
|
||||
private long checkGetRequest(int offset, int size) throws MemoryAccessException {
|
||||
Address offsetAddr = getWrappedAddress(offset);
|
||||
long available = availableInSpace(offsetAddr);
|
||||
if (available > 0 && available < size) {
|
||||
throw new MemoryAccessException();
|
||||
}
|
||||
return offsetAddr.getOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getBigInteger(int offset, int size, boolean signed)
|
||||
throws MemoryAccessException {
|
||||
long memOffset = checkGetRequest(offset, size);
|
||||
return memState.getBigInteger(address.getAddressSpace(), memOffset, size, signed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytes(byte[] b, int offset) {
|
||||
Address offsetAddr = getWrappedAddress(offset);
|
||||
return memState.getChunk(b, address.getAddressSpace(), offsetAddr.getOffset(), b.length,
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte(int offset) throws MemoryAccessException {
|
||||
long memOffset = checkGetRequest(offset, 1);
|
||||
return (byte) memState.getValue(address.getAddressSpace(), memOffset, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort(int offset) throws MemoryAccessException {
|
||||
long memOffset = checkGetRequest(offset, 2);
|
||||
return (short) memState.getValue(address.getAddressSpace(), memOffset, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int offset) throws MemoryAccessException {
|
||||
long memOffset = checkGetRequest(offset, 4);
|
||||
return (int) memState.getValue(address.getAddressSpace(), memOffset, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int offset) throws MemoryAccessException {
|
||||
long memOffset = checkGetRequest(offset, 8);
|
||||
return memState.getValue(address.getAddressSpace(), memOffset, 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Memory getMemory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBigEndian() {
|
||||
return memState.getMemoryBank(address.getAddressSpace()).isBigEndian();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
public class InstructionDecodeException extends LowlevelError {
|
||||
|
||||
private Address pc;
|
||||
|
||||
public InstructionDecodeException(String reason, Address pc) {
|
||||
super("Instruction decode failed (" + reason + "), PC=" + pc);
|
||||
this.pc = pc;
|
||||
}
|
||||
|
||||
public Address getProgramCounter() {
|
||||
return pc;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.pcode.pcoderaw.PcodeOpRaw;
|
||||
|
||||
public class UnimplementedCallOtherException extends LowlevelError {
|
||||
|
||||
private String opName;
|
||||
private PcodeOpRaw op;
|
||||
|
||||
public UnimplementedCallOtherException(PcodeOpRaw op, String opName) {
|
||||
super("Unimplemented CALLOTHER pcodeop (" + opName + "), PC=" + op.getAddress());
|
||||
this.op = op;
|
||||
this.opName = opName;
|
||||
}
|
||||
|
||||
public PcodeOpRaw getCallOtherOp() {
|
||||
return op;
|
||||
}
|
||||
|
||||
public String getCallOtherOpName() {
|
||||
return opName;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
public class UnimplementedInstructionException extends LowlevelError {
|
||||
|
||||
private Address addr;
|
||||
|
||||
public UnimplementedInstructionException(Address addr) {
|
||||
super("Unimplemented instruction, PC=" + addr);
|
||||
this.addr = addr;
|
||||
}
|
||||
|
||||
public Address getInstructionAddress() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate.callother;
|
||||
|
||||
import ghidra.pcode.emulate.Emulate;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
|
||||
public interface OpBehaviorOther {
|
||||
|
||||
/**
|
||||
* Evaluate the CALLOTHER op which corresponds to this behavior.
|
||||
* @param emu emulator which contains associated memory state
|
||||
* @param out output varnode or null if no assignment has been
|
||||
* made. Implementation is responsible for updating memory
|
||||
* state appropriately.
|
||||
* @param inputs input varnodes passed as parameters to this
|
||||
* pcodeop. The inputs[0] value corresponds to the index value of this
|
||||
* pcodeop and can generally be ignored. The inputs[1] value
|
||||
* corresponds to the first (leftmost) parameter passed to
|
||||
* this pcodeop within the language implementation.
|
||||
*/
|
||||
public void evaluate(Emulate emu, Varnode out, Varnode[] inputs);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.emulate.callother;
|
||||
|
||||
import ghidra.pcode.emulate.Emulate;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
|
||||
public class OpBehaviorOtherNOP implements OpBehaviorOther {
|
||||
|
||||
@Override
|
||||
public void evaluate(Emulate emu, Varnode out, Varnode[] inputs) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,11 +17,11 @@ package ghidra.pcode.error;
|
|||
|
||||
public class LowlevelError extends RuntimeException {
|
||||
|
||||
public LowlevelError( String message ) {
|
||||
super( message );
|
||||
public LowlevelError(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LowlevelError( String message, Throwable throwable ) {
|
||||
super( message, throwable );
|
||||
|
||||
public LowlevelError(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.loadimage;
|
||||
|
||||
import ghidra.pcode.memstate.MemoryPage;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
// API for accessing a binary load image
|
||||
// using 1 of possibly many different methods behind the scenes
|
||||
public interface LoadImage {
|
||||
|
||||
// TODO this doesn't appear to be used.
|
||||
// /**
|
||||
// *
|
||||
// * @param ptr
|
||||
// * @param size
|
||||
// * @param addr
|
||||
// * @param bufOffset
|
||||
// * @param generateInitializedMask if true the function should return an initialized bit mask
|
||||
// * or null if all loaded bytes were known. If true, uninitialized memory reads should only be
|
||||
// * reflected in the mask and should not be reported via the memory fault handler.
|
||||
// * @return initialized bit mask or null (see generateInitializedMask parameter)
|
||||
// * @see MemoryPage
|
||||
// */
|
||||
public byte[] loadFill( byte[] buf, int size, Address addr, int bufOffset, boolean generateInitializedMask );
|
||||
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.loadimage;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
public class LoadImageFunc {
|
||||
public Address address; // Start of function
|
||||
public String name; // Name of function
|
||||
|
||||
}
|
|
@ -1,269 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
|
||||
public abstract class AbstractMemoryState implements MemoryState {
|
||||
final Language language;
|
||||
|
||||
public AbstractMemoryState(Language language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for setting a value directly on a varnode rather than breaking out the
|
||||
* components
|
||||
*
|
||||
* @param vn the varnode location to be written
|
||||
* @param cval the value to write into the varnode location
|
||||
*/
|
||||
@Override
|
||||
public final void setValue(Varnode vn, long cval) {
|
||||
Address addr = vn.getAddress();
|
||||
setValue(addr.getAddressSpace(), addr.getOffset(), vn.getSize(), cval);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for setting a value directly on a register rather than breaking out the
|
||||
* components
|
||||
*
|
||||
* @param reg the register location to be written
|
||||
* @param cval the value to write into the register location
|
||||
*/
|
||||
@Override
|
||||
public final void setValue(Register reg, long cval) {
|
||||
Address addr = reg.getAddress();
|
||||
setValue(addr.getAddressSpace(), addr.getOffset(), reg.getMinimumByteSize(), cval);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a convenience method for setting registers by name. Any register name known to the
|
||||
* language can be used as a write location. The associated address space, offset, and size is
|
||||
* looked up and automatically passed to the main setValue routine.
|
||||
*
|
||||
* @param nm is the name of the register
|
||||
* @param cval is the value to write to the register
|
||||
*/
|
||||
@Override
|
||||
public final void setValue(String nm, long cval) {
|
||||
// Set a "register" value
|
||||
setValue(language.getRegister(nm), cval);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main interface for writing values to the MemoryState. If there is no registered
|
||||
* MemoryBank for the desired address space, or if there is some other error, an exception is
|
||||
* thrown.
|
||||
*
|
||||
* @param spc is the address space to write to
|
||||
* @param off is the offset where the value should be written
|
||||
* @param size is the number of bytes to be written
|
||||
* @param cval is the value to be written
|
||||
*/
|
||||
@Override
|
||||
public final void setValue(AddressSpace spc, long off, int size, long cval) {
|
||||
setChunk(Utils.longToBytes(cval, size, language.isBigEndian()), spc, off, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for reading a value directly from a varnode rather than querying for the
|
||||
* offset and space
|
||||
*
|
||||
* @param vn the varnode location to be read
|
||||
* @return the value read from the varnode location
|
||||
*/
|
||||
@Override
|
||||
public final long getValue(Varnode vn) {
|
||||
Address addr = vn.getAddress();
|
||||
return getValue(addr.getAddressSpace(), addr.getOffset(), vn.getSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for reading a value directly from a register rather than querying for
|
||||
* the offset and space
|
||||
*
|
||||
* @param reg the register location to be read
|
||||
* @return the value read from the register location
|
||||
*/
|
||||
@Override
|
||||
public final long getValue(Register reg) {
|
||||
Address addr = reg.getAddress();
|
||||
return getValue(addr.getAddressSpace(), addr.getOffset(), reg.getMinimumByteSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a convenience method for reading registers by name. any register name known to the
|
||||
* language can be used as a read location. The associated address space, offset, and size is
|
||||
* looked up and automatically passed to the main getValue routine.
|
||||
*
|
||||
* @param nm is the name of the register
|
||||
* @return the value associated with that register
|
||||
*/
|
||||
@Override
|
||||
public final long getValue(String nm) {
|
||||
// Get a "register" value
|
||||
return getValue(language.getRegister(nm));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main interface for reading values from the MemoryState. If there is no registered
|
||||
* MemoryBank for the desired address space, or if there is some other error, an exception is
|
||||
* thrown.
|
||||
*
|
||||
* @param spc is the address space being queried
|
||||
* @param off is the offset of the value being queried
|
||||
* @param size is the number of bytes to query
|
||||
* @return the queried value
|
||||
*/
|
||||
@Override
|
||||
public final long getValue(AddressSpace spc, long off, int size) {
|
||||
if (spc.isConstantSpace()) {
|
||||
return off;
|
||||
}
|
||||
byte[] bytes = new byte[size];
|
||||
getChunk(bytes, spc, off, size, false);
|
||||
return Utils.bytesToLong(bytes, size, language.isBigEndian());
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for setting a value directly on a varnode rather than breaking out the
|
||||
* components
|
||||
*
|
||||
* @param vn the varnode location to be written
|
||||
* @param cval the value to write into the varnode location
|
||||
*/
|
||||
@Override
|
||||
public final void setValue(Varnode vn, BigInteger cval) {
|
||||
Address addr = vn.getAddress();
|
||||
setValue(addr.getAddressSpace(), addr.getOffset(), vn.getSize(), cval);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for setting a value directly on a register rather than breaking out the
|
||||
* components
|
||||
*
|
||||
* @param reg the register location to be written
|
||||
* @param cval the value to write into the register location
|
||||
*/
|
||||
@Override
|
||||
public final void setValue(Register reg, BigInteger cval) {
|
||||
Address addr = reg.getAddress();
|
||||
setValue(addr.getAddressSpace(), addr.getOffset(), reg.getMinimumByteSize(), cval);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a convenience method for setting registers by name. Any register name known to the
|
||||
* language can be used as a write location. The associated address space, offset, and size is
|
||||
* looked up and automatically passed to the main setValue routine.
|
||||
*
|
||||
* @param nm is the name of the register
|
||||
* @param cval is the value to write to the register
|
||||
*/
|
||||
@Override
|
||||
public final void setValue(String nm, BigInteger cval) {
|
||||
// Set a "register" value
|
||||
setValue(language.getRegister(nm), cval);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main interface for writing values to the MemoryState. If there is no registered
|
||||
* MemoryBank for the desired address space, or if there is some other error, an exception is
|
||||
* thrown.
|
||||
*
|
||||
* @param spc is the address space to write to
|
||||
* @param off is the offset where the value should be written
|
||||
* @param size is the number of bytes to be written
|
||||
* @param cval is the value to be written
|
||||
*/
|
||||
@Override
|
||||
public final void setValue(AddressSpace spc, long off, int size, BigInteger cval) {
|
||||
setChunk(Utils.bigIntegerToBytes(cval, size, language.isBigEndian()), spc, off, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for reading a value directly from a varnode rather than querying for the
|
||||
* offset and space
|
||||
*
|
||||
* @param vn the varnode location to be read
|
||||
* @param signed true if signed value should be returned, false for unsigned value
|
||||
* @return the unsigned value read from the varnode location
|
||||
*/
|
||||
@Override
|
||||
public final BigInteger getBigInteger(Varnode vn, boolean signed) {
|
||||
Address addr = vn.getAddress();
|
||||
return getBigInteger(addr.getAddressSpace(), addr.getOffset(), vn.getSize(), signed);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for reading a value directly from a register rather than querying for
|
||||
* the offset and space
|
||||
*
|
||||
* @param reg the register location to be read
|
||||
* @return the unsigned value read from the register location
|
||||
*/
|
||||
@Override
|
||||
public final BigInteger getBigInteger(Register reg) {
|
||||
Address addr = reg.getAddress();
|
||||
return getBigInteger(addr.getAddressSpace(), addr.getOffset(), reg.getMinimumByteSize(),
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a convenience method for reading registers by name. any register name known to the
|
||||
* language can be used as a read location. The associated address space, offset, and size is
|
||||
* looked up and automatically passed to the main getValue routine.
|
||||
*
|
||||
* @param nm is the name of the register
|
||||
* @return the unsigned value associated with that register
|
||||
*/
|
||||
@Override
|
||||
public final BigInteger getBigInteger(String nm) {
|
||||
// Get a "register" value
|
||||
return getBigInteger(language.getRegister(nm));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main interface for reading values from the MemoryState. If there is no registered
|
||||
* MemoryBank for the desired address space, or if there is some other error, an exception is
|
||||
* thrown.
|
||||
*
|
||||
* @param spc is the address space being queried
|
||||
* @param off is the offset of the value being queried
|
||||
* @param size is the number of bytes to query
|
||||
* @param signed true if signed value should be returned, false for unsigned value
|
||||
* @return the queried unsigned value
|
||||
*/
|
||||
@Override
|
||||
public final BigInteger getBigInteger(AddressSpace spc, long off, int size, boolean signed) {
|
||||
if (spc.isConstantSpace()) {
|
||||
if (!signed && off < 0) {
|
||||
return new BigInteger(1, Utils.longToBytes(off, 8, true));
|
||||
}
|
||||
return BigInteger.valueOf(off);
|
||||
}
|
||||
byte[] bytes = new byte[size];
|
||||
getChunk(bytes, spc, off, size, false);
|
||||
return Utils.bytesToBigInteger(bytes, size, language.isBigEndian(), signed);
|
||||
}
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import generic.stl.VectorSTL;
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Language;
|
||||
|
||||
/**
|
||||
* All storage/state for a pcode emulator machine
|
||||
*
|
||||
* Every piece of information in a pcode emulator machine is representable as a triple
|
||||
* (AddressSpace,offset,size). This class allows getting and setting of all state information of
|
||||
* this form.
|
||||
*/
|
||||
public class DefaultMemoryState extends AbstractMemoryState {
|
||||
|
||||
VectorSTL<MemoryBank> memspace = new VectorSTL<MemoryBank>();
|
||||
|
||||
/**
|
||||
* MemoryState constructor for a specified processor language
|
||||
*
|
||||
* @param language
|
||||
*/
|
||||
public DefaultMemoryState(Language language) {
|
||||
super(language);
|
||||
}
|
||||
|
||||
/**
|
||||
* MemoryBanks associated with specific address spaces must be registers with this MemoryState
|
||||
* via this method. Each address space that will be used during emulation must be registered
|
||||
* separately. The MemoryState object does not assume responsibility for freeing the MemoryBank.
|
||||
*
|
||||
* @param bank is a pointer to the MemoryBank to be registered
|
||||
*/
|
||||
@Override
|
||||
public final void setMemoryBank(MemoryBank bank) {
|
||||
AddressSpace spc = bank.getSpace();
|
||||
int index = spc.getUnique();
|
||||
|
||||
while (index >= memspace.size())
|
||||
memspace.push_back(null);
|
||||
|
||||
memspace.set(index, bank);
|
||||
}
|
||||
|
||||
/**
|
||||
* Any MemoryBank that has been registered with this MemoryState can be retrieved via this
|
||||
* method if the MemoryBank's associated address space is known.
|
||||
*
|
||||
* @param spc is the address space of the desired MemoryBank
|
||||
* @return the MemoryBank or null if no bank is associated with spc.
|
||||
*/
|
||||
@Override
|
||||
public final MemoryBank getMemoryBank(AddressSpace spc) {
|
||||
int index = spc.getUnique();
|
||||
if (index >= memspace.size())
|
||||
return null;
|
||||
return memspace.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main interface for reading a range of bytes from the MemorySate. The MemoryBank
|
||||
* associated with the address space of the query is looked up and the request is forwarded to
|
||||
* the getChunk method on the MemoryBank. If there is no registered MemoryBank or some other
|
||||
* error, an exception is thrown. All getLongValue methods utilize this method to read the bytes
|
||||
* from the appropriate memory bank.
|
||||
*
|
||||
* @param res the result buffer for storing retrieved bytes
|
||||
* @param spc the desired address space
|
||||
* @param off the starting offset of the byte range being read
|
||||
* @param size the number of bytes being read
|
||||
* @param stopOnUnintialized if true a partial read is permitted and returned size may be
|
||||
* smaller than size requested
|
||||
* @return number of bytes actually read
|
||||
* @throws LowlevelError if spc has not been mapped within this MemoryState or memory fault
|
||||
* handler generated error
|
||||
*/
|
||||
@Override
|
||||
public int getChunk(byte[] res, AddressSpace spc, long off, int size,
|
||||
boolean stopOnUnintialized) {
|
||||
if (spc.isConstantSpace()) {
|
||||
System.arraycopy(Utils.longToBytes(off, size, language.isBigEndian()), 0, res, 0, size);
|
||||
return size;
|
||||
}
|
||||
MemoryBank mspace = getMemoryBank(spc);
|
||||
if (mspace == null)
|
||||
throw new LowlevelError("Getting chunk from unmapped memory space: " + spc.getName());
|
||||
return mspace.getChunk(off, size, res, stopOnUnintialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main interface for setting values for a range of bytes in the MemoryState. The
|
||||
* MemoryBank associated with the desired address space is looked up and the write is forwarded
|
||||
* to the setChunk method on the MemoryBank. If there is no registered MemoryBank or some other
|
||||
* error, an exception is throw. All setValue methods utilize this method to read the bytes from
|
||||
* the appropriate memory bank.
|
||||
*
|
||||
* @param val the byte values to be written into the MemoryState
|
||||
* @param spc the address space being written
|
||||
* @param off the starting offset of the range being written
|
||||
* @param size the number of bytes to write
|
||||
* @throws LowlevelError if spc has not been mapped within this MemoryState
|
||||
*/
|
||||
@Override
|
||||
public void setChunk(byte[] val, AddressSpace spc, long off, int size) {
|
||||
MemoryBank mspace = getMemoryBank(spc);
|
||||
if (mspace == null)
|
||||
throw new LowlevelError("Setting chunk of unmapped memory space: " + spc.getName());
|
||||
mspace.setChunk(off, size, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main interface for setting the initialization status for a range of bytes in the
|
||||
* MemoryState. The MemoryBank associated with the desired address space is looked up and the
|
||||
* write is forwarded to the setInitialized method on the MemoryBank. If there is no registered
|
||||
* MemoryBank or some other error, an exception is throw. All setValue methods utilize this
|
||||
* method to read the bytes from the appropriate memory bank.
|
||||
*
|
||||
* @param initialized indicates if range should be marked as initialized or not
|
||||
* @param spc the address space being written
|
||||
* @param off the starting offset of the range being written
|
||||
* @param size the number of bytes to write
|
||||
*/
|
||||
@Override
|
||||
public void setInitialized(boolean initialized, AddressSpace spc, long off, int size) {
|
||||
MemoryBank mspace = getMemoryBank(spc);
|
||||
if (mspace == null)
|
||||
throw new LowlevelError("Setting intialization status of unmapped memory space: " +
|
||||
spc.getName());
|
||||
mspace.setInitialized(off, size, initialized);
|
||||
}
|
||||
}
|
|
@ -1,310 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
public abstract class MemoryBank {
|
||||
|
||||
private final int pagesize; ///< Number of bytes in an aligned page access
|
||||
private final AddressSpace space; ///< The address space associated with this memory
|
||||
private final boolean isBigEndian;
|
||||
private final int initializedMaskSize; // number of bytes required for uninitialized mask
|
||||
|
||||
protected final MemoryFaultHandler faultHandler;
|
||||
|
||||
/**
|
||||
* A MemoryBank must be associated with a specific address space, have a preferred or natural
|
||||
* pagesize. The pagesize must be a power of 2.
|
||||
* @param spc is the associated address space
|
||||
* @param isBigEndian memory endianess
|
||||
* @param ps ps is the number of bytes in a page (must be a power of 2)
|
||||
* @param faultHandler memory fault handler
|
||||
*/
|
||||
public MemoryBank(AddressSpace spc, boolean isBigEndian, int ps, MemoryFaultHandler faultHandler) {
|
||||
space = spc;
|
||||
pagesize = ps;
|
||||
this.isBigEndian = isBigEndian;
|
||||
this.faultHandler = faultHandler;
|
||||
initializedMaskSize = (ps + 7) / 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return memory fault handler (may be null)
|
||||
*/
|
||||
public MemoryFaultHandler getMemoryFaultHandler() {
|
||||
return faultHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if memory bank is big endian
|
||||
*/
|
||||
public boolean isBigEndian() {
|
||||
return isBigEndian;
|
||||
}
|
||||
|
||||
/**
|
||||
* A MemoryBank is instantiated with a \e natural page size. Requests for large chunks of data
|
||||
* may be broken down into units of this size.
|
||||
* @return the number of bytes in a page.
|
||||
*/
|
||||
public int getPageSize() {
|
||||
return pagesize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of a page initialized mask in bytes. Each bit within the
|
||||
* mask corresponds to a data byte within a page.
|
||||
*/
|
||||
public int getInitializedMaskSize() {
|
||||
return initializedMaskSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the AddressSpace associated with this bank.
|
||||
*/
|
||||
public AddressSpace getSpace() {
|
||||
return space;
|
||||
}
|
||||
|
||||
/// This routine only retrieves data from a single \e page in the memory bank. Bytes need not
|
||||
/// be retrieved from the exact start of a page, but all bytes must come from \e one page.
|
||||
/// A page is a fixed number of bytes, and the address of a page is always aligned based
|
||||
/// on that number of bytes. This routine may be overridden for a page based implementation
|
||||
/// of the MemoryBank. The default implementation retrieves the page as aligned words
|
||||
/// using the find method.
|
||||
/// \param addr is the \e aligned offset of the desired page
|
||||
/// \param res is a pointer to where fetched data should be written
|
||||
/// \param skip is the offset \e into \e the \e page to get the bytes from
|
||||
/// \param size is the number of bytes to retrieve
|
||||
/// \param ignoreFault if true ignore fault and return
|
||||
//protected abstract void getPage(long addr,MemoryPage res,int skip,int size, int bufOffset);
|
||||
|
||||
protected abstract MemoryPage getPage(long addr);
|
||||
|
||||
/// This routine writes data only to a single \e page of the memory bank. Bytes need not be
|
||||
/// written to the exact start of the page, but all bytes must be written to only one page
|
||||
/// when using this routine. A page is a
|
||||
/// fixed number of bytes, and the address of a page is always aligned based on this size.
|
||||
/// This routine may be overridden for a page based implementation of the MemoryBank. The
|
||||
/// default implementation writes the page as a sequence of aligned words, using the
|
||||
/// insert method.
|
||||
/// \param addr is the \e aligned offset of the desired page
|
||||
/// \param val is a pointer to the bytes to be written into the page
|
||||
/// \param skip is the offset \e into \e the \e page where bytes will be written
|
||||
/// \param size is the number of bytes to be written
|
||||
/// \param bufOffset the offset in val from which to get the bytes
|
||||
protected abstract void setPage(long addr, byte[] val, int skip, int size, int bufOffset);
|
||||
|
||||
/// This routine marks a range within a single \e page of the memory bank as initialized or
|
||||
/// uninitialized. A page is a
|
||||
/// fixed number of bytes, and the address of a page is always aligned based on this size.
|
||||
/// This routine may be overridden for a page based implementation of the MemoryBank. The
|
||||
/// default implementation writes the page as a sequence of aligned words, using the
|
||||
/// insert method.
|
||||
/// \param addr is the \e aligned offset of the desired page
|
||||
/// \param initialized true if range should be marked as initialized, false if uninitialized
|
||||
/// \param skip is the offset \e into \e the \e page where bytes will be written
|
||||
/// \param size is the number of bytes to be written
|
||||
/// \param bufOffset the offset in val from which to get the bytes
|
||||
protected abstract void setPageInitialized(long addr, boolean initialized, int skip, int size,
|
||||
int bufOffset);
|
||||
|
||||
/// This the most general method for writing a sequence of bytes into the memory bank.
|
||||
/// The initial offset and page writes will be wrapped within the address space.
|
||||
/// \param offset is the start of the byte range to be written. This offset will be wrapped
|
||||
/// within the space
|
||||
/// \param size is the number of bytes to write
|
||||
/// \param val is a pointer to the sequence of bytes to be written into the bank
|
||||
public void setChunk(long offset, int size, byte[] val) {
|
||||
int cursize;
|
||||
int count;
|
||||
long pagemask = (pagesize - 1);
|
||||
long offalign;
|
||||
int skip;
|
||||
int bufOffset = 0;
|
||||
|
||||
count = 0;
|
||||
while (count < size) {
|
||||
cursize = pagesize;
|
||||
offset = space.truncateOffset(offset);
|
||||
offalign = offset & ~pagemask;
|
||||
skip = 0;
|
||||
if (offalign != offset) {
|
||||
skip = (int) (offset - offalign);
|
||||
cursize -= skip;
|
||||
}
|
||||
if (size - count < cursize)
|
||||
cursize = size - count;
|
||||
setPage(offalign, val, skip, cursize, bufOffset);
|
||||
count += cursize;
|
||||
offset += cursize;
|
||||
bufOffset += cursize;
|
||||
}
|
||||
}
|
||||
|
||||
/// This method allows ranges of bytes to marked as initialized or not.
|
||||
/// There is no restriction on the offset to write to or the number of bytes to be written,
|
||||
/// except that the range must be contained in the address space.
|
||||
/// \param offset is the start of the byte range to be written
|
||||
/// \param size is the number of bytes to write
|
||||
/// \param initialized indicates if the range should be marked as initialized or not
|
||||
public void setInitialized(long offset, int size, boolean initialized) {
|
||||
int cursize;
|
||||
int count;
|
||||
long pagemask = (pagesize - 1);
|
||||
long offalign;
|
||||
int skip;
|
||||
int bufOffset = 0;
|
||||
|
||||
count = 0;
|
||||
while (count < size) {
|
||||
cursize = pagesize;
|
||||
offalign = offset & ~pagemask;
|
||||
skip = 0;
|
||||
if (offalign != offset) {
|
||||
skip = (int) (offset - offalign);
|
||||
cursize -= skip;
|
||||
}
|
||||
if (size - count < cursize)
|
||||
cursize = size - count;
|
||||
setPageInitialized(offalign, initialized, skip, cursize, bufOffset);
|
||||
count += cursize;
|
||||
offset += cursize;
|
||||
bufOffset += cursize;
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the most general method for reading a sequence of bytes from the memory bank.
|
||||
/// There is no restriction on the offset or the number of bytes to read, except that the
|
||||
/// range must be contained in the address space.
|
||||
/// \param offset is the start of the byte range to read
|
||||
/// \param size is the number of bytes to read
|
||||
/// \param res is a pointer to where the retrieved bytes should be stored
|
||||
/// \param stopOnUnintialized if true a partial read is permitted and returned size may be
|
||||
/// smaller than size requested if uninitialized data is encountered.
|
||||
/// \return number of bytes actually read
|
||||
public int getChunk(long addrOffset, int size, byte[] res, boolean stopOnUnintialized) {
|
||||
int cursize, count;
|
||||
long pagemask = (pagesize - 1);
|
||||
long offalign;
|
||||
int skip;
|
||||
int bufOffset = 0;
|
||||
|
||||
addrOffset = space.truncateOffset(addrOffset);
|
||||
|
||||
count = 0;
|
||||
while (count < size) {
|
||||
cursize = pagesize;
|
||||
offalign = addrOffset & ~pagemask;
|
||||
skip = 0;
|
||||
if (offalign != addrOffset) {
|
||||
skip = (int) (addrOffset - offalign);
|
||||
cursize -= skip;
|
||||
}
|
||||
if (size - count < cursize)
|
||||
cursize = size - count;
|
||||
|
||||
MemoryPage page = getPage(offalign);
|
||||
|
||||
// Read initialized data which is available
|
||||
int initializedByteCount = page.getInitializedByteCount(skip, cursize);
|
||||
System.arraycopy(page.data, skip, res, bufOffset, initializedByteCount);
|
||||
count += initializedByteCount;
|
||||
|
||||
long nextAddrOffset = space.truncateOffset(addrOffset + initializedByteCount);
|
||||
addrOffset += initializedByteCount;
|
||||
bufOffset += initializedByteCount;
|
||||
cursize -= initializedByteCount;
|
||||
|
||||
if (cursize != 0) {
|
||||
// Handle incomplete read from current page
|
||||
skip += initializedByteCount;
|
||||
if (faultHandler.uninitializedRead(getSpace().getAddress(offalign + skip), cursize,
|
||||
page.data, skip)) {
|
||||
page.setInitialized(skip, cursize);
|
||||
}
|
||||
else if (stopOnUnintialized) {
|
||||
return count;
|
||||
}
|
||||
System.arraycopy(page.data, skip, res, bufOffset, cursize);
|
||||
count += cursize;
|
||||
|
||||
nextAddrOffset = space.truncateOffset(nextAddrOffset + cursize);
|
||||
addrOffset += cursize;
|
||||
bufOffset += cursize;
|
||||
}
|
||||
|
||||
// stop if wrapped midway
|
||||
if (addrOffset < 0) {
|
||||
if (nextAddrOffset > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (nextAddrOffset < addrOffset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// This is a static convenience routine for decoding a value from a sequence of bytes depending
|
||||
/// on the desired endianness
|
||||
/// \param ptr is the pointer to the bytes to decode
|
||||
/// \param size is the number of bytes
|
||||
/// \param bigendian is \b true if the bytes are encoded in big endian form
|
||||
/// \return the decoded value
|
||||
public static long constructValue(byte[] ptr, int offset, int size, boolean bigendian) {
|
||||
long res = 0;
|
||||
|
||||
if (bigendian) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
res <<= 8;
|
||||
res |= ptr[i + offset] & 0xffL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = size - 1; i >= 0; --i) {
|
||||
res <<= 8;
|
||||
res |= ptr[i + offset] & 0xffL;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// This is a static convenience routine for encoding bytes from a given value, depending on
|
||||
/// the desired endianness
|
||||
/// \param ptr is a pointer to the location to write the encoded bytes
|
||||
/// \param val is the value to be encoded
|
||||
/// \param size is the number of bytes to encode
|
||||
/// \param bigendian is \b true if a big endian encoding is desired
|
||||
public static void deconstructValue(byte[] ptr, int offset, long val, int size,
|
||||
boolean bigendian) {
|
||||
if (bigendian) {
|
||||
for (int i = size - 1; i >= 0; --i) {
|
||||
ptr[i + offset] = (byte) (val & 0xff);
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
ptr[i + offset] = (byte) (val & 0xff);
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
public interface MemoryFaultHandler {
|
||||
|
||||
/**
|
||||
* An attempt has been made to read uninitialized memory at the
|
||||
* specified address.
|
||||
* @param address uninitialized storage address (memory, register or unique)
|
||||
* @param size number of uninitialized bytes
|
||||
* @param buf storage buffer
|
||||
* @param bufOffset read offset within buffer
|
||||
* @return true if data should be treated as initialized
|
||||
*/
|
||||
boolean uninitializedRead(Address address, int size, byte[] buf, int bufOffset);
|
||||
|
||||
/**
|
||||
* Unable to translate the specified address
|
||||
* @param address address which failed to be translated
|
||||
* @param write true if memory operation was a write vs. read
|
||||
* @return true if fault was handled
|
||||
*/
|
||||
boolean unknownAddress(Address address, boolean write);
|
||||
|
||||
}
|
|
@ -1,252 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* <code>MemoryPage</code> is allows the contents/data of a memory page
|
||||
* to be maintained along with an initializedMask. Each bit within the
|
||||
* initializedMask corresponds to a data byte within the page. A null
|
||||
* mask indicates that all data within the page is initialized. A one-bit
|
||||
* within the mask indicates that the corresponding data byte is initialized.
|
||||
*/
|
||||
public class MemoryPage {
|
||||
|
||||
public final byte[] data;
|
||||
private byte[] initializedMask;
|
||||
|
||||
/**
|
||||
* Construct a new fully initialized page containing
|
||||
* all zero (0) byte data.
|
||||
*/
|
||||
public MemoryPage(int pageSize) {
|
||||
data = new byte[pageSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a memory page with an existing data bytes buffer
|
||||
* @param bytes buffer
|
||||
*/
|
||||
public MemoryPage(byte[] bytes) {
|
||||
data = bytes;
|
||||
}
|
||||
|
||||
public byte[] getInitializedMask() {
|
||||
return initializedMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark entire page as uninitialized
|
||||
*/
|
||||
public void setUninitialized() {
|
||||
initializedMask = getInitializedMask(data.length, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark entire page as uninitialized
|
||||
*/
|
||||
public void setInitialized() {
|
||||
initializedMask = getInitializedMask(data.length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update initialization mask
|
||||
* @param pageOffset
|
||||
* @param size
|
||||
* @param maskUpdate
|
||||
*/
|
||||
public void setInitialized(int pageOffset, int size, byte[] maskUpdate) {
|
||||
int maskOffset = pageOffset / 8;
|
||||
int firstBit = pageOffset % 8;
|
||||
while (size > 0) {
|
||||
int s = Math.min(size, 8 - firstBit);
|
||||
size -= s;
|
||||
int mask = (0xff << firstBit) & ((1 << (firstBit + s)) - 1);
|
||||
int val = mask;
|
||||
if (maskUpdate != null) {
|
||||
val &= maskUpdate[maskOffset];
|
||||
}
|
||||
if (initializedMask == null) {
|
||||
// allocate mask if needed
|
||||
byte test = (byte) (val | ~mask);
|
||||
if (test == (byte) -1) {
|
||||
++maskOffset;
|
||||
firstBit = 0;
|
||||
continue;
|
||||
}
|
||||
initializedMask = getInitializedMask(data.length, true);
|
||||
}
|
||||
initializedMask[maskOffset] = (byte) ((initializedMask[maskOffset] & ~mask) | val);
|
||||
++maskOffset;
|
||||
firstBit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark specified page region as initialized.
|
||||
* @param pageOffset
|
||||
* @param size
|
||||
*/
|
||||
public void setInitialized(int pageOffset, int size) {
|
||||
if (initializedMask == null) {
|
||||
return;
|
||||
}
|
||||
if (pageOffset == 0 && size == data.length) {
|
||||
initializedMask = null;
|
||||
return;
|
||||
}
|
||||
setInitialized(initializedMask, pageOffset, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark specified page region as uninitialized.
|
||||
* @param pageOffset
|
||||
* @param size
|
||||
*/
|
||||
public void setUninitialized(int pageOffset, int size) {
|
||||
if (initializedMask == null) {
|
||||
initializedMask = getInitializedMask(data.length, true);
|
||||
}
|
||||
setUninitialized(initializedMask, pageOffset, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of leading bytes within page range which have been
|
||||
* initialized.
|
||||
* @param pageOffset
|
||||
* @param size
|
||||
* @return number of leading bytes within page range which have been
|
||||
* initialized.
|
||||
*/
|
||||
public int getInitializedByteCount(int pageOffset, int size) {
|
||||
return getInitializedByteCount(initializedMask, pageOffset, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an initialized mask for the specified page size
|
||||
* @param pageSize
|
||||
* @param initialized
|
||||
* @return
|
||||
*/
|
||||
public static byte[] getInitializedMask(int pageSize, boolean initialized) {
|
||||
byte[] mask = new byte[(pageSize + 7) / 8];
|
||||
if (initialized) {
|
||||
Arrays.fill(mask, (byte) -1);
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an initialized mask for the specified page size.
|
||||
* The region is identified by offset and size. The remaining portions
|
||||
* of the mask will be set based upon !initialized.
|
||||
* @param pageSize
|
||||
* @param offset
|
||||
* @param size
|
||||
* @param initialized
|
||||
* @return
|
||||
*/
|
||||
public static byte[] getInitializedMask(int pageSize, int offset, int size,
|
||||
boolean initialized) {
|
||||
byte[] mask = getInitializedMask(pageSize, true);
|
||||
if (initialized) {
|
||||
if (offset != 0) {
|
||||
setUninitialized(mask, 0, offset);
|
||||
}
|
||||
int end = offset + size;
|
||||
if (end < pageSize) {
|
||||
setUninitialized(mask, end, pageSize - end);
|
||||
}
|
||||
}
|
||||
else if (size != 0) {
|
||||
setUninitialized(mask, offset, size);
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark specified page region as initialized.
|
||||
* @param initializedMask
|
||||
* @param pageOffset
|
||||
* @param size
|
||||
*/
|
||||
public static void setInitialized(byte[] initializedMask, int pageOffset, int size) {
|
||||
int maskOffset = pageOffset / 8;
|
||||
int firstBit = pageOffset % 8;
|
||||
while (size > 0) {
|
||||
int s = Math.min(size, 8 - firstBit);
|
||||
size -= s;
|
||||
int mask = (0xff << firstBit) & ((1 << (firstBit + s)) - 1);
|
||||
initializedMask[maskOffset] |= (byte) mask;
|
||||
++maskOffset;
|
||||
firstBit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark specified page region as uninitialized.
|
||||
* @param initializedMask
|
||||
* @param pageOffset
|
||||
* @param size
|
||||
*/
|
||||
public static void setUninitialized(byte[] initializedMask, int pageOffset, int size) {
|
||||
int maskOffset = pageOffset / 8;
|
||||
int firstBit = pageOffset % 8;
|
||||
while (size > 0) {
|
||||
int s = Math.min(size, 8 - firstBit);
|
||||
size -= s;
|
||||
int mask = (0xff << firstBit) & ((1 << (firstBit + s)) - 1);
|
||||
initializedMask[maskOffset] &= (byte) ~mask;
|
||||
++maskOffset;
|
||||
firstBit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine how many leading bytes of a specified page region is marked as
|
||||
* initialized. Valid page region defined by pageOffset and size is assumed.
|
||||
* @param initializedMask
|
||||
* @param pageOffset
|
||||
* @param size
|
||||
* @return number of leading bytes at pageOffset (upto size) are initialized.
|
||||
*/
|
||||
public static int getInitializedByteCount(byte[] initializedMask, int pageOffset, int size) {
|
||||
if (initializedMask == null) {
|
||||
return size;
|
||||
}
|
||||
int initializedSize = 0;
|
||||
int maskOffset = pageOffset / 8;
|
||||
int firstBit = pageOffset % 8;
|
||||
while (size > 0) {
|
||||
int s = Math.min(size, 8 - firstBit); // number of bytes represented by mask
|
||||
size -= s;
|
||||
int mask = (0xff << firstBit) & ((1 << (firstBit + s)) - 1);
|
||||
int result = initializedMask[maskOffset] & mask;
|
||||
if (result != mask) {
|
||||
// count leading bits
|
||||
for (result >>= firstBit; (result & 1) != 0; result >>= 1) {
|
||||
++initializedSize;
|
||||
}
|
||||
return initializedSize;
|
||||
}
|
||||
initializedSize += s;
|
||||
++maskOffset;
|
||||
firstBit = 0;
|
||||
}
|
||||
return initializedSize;
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import generic.stl.*;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
public class MemoryPageBank extends MemoryBank {
|
||||
|
||||
protected MapSTL<Long, MemoryPage> page = new ComparableMapSTL<>();
|
||||
|
||||
public MemoryPageBank(AddressSpace spc, boolean isBigEndian, int ps,
|
||||
MemoryFaultHandler faultHandler) {
|
||||
super(spc, isBigEndian, ps, faultHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MemoryPage getPage(long addr) {
|
||||
IteratorSTL<Pair<Long, MemoryPage>> iter;
|
||||
iter = page.find(addr);
|
||||
if (iter.equals(page.end())) {
|
||||
int size = getPageSize();
|
||||
MemoryPage pageptr = new MemoryPage(size);
|
||||
page.add(addr, pageptr);
|
||||
pageptr.setUninitialized();
|
||||
return pageptr;
|
||||
}
|
||||
return (iter.get()).second;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setPage(long addr, byte[] val, int skip, int size, int bufOffset) {
|
||||
if (size == getPageSize() && bufOffset == 0) {
|
||||
page.put(addr, new MemoryPage(val));
|
||||
return;
|
||||
}
|
||||
MemoryPage pageptr = getPage(addr);
|
||||
System.arraycopy(val, bufOffset, pageptr.data, skip, size);
|
||||
pageptr.setInitialized(skip, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setPageInitialized(long addr, boolean initialized, int skip, int size,
|
||||
int bufOffset) {
|
||||
|
||||
MemoryPage pageptr;
|
||||
IteratorSTL<Pair<Long, MemoryPage>> iter;
|
||||
iter = page.find(addr);
|
||||
if (iter.equals(page.end())) {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
int pagesize = getPageSize();
|
||||
pageptr = new MemoryPage(pagesize);
|
||||
page.add(addr, pageptr);
|
||||
}
|
||||
else {
|
||||
pageptr = (iter.get()).second;
|
||||
|
||||
}
|
||||
if (size == getPageSize() && bufOffset == 0) {
|
||||
if (initialized) {
|
||||
pageptr.setInitialized();
|
||||
}
|
||||
else {
|
||||
pageptr.setUninitialized();
|
||||
}
|
||||
}
|
||||
else if (initialized) {
|
||||
pageptr.setInitialized(skip, size);
|
||||
}
|
||||
else {
|
||||
pageptr.setUninitialized(skip, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import generic.stl.IteratorSTL;
|
||||
import generic.stl.Pair;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
/// \brief Memory bank that overlays some other memory bank, using a "copy on write" behavior.
|
||||
///
|
||||
/// Pages are copied from the underlying object only when there is
|
||||
/// a write. The underlying access routines are overridden to make optimal use
|
||||
/// of this page implementation. The underlying memory bank can be a \b null pointer
|
||||
/// in which case, this memory bank behaves as if it were initially filled with zeros.
|
||||
public class MemoryPageOverlay extends MemoryPageBank {
|
||||
|
||||
protected MemoryBank underlie; // underlying memory object
|
||||
|
||||
/// A page overlay memory bank needs all the parameters for a generic memory bank
|
||||
/// and it needs to know the underlying memory bank being overlayed.
|
||||
/// \param spc is the address space associated with the memory bank
|
||||
/// \param ul is the underlying MemoryBank
|
||||
public MemoryPageOverlay(AddressSpace spc, MemoryBank ul, MemoryFaultHandler faultHandler) {
|
||||
super(spc,ul.isBigEndian(),ul.getPageSize(),faultHandler);
|
||||
underlie = ul;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MemoryPage getPage(long addr) {
|
||||
IteratorSTL<Pair<Long, MemoryPage>> iter;
|
||||
iter = page.find(addr);
|
||||
if (iter.equals(page.end())) {
|
||||
MemoryPage pageptr;
|
||||
if (underlie == null) {
|
||||
int size = getPageSize();
|
||||
pageptr = new MemoryPage(size);
|
||||
for(int i=0;i<size;++i) {
|
||||
pageptr.data[i] = 0;
|
||||
}
|
||||
pageptr.setUninitialized();
|
||||
return pageptr;
|
||||
}
|
||||
// defer to underlie memory bank
|
||||
pageptr = underlie.getPage(addr);
|
||||
page.add(addr, pageptr);
|
||||
return pageptr;
|
||||
}
|
||||
return (iter.get()).second;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
|
||||
public interface MemoryState {
|
||||
|
||||
/**
|
||||
* MemoryBanks associated with specific address spaces must be registers with this MemoryState
|
||||
* via this method. Each address space that will be used during emulation must be registered
|
||||
* separately. The MemoryState object does not assume responsibility for freeing the MemoryBank.
|
||||
* @param bank is a pointer to the MemoryBank to be registered
|
||||
*/
|
||||
void setMemoryBank(MemoryBank bank);
|
||||
|
||||
/**
|
||||
* Any MemoryBank that has been registered with this MemoryState can be retrieved via this
|
||||
* method if the MemoryBank's associated address space is known.
|
||||
* @param spc is the address space of the desired MemoryBank
|
||||
* @return the MemoryBank or null if no bank is associated with spc.
|
||||
*/
|
||||
MemoryBank getMemoryBank(AddressSpace spc);
|
||||
|
||||
/**
|
||||
* A convenience method for setting a value directly on a varnode rather than
|
||||
* breaking out the components
|
||||
* @param vn the varnode location to be written
|
||||
* @param cval the value to write into the varnode location
|
||||
*/
|
||||
void setValue(Varnode vn, long cval);
|
||||
|
||||
/**
|
||||
* A convenience method for setting a value directly on a register rather than
|
||||
* breaking out the components
|
||||
* @param reg the register location to be written
|
||||
* @param cval the value to write into the register location
|
||||
*/
|
||||
void setValue(Register reg, long cval);
|
||||
|
||||
/**
|
||||
* This is a convenience method for setting registers by name.
|
||||
* Any register name known to the language can be used as a write location.
|
||||
* The associated address space, offset, and size is looked up and automatically
|
||||
* passed to the main setValue routine.
|
||||
* @param nm is the name of the register
|
||||
* @param cval is the value to write to the register
|
||||
*/
|
||||
void setValue(String nm, long cval);
|
||||
|
||||
/**
|
||||
* This is the main interface for writing values to the MemoryState.
|
||||
* If there is no registered MemoryBank for the desired address space, or
|
||||
* if there is some other error, an exception is thrown.
|
||||
* @param spc is the address space to write to
|
||||
* @param off is the offset where the value should be written
|
||||
* @param size is the number of bytes to be written
|
||||
* @param cval is the value to be written
|
||||
*/
|
||||
void setValue(AddressSpace spc, long off, int size, long cval);
|
||||
|
||||
/**
|
||||
* A convenience method for reading a value directly from a varnode rather
|
||||
* than querying for the offset and space
|
||||
* @param vn the varnode location to be read
|
||||
* @return the value read from the varnode location
|
||||
*/
|
||||
long getValue(Varnode vn);
|
||||
|
||||
/**
|
||||
* A convenience method for reading a value directly from a register rather
|
||||
* than querying for the offset and space
|
||||
* @param reg the register location to be read
|
||||
* @return the value read from the register location
|
||||
*/
|
||||
long getValue(Register reg);
|
||||
|
||||
/**
|
||||
* This is a convenience method for reading registers by name.
|
||||
* any register name known to the language can be used as a read location.
|
||||
* The associated address space, offset, and size is looked up and automatically
|
||||
* passed to the main getValue routine.
|
||||
* @param nm is the name of the register
|
||||
* @return the value associated with that register
|
||||
*/
|
||||
long getValue(String nm);
|
||||
|
||||
/**
|
||||
* This is the main interface for reading values from the MemoryState.
|
||||
* If there is no registered MemoryBank for the desired address space, or
|
||||
* if there is some other error, an exception is thrown.
|
||||
* @param spc is the address space being queried
|
||||
* @param off is the offset of the value being queried
|
||||
* @param size is the number of bytes to query
|
||||
* @return the queried value
|
||||
*/
|
||||
long getValue(AddressSpace spc, long off, int size);
|
||||
|
||||
/**
|
||||
* A convenience method for setting a value directly on a varnode rather than
|
||||
* breaking out the components
|
||||
* @param vn the varnode location to be written
|
||||
* @param cval the value to write into the varnode location
|
||||
*/
|
||||
void setValue(Varnode vn, BigInteger cval);
|
||||
|
||||
/**
|
||||
* A convenience method for setting a value directly on a register rather than
|
||||
* breaking out the components
|
||||
* @param reg the register location to be written
|
||||
* @param cval the value to write into the register location
|
||||
*/
|
||||
void setValue(Register reg, BigInteger cval);
|
||||
|
||||
/**
|
||||
* This is a convenience method for setting registers by name.
|
||||
* Any register name known to the language can be used as a write location.
|
||||
* The associated address space, offset, and size is looked up and automatically
|
||||
* passed to the main setValue routine.
|
||||
* @param nm is the name of the register
|
||||
* @param cval is the value to write to the register
|
||||
*/
|
||||
void setValue(String nm, BigInteger cval);
|
||||
|
||||
/**
|
||||
* This is the main interface for writing values to the MemoryState.
|
||||
* If there is no registered MemoryBank for the desired address space, or
|
||||
* if there is some other error, an exception is thrown.
|
||||
* @param spc is the address space to write to
|
||||
* @param off is the offset where the value should be written
|
||||
* @param size is the number of bytes to be written
|
||||
* @param cval is the value to be written
|
||||
*/
|
||||
void setValue(AddressSpace spc, long off, int size, BigInteger cval);
|
||||
|
||||
/**
|
||||
* A convenience method for reading a value directly from a varnode rather
|
||||
* than querying for the offset and space
|
||||
* @param vn the varnode location to be read
|
||||
* @param signed true if signed value should be returned, false for unsigned value
|
||||
* @return the unsigned value read from the varnode location
|
||||
*/
|
||||
BigInteger getBigInteger(Varnode vn, boolean signed);
|
||||
|
||||
/**
|
||||
* A convenience method for reading a value directly from a register rather
|
||||
* than querying for the offset and space
|
||||
* @param reg the register location to be read
|
||||
* @return the unsigned value read from the register location
|
||||
*/
|
||||
BigInteger getBigInteger(Register reg);
|
||||
|
||||
/**
|
||||
* This is a convenience method for reading registers by name.
|
||||
* any register name known to the language can be used as a read location.
|
||||
* The associated address space, offset, and size is looked up and automatically
|
||||
* passed to the main getValue routine.
|
||||
* @param nm is the name of the register
|
||||
* @return the unsigned value associated with that register
|
||||
*/
|
||||
BigInteger getBigInteger(String nm);
|
||||
|
||||
/**
|
||||
* This is the main interface for reading values from the MemoryState.
|
||||
* If there is no registered MemoryBank for the desired address space, or
|
||||
* if there is some other error, an exception is thrown.
|
||||
* @param spc is the address space being queried
|
||||
* @param off is the offset of the value being queried
|
||||
* @param size is the number of bytes to query
|
||||
* @param signed true if signed value should be returned, false for unsigned value
|
||||
* @return the queried unsigned value
|
||||
*/
|
||||
BigInteger getBigInteger(AddressSpace spc, long off, int size, boolean signed);
|
||||
|
||||
/**
|
||||
* This is the main interface for reading a range of bytes from the MemorySate.
|
||||
* The MemoryBank associated with the address space of the query is looked up
|
||||
* and the request is forwarded to the getChunk method on the MemoryBank. If there
|
||||
* is no registered MemoryBank or some other error, an exception is thrown.
|
||||
* All getLongValue methods utilize this method to read the bytes from the
|
||||
* appropriate memory bank.
|
||||
* @param res the result buffer for storing retrieved bytes
|
||||
* @param spc the desired address space
|
||||
* @param off the starting offset of the byte range being read
|
||||
* @param size the number of bytes being read
|
||||
* @param stopOnUnintialized if true a partial read is permitted and returned size may be
|
||||
* smaller than size requested
|
||||
* @return number of bytes actually read
|
||||
* @throws LowlevelError if spc has not been mapped within this MemoryState or memory fault
|
||||
* handler generated error
|
||||
*/
|
||||
int getChunk(byte[] res, AddressSpace spc, long off, int size,
|
||||
boolean stopOnUnintialized);
|
||||
|
||||
/**
|
||||
* This is the main interface for setting values for a range of bytes in the MemoryState.
|
||||
* The MemoryBank associated with the desired address space is looked up and the
|
||||
* write is forwarded to the setChunk method on the MemoryBank. If there is no
|
||||
* registered MemoryBank or some other error, an exception is throw.
|
||||
* All setValue methods utilize this method to read the bytes from the
|
||||
* appropriate memory bank.
|
||||
* @param val the byte values to be written into the MemoryState
|
||||
* @param spc the address space being written
|
||||
* @param off the starting offset of the range being written
|
||||
* @param size the number of bytes to write
|
||||
* @throws LowlevelError if spc has not been mapped within this MemoryState
|
||||
*/
|
||||
void setChunk(byte[] val, AddressSpace spc, long off, int size);
|
||||
|
||||
/**
|
||||
* This is the main interface for setting the initialization status for a range of bytes
|
||||
* in the MemoryState.
|
||||
* The MemoryBank associated with the desired address space is looked up and the
|
||||
* write is forwarded to the setInitialized method on the MemoryBank. If there is no
|
||||
* registered MemoryBank or some other error, an exception is throw.
|
||||
* All setValue methods utilize this method to read the bytes from the
|
||||
* appropriate memory bank.
|
||||
* @param initialized indicates if range should be marked as initialized or not
|
||||
* @param spc the address space being written
|
||||
* @param off the starting offset of the range being written
|
||||
* @param size the number of bytes to write
|
||||
*/
|
||||
void setInitialized(boolean initialized, AddressSpace spc, long off, int size);
|
||||
|
||||
}
|
|
@ -1,254 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import generic.stl.ComparableMapSTL;
|
||||
import generic.stl.MapSTL;
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
/**
|
||||
* An subclass of {@link MemoryBank} intended for modeling the "unique" memory
|
||||
* space. The space is byte-addressable and paging is not supported.
|
||||
*/
|
||||
public class UniqueMemoryBank extends MemoryBank {
|
||||
|
||||
/**A map from {@link Long} offsets to byte values would require many lookups.
|
||||
* As an optimization, this map is defined from {@link Long} values to
|
||||
* {@link WordInfo} objects, each of which represents an eight-byte word
|
||||
* of memory. Each key in this map must be 0 mod 8.
|
||||
*/
|
||||
protected MapSTL<Long, WordInfo> map = new ComparableMapSTL<Long, WordInfo>();
|
||||
|
||||
private static final long ALIGNMENT_MASK = 0xfffffffffffffff8L;
|
||||
|
||||
//note that WordInfo use the bits in a byte to record whether
|
||||
//or not a given byte has been written to, so you can't just
|
||||
//change WORD_SIZE to another value and without also changing
|
||||
//the implementation of WordInfo
|
||||
private static final int WORD_SIZE = 8;
|
||||
|
||||
private byte[] buffer = new byte[WORD_SIZE];
|
||||
|
||||
public UniqueMemoryBank(AddressSpace spc, boolean isBigEndian) {
|
||||
super(spc, isBigEndian, 0, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MemoryPage getPage(long addr) {
|
||||
throw new UnsupportedOperationException("UniqueMemoryBank does not support paging");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setPage(long addr, byte[] val, int skip, int size, int bufOffset) {
|
||||
throw new UnsupportedOperationException("UniqueMemoryBank does not support paging");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setPageInitialized(long addr, boolean initialized, int skip, int size,
|
||||
int bufOffset) {
|
||||
throw new UnsupportedOperationException("UniqueMemoryBank does not support paging");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChunk(long offset, int size, byte[] dest, boolean stopOnUninitialized) {
|
||||
int bytesRead = 0;
|
||||
if (size == 0) {
|
||||
return bytesRead;
|
||||
}
|
||||
try {
|
||||
//align if necessary
|
||||
int adjustment = (int) offset % WORD_SIZE;
|
||||
if (adjustment != 0) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
throw new LowlevelError("Attempted to read uninitialized word in unique space");
|
||||
}
|
||||
for (int i = adjustment; i < WORD_SIZE && bytesRead < size; ++i) {
|
||||
dest[bytesRead++] = word.getByte(i);
|
||||
offset += 1;
|
||||
}
|
||||
}
|
||||
//copy a word at a time
|
||||
while (size - bytesRead > 0) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
throw new LowlevelError("Attempted to read uninitialized word in unique space");
|
||||
}
|
||||
offset += WORD_SIZE;
|
||||
//whole word is initialized, copy it (or the appropriate
|
||||
//initial segment) all at once
|
||||
int bytesToRead = Math.min(WORD_SIZE, size - bytesRead);
|
||||
if (word.isEntireWordInitialized()) {
|
||||
word.getWord(buffer);
|
||||
System.arraycopy(buffer, 0, dest, bytesRead,
|
||||
Math.min(WORD_SIZE, size - bytesRead));
|
||||
bytesRead += bytesToRead;
|
||||
continue;
|
||||
}
|
||||
//not entirely initialized, copy one byte at a time until
|
||||
//all requested bytes read (or word.getByte throws an exception)
|
||||
int base = bytesRead;
|
||||
for (int i = 0; i < bytesToRead; ++i) {
|
||||
dest[base + i] = word.getByte(i);
|
||||
bytesRead += 1;
|
||||
}
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
catch (LowlevelError e) {
|
||||
if (stopOnUninitialized) {
|
||||
return bytesRead;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunk(long offset, int size, byte[] src) {
|
||||
if (size == 0 || src.length == 0) {
|
||||
return;
|
||||
}
|
||||
int currentPosition = 0;
|
||||
//align if necessary
|
||||
int adjustment = (int) offset % WORD_SIZE;
|
||||
if (adjustment != 0) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
word = new WordInfo();
|
||||
map.put(offset & ALIGNMENT_MASK, word);
|
||||
}
|
||||
for (int i = adjustment; i < WORD_SIZE; ++i) {
|
||||
word.setByte(src[currentPosition], i);
|
||||
offset += 1;
|
||||
currentPosition += 1;
|
||||
}
|
||||
}
|
||||
while (size > currentPosition) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
word = new WordInfo();
|
||||
map.put(offset & ALIGNMENT_MASK, word);
|
||||
}
|
||||
int bytesToWrite = Math.min(WORD_SIZE, size - currentPosition);
|
||||
for (int i = 0; i < bytesToWrite; i++) {
|
||||
word.setByte(src[currentPosition + i], i);
|
||||
}
|
||||
offset += bytesToWrite;
|
||||
currentPosition += bytesToWrite;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear unique storage at the start of an instruction
|
||||
*/
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple class representing a byte-addressable word of memory. Each
|
||||
* byte can be either initialized to a byte value or uninitialized.
|
||||
* It is an error to attempt to read an uninitialized byte.
|
||||
*/
|
||||
public static class WordInfo {
|
||||
public byte initialized;
|
||||
public long word;
|
||||
|
||||
/**
|
||||
* Constructs a {@link WordInfo} object with all bytes uninitialized.
|
||||
*/
|
||||
public WordInfo() {
|
||||
initialized = 0;
|
||||
word = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the byte at {@code index} and sets its value to
|
||||
* {@code val}
|
||||
* @param val new value
|
||||
* @param index index
|
||||
* @throws LowlevelError if the index is invalid
|
||||
*/
|
||||
public void setByte(byte val, int index) {
|
||||
validateIndex(index);
|
||||
word &= ~(0xffL << (WORD_SIZE * index));
|
||||
long shifted = ((long) val) << (WORD_SIZE * index);
|
||||
word |= shifted;
|
||||
initialized |= (1 << index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte at the given index
|
||||
* @param index index
|
||||
* @return corresponding byte value
|
||||
* @throws LowlevelError if the index is invalid or the requested byte
|
||||
* is not initialized.
|
||||
*/
|
||||
public byte getByte(int index) {
|
||||
validateIndex(index);
|
||||
checkInitialized(index);
|
||||
long selected = word & (0xffL << (WORD_SIZE * index));
|
||||
long adjusted = selected >> (WORD_SIZE * index);
|
||||
return (byte) adjusted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an entire word into {@code buffer}
|
||||
* @param buffer buffer to write a single word to. Must have
|
||||
* length 8.
|
||||
* @throws LowlevelError if the entire word is not initialized
|
||||
*/
|
||||
public void getWord(byte[] buffer) {
|
||||
if (initialized != ((byte) (0xff))) {
|
||||
throw new LowlevelError("Attempted to read uninitialized word in unique space");
|
||||
}
|
||||
if (buffer.length != WORD_SIZE) {
|
||||
throw new IllegalArgumentException("Buffer must have length 8");
|
||||
}
|
||||
for (int i = 0; i < WORD_SIZE; ++i) {
|
||||
buffer[i] = (byte) ((word & (0xffL << (WORD_SIZE * i))) >> (WORD_SIZE * i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true precisely when the entire word is initialized.
|
||||
* @return true if entire work initialized
|
||||
*/
|
||||
protected boolean isEntireWordInitialized() {
|
||||
return initialized == (byte) 0xff;
|
||||
}
|
||||
|
||||
//assumes 0 <= index <= 7
|
||||
private void checkInitialized(int index) {
|
||||
if ((initialized & (1 << (index))) == 0) {
|
||||
throw new LowlevelError(
|
||||
"Attempted to read uninitialized memory in the unique space.");
|
||||
}
|
||||
}
|
||||
|
||||
//ensure that the provided index is valid
|
||||
private void validateIndex(int index) {
|
||||
if (index < 0 || index > 7) {
|
||||
throw new LowlevelError("Invalid index: " + Integer.toString(index));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public abstract class BinaryOpBehavior extends OpBehavior {
|
||||
|
||||
BinaryOpBehavior(int opcode) {
|
||||
super(opcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the binary (2 input args) operation using long data
|
||||
* @param sizeout intended output size (bytes)
|
||||
* @param sizein in1 size (bytes)
|
||||
* @param unsignedIn1 unsigned input 1
|
||||
* @param unsignedIn2 unsigned input 2
|
||||
* @return operation result. NOTE: if the operation overflows bits may be
|
||||
* set beyond the specified sizeout. Even though results should be treated
|
||||
* as unsigned it may be returned as a signed long value. It is expected that the
|
||||
* returned result always be properly truncated by the caller since the evaluation
|
||||
* may not - this is done to conserve emulation cycles.
|
||||
* @see Utils#longToBytes(long, int, boolean)
|
||||
* @see Utils#bytesToLong(byte[], int, boolean)
|
||||
*/
|
||||
|
||||
public abstract long evaluateBinary(int sizeout, int sizein, long unsignedIn1, long unsignedIn2);
|
||||
|
||||
/**
|
||||
* Evaluate the binary (2 input args) operation using BigInteger data
|
||||
* @param sizeout intended output size (bytes)
|
||||
* @param sizein in1 size (bytes)
|
||||
* @param unsignedIn1 unsigned input 1
|
||||
* @param unsignedIn2 unsigned input 2
|
||||
* @return operation result. NOTE: if the operation overflows bits may be
|
||||
* set beyond the specified sizeout. Even though results should be treated
|
||||
* as unsigned it may be returned as a signed value. It is expected that the
|
||||
* returned result always be properly truncated by the caller since the evaluation
|
||||
* may not - this is done to conserve emulation cycles.
|
||||
* @see Utils#bigIntegerToBytes(BigInteger, int, boolean)
|
||||
* @see Utils#bytesToBigInteger(byte[], int, boolean, boolean)
|
||||
*/
|
||||
public abstract BigInteger evaluateBinary(int sizeout, int sizein, BigInteger unsignedIn1,
|
||||
BigInteger unsignedIn2);
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
public class OpBehavior {
|
||||
|
||||
final int opcode;
|
||||
|
||||
OpBehavior(int opcode) {
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
public int getOpCode() {
|
||||
return opcode;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorBoolAnd extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorBoolAnd() {
|
||||
super(PcodeOp.BOOL_AND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = in1 & in2;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.and(in2);
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorBoolNegate extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorBoolNegate() {
|
||||
super(PcodeOp.BOOL_NEGATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
long res = in1 ^ 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
BigInteger res = in1.xor(BigInteger.ONE);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorBoolOr extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorBoolOr() {
|
||||
super(PcodeOp.BOOL_OR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = in1 | in2;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.or(in2);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorBoolXor extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorBoolXor() {
|
||||
super(PcodeOp.BOOL_XOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = in1 ^ in2;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.xor(in2);
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorCopy extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorCopy() {
|
||||
super(PcodeOp.COPY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
return in1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
return in1;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public long recoverInputUnary( int sizeout, long out, int sizein ) {
|
||||
// return out;
|
||||
// }
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorEqual extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorEqual() {
|
||||
super(PcodeOp.INT_EQUAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
return (in1 == in2) ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.equals(in2) ? BigInteger.ONE : BigInteger.ZERO;
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
public class OpBehaviorFactory {
|
||||
|
||||
private static Map<Integer, OpBehavior> opBehaviorMap = new HashMap<Integer, OpBehavior>();
|
||||
static {
|
||||
// TODO: should pass float format factory
|
||||
|
||||
opBehaviorMap.put(PcodeOp.COPY, new OpBehaviorCopy());
|
||||
opBehaviorMap.put(PcodeOp.LOAD, new SpecialOpBehavior(PcodeOp.LOAD));
|
||||
opBehaviorMap.put(PcodeOp.STORE, new SpecialOpBehavior(PcodeOp.STORE));
|
||||
opBehaviorMap.put(PcodeOp.BRANCH, new SpecialOpBehavior(PcodeOp.BRANCH));
|
||||
opBehaviorMap.put(PcodeOp.CBRANCH, new SpecialOpBehavior(PcodeOp.CBRANCH));
|
||||
opBehaviorMap.put(PcodeOp.BRANCHIND, new SpecialOpBehavior(PcodeOp.BRANCHIND));
|
||||
opBehaviorMap.put(PcodeOp.CALL, new SpecialOpBehavior(PcodeOp.CALL));
|
||||
opBehaviorMap.put(PcodeOp.CALLIND, new SpecialOpBehavior(PcodeOp.CALLIND));
|
||||
opBehaviorMap.put(PcodeOp.CALLOTHER, new SpecialOpBehavior(PcodeOp.CALLOTHER));
|
||||
opBehaviorMap.put(PcodeOp.RETURN, new SpecialOpBehavior(PcodeOp.RETURN));
|
||||
|
||||
opBehaviorMap.put(PcodeOp.MULTIEQUAL, new SpecialOpBehavior(PcodeOp.MULTIEQUAL));
|
||||
opBehaviorMap.put(PcodeOp.INDIRECT, new SpecialOpBehavior(PcodeOp.INDIRECT));
|
||||
|
||||
opBehaviorMap.put(PcodeOp.PIECE, new OpBehaviorPiece());
|
||||
opBehaviorMap.put(PcodeOp.SUBPIECE, new OpBehaviorSubpiece());
|
||||
opBehaviorMap.put(PcodeOp.INT_EQUAL, new OpBehaviorEqual());
|
||||
opBehaviorMap.put(PcodeOp.INT_NOTEQUAL, new OpBehaviorNotEqual());
|
||||
opBehaviorMap.put(PcodeOp.INT_SLESS, new OpBehaviorIntSless());
|
||||
opBehaviorMap.put(PcodeOp.INT_SLESSEQUAL, new OpBehaviorIntSlessEqual());
|
||||
opBehaviorMap.put(PcodeOp.INT_LESS, new OpBehaviorIntLess());
|
||||
opBehaviorMap.put(PcodeOp.INT_LESSEQUAL, new OpBehaviorIntLessEqual());
|
||||
opBehaviorMap.put(PcodeOp.INT_ZEXT, new OpBehaviorIntZext());
|
||||
opBehaviorMap.put(PcodeOp.INT_SEXT, new OpBehaviorIntSext());
|
||||
opBehaviorMap.put(PcodeOp.INT_ADD, new OpBehaviorIntAdd());
|
||||
opBehaviorMap.put(PcodeOp.INT_SUB, new OpBehaviorIntSub());
|
||||
opBehaviorMap.put(PcodeOp.INT_CARRY, new OpBehaviorIntCarry());
|
||||
opBehaviorMap.put(PcodeOp.INT_SCARRY, new OpBehaviorIntScarry());
|
||||
opBehaviorMap.put(PcodeOp.INT_SBORROW, new OpBehaviorIntSborrow());
|
||||
opBehaviorMap.put(PcodeOp.INT_2COMP, new OpBehaviorInt2Comp());
|
||||
opBehaviorMap.put(PcodeOp.INT_NEGATE, new OpBehaviorIntNegate());
|
||||
opBehaviorMap.put(PcodeOp.INT_XOR, new OpBehaviorIntXor());
|
||||
opBehaviorMap.put(PcodeOp.INT_AND, new OpBehaviorIntAnd());
|
||||
opBehaviorMap.put(PcodeOp.INT_OR, new OpBehaviorIntOr());
|
||||
opBehaviorMap.put(PcodeOp.INT_LEFT, new OpBehaviorIntLeft());
|
||||
opBehaviorMap.put(PcodeOp.INT_RIGHT, new OpBehaviorIntRight());
|
||||
opBehaviorMap.put(PcodeOp.INT_SRIGHT, new OpBehaviorIntSright());
|
||||
opBehaviorMap.put(PcodeOp.INT_MULT, new OpBehaviorIntMult());
|
||||
opBehaviorMap.put(PcodeOp.INT_DIV, new OpBehaviorIntDiv());
|
||||
opBehaviorMap.put(PcodeOp.INT_SDIV, new OpBehaviorIntSdiv());
|
||||
opBehaviorMap.put(PcodeOp.INT_REM, new OpBehaviorIntRem());
|
||||
opBehaviorMap.put(PcodeOp.INT_SREM, new OpBehaviorIntSrem());
|
||||
|
||||
opBehaviorMap.put(PcodeOp.BOOL_NEGATE, new OpBehaviorBoolNegate());
|
||||
opBehaviorMap.put(PcodeOp.BOOL_XOR, new OpBehaviorBoolXor());
|
||||
opBehaviorMap.put(PcodeOp.BOOL_AND, new OpBehaviorBoolAnd());
|
||||
opBehaviorMap.put(PcodeOp.BOOL_OR, new OpBehaviorBoolOr());
|
||||
|
||||
opBehaviorMap.put(PcodeOp.CAST, new SpecialOpBehavior(PcodeOp.CAST));
|
||||
opBehaviorMap.put(PcodeOp.PTRADD, new SpecialOpBehavior(PcodeOp.PTRADD));
|
||||
opBehaviorMap.put(PcodeOp.PTRSUB, new SpecialOpBehavior(PcodeOp.PTRSUB));
|
||||
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_EQUAL, new OpBehaviorFloatEqual());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_NOTEQUAL, new OpBehaviorFloatNotEqual());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_LESS, new OpBehaviorFloatLess());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_LESSEQUAL, new OpBehaviorFloatLessEqual());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_NAN, new OpBehaviorFloatNan());
|
||||
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_ADD, new OpBehaviorFloatAdd());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_DIV, new OpBehaviorFloatDiv());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_MULT, new OpBehaviorFloatMult());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_SUB, new OpBehaviorFloatSub());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_NEG, new OpBehaviorFloatNeg());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_ABS, new OpBehaviorFloatAbs());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_SQRT, new OpBehaviorFloatSqrt());
|
||||
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_INT2FLOAT, new OpBehaviorFloatInt2Float());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_FLOAT2FLOAT, new OpBehaviorFloatFloat2Float());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_TRUNC, new OpBehaviorFloatTrunc());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_CEIL, new OpBehaviorFloatCeil());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_FLOOR, new OpBehaviorFloatFloor());
|
||||
opBehaviorMap.put(PcodeOp.FLOAT_ROUND, new OpBehaviorFloatRound());
|
||||
opBehaviorMap.put(PcodeOp.SEGMENTOP, new SpecialOpBehavior(PcodeOp.SEGMENTOP));
|
||||
opBehaviorMap.put(PcodeOp.CPOOLREF, new SpecialOpBehavior(PcodeOp.CPOOLREF));
|
||||
opBehaviorMap.put(PcodeOp.NEW, new SpecialOpBehavior(PcodeOp.NEW));
|
||||
opBehaviorMap.put(PcodeOp.INSERT, new SpecialOpBehavior(PcodeOp.INSERT));
|
||||
opBehaviorMap.put(PcodeOp.EXTRACT, new SpecialOpBehavior(PcodeOp.EXTRACT));
|
||||
opBehaviorMap.put(PcodeOp.POPCOUNT, new OpBehaviorPopcount());
|
||||
opBehaviorMap.put(PcodeOp.LZCOUNT, new OpBehaviorLzcount());
|
||||
}
|
||||
|
||||
private OpBehaviorFactory() {
|
||||
}
|
||||
|
||||
public static OpBehavior getOpBehavior(int opcode) {
|
||||
return opBehaviorMap.get(opcode);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatAbs extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatAbs() {
|
||||
super(PcodeOp.FLOAT_ABS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opAbs(in1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opAbs(in1);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatAdd extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatAdd() {
|
||||
super(PcodeOp.FLOAT_ADD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opAdd(in1, in2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opAdd(in1, in2);
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatCeil extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatCeil() {
|
||||
super(PcodeOp.FLOAT_CEIL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opCeil(in1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opCeil(in1);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatDiv extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatDiv() {
|
||||
super(PcodeOp.FLOAT_DIV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opDiv(in1, in2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opDiv(in1, in2);
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatEqual extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatEqual() {
|
||||
super(PcodeOp.FLOAT_EQUAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opEqual(in1, in2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opEqual(in1, in2);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatFloat2Float extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatFloat2Float() {
|
||||
super(PcodeOp.FLOAT_FLOAT2FLOAT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
FloatFormat formatout = FloatFormatFactory.getFloatFormat(sizeout);
|
||||
FloatFormat formatin = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return formatin.opFloat2Float(in1, formatout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
FloatFormat formatout = FloatFormatFactory.getFloatFormat(sizeout);
|
||||
FloatFormat formatin = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return formatin.opFloat2Float(in1, formatout);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatFloor extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatFloor() {
|
||||
super(PcodeOp.FLOAT_FLOOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opFloor(in1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opFloor(in1);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatInt2Float extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatInt2Float() {
|
||||
super(PcodeOp.FLOAT_INT2FLOAT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizeout);
|
||||
return format.opInt2Float(in1, sizein);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizeout);
|
||||
return format.opInt2Float(in1, sizein, true);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatLess extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatLess() {
|
||||
super(PcodeOp.FLOAT_LESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opLess(in1, in2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opLess(in1, in2);
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatLessEqual extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatLessEqual() {
|
||||
super(PcodeOp.FLOAT_LESSEQUAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opLessEqual(in1, in2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opLessEqual(in1, in2);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatMult extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatMult() {
|
||||
super(PcodeOp.FLOAT_MULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opMult(in1, in2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opMult(in1, in2);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatNan extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatNan() {
|
||||
super(PcodeOp.FLOAT_NAN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opNan(in1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opNan(in1);
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatNeg extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatNeg() {
|
||||
super(PcodeOp.FLOAT_NEG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opNeg(in1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opNeg(in1);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatNotEqual extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatNotEqual() {
|
||||
super(PcodeOp.FLOAT_NOTEQUAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opNotEqual(in1, in2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opNotEqual(in1, in2);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatRound extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatRound() {
|
||||
super(PcodeOp.FLOAT_ROUND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opRound(in1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opRound(in1);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatSqrt extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatSqrt() {
|
||||
super(PcodeOp.FLOAT_SQRT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opSqrt(in1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opSqrt(in1);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatSub extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatSub() {
|
||||
super(PcodeOp.FLOAT_SUB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opSub(in1, in2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opSub(in1, in2);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorFloatTrunc extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorFloatTrunc() {
|
||||
super(PcodeOp.FLOAT_TRUNC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opTrunc(in1, sizeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
FloatFormat format = FloatFormatFactory.getFloatFormat(sizein);
|
||||
return format.opTrunc(in1, sizeout);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorInt2Comp extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorInt2Comp() {
|
||||
super(PcodeOp.INT_2COMP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
long res = Utils.uintb_negate(in1 - 1, sizein);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
if (in1.signum() < 0) {
|
||||
throw new AssertException("Expected unsigned in value");
|
||||
}
|
||||
BigInteger res = in1.negate();
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntAdd extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntAdd() {
|
||||
super(PcodeOp.INT_ADD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = (in1 + in2) & Utils.calc_mask(sizeout);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.add(in2);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntAnd extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntAnd() {
|
||||
super(PcodeOp.INT_AND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = in1 & in2;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.and(in2);
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
public class OpBehaviorIntCarry extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntCarry() {
|
||||
super(PcodeOp.INT_CARRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
return (Long.compareUnsigned(in1, (in1 + in2) & Utils.calc_mask(sizein)) > 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
if (in1.signum() < 0 || in2.signum() < 0) {
|
||||
throw new AssertException("Expected unsigned in values");
|
||||
}
|
||||
BigInteger res =
|
||||
(in1.compareTo(in1.add(in2).and(Utils.calc_bigmask(sizein))) > 0) ? BigInteger.ONE
|
||||
: BigInteger.ZERO;
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntDiv extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntDiv() {
|
||||
super(PcodeOp.INT_DIV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
if (sizein <= 0 || in2 == 0)
|
||||
return 0;
|
||||
if (in1 == in2)
|
||||
return 1;
|
||||
if (sizein == 8) {
|
||||
long mask = (0x1<<63);
|
||||
long bit1 = in1 & mask; // Get the sign bits
|
||||
long bit2 = in2 & mask;
|
||||
if (bit1 != 0 || bit2 != 0) {
|
||||
// use BigInteger to perform 64-bit unsigned division if one negative input
|
||||
BigInteger bigIn1 =
|
||||
Utils.bytesToBigInteger(Utils.longToBytes(in1, sizein, true), sizein, true,
|
||||
false);
|
||||
if (bigIn1.signum() < 0) {
|
||||
bigIn1 = Utils.convertToUnsignedValue(bigIn1, sizein);
|
||||
}
|
||||
BigInteger bigIn2 =
|
||||
Utils.bytesToBigInteger(Utils.longToBytes(in2, sizein, true), sizein, true,
|
||||
false);
|
||||
if (bigIn2.signum() < 0) {
|
||||
bigIn2 = Utils.convertToUnsignedValue(bigIn2, sizein);
|
||||
}
|
||||
BigInteger result = bigIn1.divide(bigIn2);
|
||||
return result.longValue() & Utils.calc_mask(sizeout);
|
||||
}
|
||||
}
|
||||
|
||||
return (in1 / in2) & Utils.calc_mask(sizeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
if (sizein <= 0 || in2.signum() == 0)
|
||||
return BigInteger.ZERO;
|
||||
BigInteger res = in1.divide(in2);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntLeft extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntLeft() {
|
||||
super(PcodeOp.INT_LEFT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
if (in2 < 0 || in2 >= (8 * sizein)) {
|
||||
return 0;
|
||||
}
|
||||
return (in1 << in2) & Utils.calc_mask(sizeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
if (in1.signum() < 0 || in2.signum() < 0) {
|
||||
throw new AssertException("Expected unsigned in values");
|
||||
}
|
||||
BigInteger maxShift = BigInteger.valueOf(sizein * 8);
|
||||
if (in2.compareTo(maxShift) >= 0) {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
return in1.shiftLeft(in2.intValue());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntLess extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntLess() {
|
||||
super(PcodeOp.INT_LESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res, mask, bit1, bit2;
|
||||
if (sizein <= 0) {
|
||||
res = 0;
|
||||
}
|
||||
else {
|
||||
mask = Utils.calc_mask(sizein);
|
||||
in1 &= mask;
|
||||
in2 &= mask;
|
||||
if (in1 == in2) {
|
||||
res = 0;
|
||||
}
|
||||
else if (sizein < 8) {
|
||||
res = (in1 < in2) ? 1 : 0;
|
||||
}
|
||||
else {
|
||||
mask = 0x80;
|
||||
mask <<= 8 * (sizein - 1);
|
||||
bit1 = in1 & mask; // Get the sign bits
|
||||
bit2 = in2 & mask;
|
||||
if (bit1 != bit2)
|
||||
res = (bit1 != 0) ? 0 : 1;
|
||||
else
|
||||
res = (in1 < in2) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = (in1.compareTo(in2) < 0) ? BigInteger.ONE : BigInteger.ZERO;
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntLessEqual extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntLessEqual() {
|
||||
super(PcodeOp.INT_LESSEQUAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res, mask, bit1, bit2;
|
||||
if (sizein <= 0) {
|
||||
res = 0;
|
||||
}
|
||||
else {
|
||||
mask = Utils.calc_mask(sizein);
|
||||
in1 &= mask;
|
||||
in2 &= mask;
|
||||
if (in1 == in2) {
|
||||
res = 1;
|
||||
}
|
||||
else if (sizein < 8) {
|
||||
res = (in1 < in2) ? 1 : 0;
|
||||
}
|
||||
else {
|
||||
mask = 0x80;
|
||||
mask <<= 8 * (sizein - 1);
|
||||
bit1 = in1 & mask; // Get the sign bits
|
||||
bit2 = in2 & mask;
|
||||
if (bit1 != bit2)
|
||||
res = (bit1 != 0) ? 0 : 1;
|
||||
else
|
||||
res = (in1 < in2) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = (in1.compareTo(in2) <= 0) ? BigInteger.ONE : BigInteger.ZERO;
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntMult extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntMult() {
|
||||
super(PcodeOp.INT_MULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = (in1 * in2) & Utils.calc_mask(sizeout);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.multiply(in2);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntNegate extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntNegate() {
|
||||
super(PcodeOp.INT_NEGATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
long res = Utils.uintb_negate(in1, sizein);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
if (in1.signum() < 0) {
|
||||
throw new AssertException("Expected unsigned in value");
|
||||
}
|
||||
return in1.not();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntOr extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntOr() {
|
||||
super(PcodeOp.INT_OR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = in1 | in2;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.or(in2);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
public class OpBehaviorIntRem extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntRem() {
|
||||
super(PcodeOp.INT_REM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
if (in2 == 0) {
|
||||
throw new LowlevelError("Remainder by 0");
|
||||
}
|
||||
return Long.remainderUnsigned(in1, in2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
if (in2.signum() == 0) {
|
||||
throw new LowlevelError("Remainder by 0");
|
||||
}
|
||||
BigInteger res = in1.remainder(in2);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntRight extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntRight() {
|
||||
super(PcodeOp.INT_RIGHT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
if (in2 < 0 || in2 >= (8 * sizein)) {
|
||||
return 0;
|
||||
}
|
||||
return (in1 >>> in2) & Utils.calc_mask(sizeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
|
||||
if (in1.signum() < 0 || in2.signum() < 0) {
|
||||
throw new AssertException("Expected unsigned in values");
|
||||
}
|
||||
BigInteger maxShift = BigInteger.valueOf(sizein * 8);
|
||||
if (in2.compareTo(maxShift) >= 0) {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
return in1.shiftRight(in2.intValue());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntSborrow extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntSborrow() {
|
||||
super(PcodeOp.INT_SBORROW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = in1 - in2;
|
||||
|
||||
int a = (int) (in1 >> (sizein * 8 - 1)) & 1; // Grab sign bit
|
||||
int b = (int) (in2 >> (sizein * 8 - 1)) & 1; // Grab sign bit
|
||||
int r = (int) (res >> (sizein * 8 - 1)) & 1; // Grab sign bit
|
||||
|
||||
a ^= r;
|
||||
r ^= b;
|
||||
r ^= 1;
|
||||
a &= r;
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.subtract(in2);
|
||||
|
||||
boolean a = in1.testBit(sizein * 8 - 1); // Grab sign bit
|
||||
boolean b = in2.testBit(sizein * 8 - 1); // Grab sign bit
|
||||
boolean r = res.testBit(sizein * 8 - 1); // Grab sign bit
|
||||
|
||||
a ^= r;
|
||||
r ^= b;
|
||||
r ^= true;
|
||||
a &= r;
|
||||
return a ? BigInteger.ONE : BigInteger.ZERO;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntScarry extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntScarry() {
|
||||
super(PcodeOp.INT_SCARRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = in1 + in2;
|
||||
|
||||
int a = (int) (in1 >> (sizein * 8 - 1)) & 1; // Grab sign bit
|
||||
int b = (int) (in2 >> (sizein * 8 - 1)) & 1; // Grab sign bit
|
||||
int r = (int) (res >> (sizein * 8 - 1)) & 1; // Grab sign bit
|
||||
|
||||
r ^= a;
|
||||
a ^= b;
|
||||
a ^= 1;
|
||||
r &= a;
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.add(in2);
|
||||
|
||||
boolean a = in1.testBit(sizein * 8 - 1); // Grab sign bit
|
||||
boolean b = in2.testBit(sizein * 8 - 1); // Grab sign bit
|
||||
boolean r = res.testBit(sizein * 8 - 1); // Grab sign bit
|
||||
|
||||
r ^= a;
|
||||
a ^= b;
|
||||
a ^= true;
|
||||
r &= a;
|
||||
return r ? BigInteger.ONE : BigInteger.ZERO;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntSdiv extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntSdiv() {
|
||||
super(PcodeOp.INT_SDIV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
if (in2 == 0)
|
||||
throw new LowlevelError("Divide by 0");
|
||||
long num = in1; // Convert to signed
|
||||
long denom = in2;
|
||||
num = Utils.zzz_sign_extend(num, 8 * sizein - 1);
|
||||
denom = Utils.zzz_sign_extend(denom, 8 * sizein - 1);
|
||||
long sres = num / denom; // Do the signed division
|
||||
// Cut to appropriate size
|
||||
sres = Utils.zzz_zero_extend(sres, 8 * sizeout - 1);
|
||||
return sres; // Recast as unsigned
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
if (in2.signum() == 0)
|
||||
throw new LowlevelError("Divide by 0");
|
||||
// convert to signed
|
||||
in1 = Utils.convertToSignedValue(in1, sizein);
|
||||
in2 = Utils.convertToSignedValue(in2, sizein);
|
||||
return in1.divide(in2);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntSext extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntSext() {
|
||||
super(PcodeOp.INT_SEXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
long res = Utils.sign_extend(in1, sizein, sizeout);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
return Utils.convertToSignedValue(in1, sizein);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public long recoverInputUnary(int sizeout, long out, int sizein) {
|
||||
// long masklong = Utils.calc_mask(sizeout);
|
||||
// long maskshort = Utils.calc_mask(sizein);
|
||||
//
|
||||
// if ((out & (maskshort ^ (maskshort >>> 1))) == 0) { // Positive input
|
||||
// if ((out & maskshort) != out)
|
||||
// throw new LowlevelError(
|
||||
// "Output is not in range of sext operation");
|
||||
// } else { // Negative input
|
||||
// if ((out & (masklong ^ maskshort)) != (masklong ^ maskshort))
|
||||
// throw new LowlevelError(
|
||||
// "Output is not in range of sext operation");
|
||||
// }
|
||||
// return (out & maskshort);
|
||||
// }
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntSless extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntSless() {
|
||||
super(PcodeOp.INT_SLESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res, mask, bit1, bit2;
|
||||
|
||||
if (sizein <= 0)
|
||||
res = 0;
|
||||
else {
|
||||
mask = 0x80;
|
||||
mask <<= 8 * (sizein - 1);
|
||||
bit1 = in1 & mask; // Get the sign bits
|
||||
bit2 = in2 & mask;
|
||||
if (bit1 != bit2)
|
||||
res = (bit1 != 0) ? 1 : 0;
|
||||
else
|
||||
res = (in1 < in2) ? 1 : 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
if (sizein <= 0)
|
||||
return BigInteger.ZERO;
|
||||
// convert to signed
|
||||
in1 = Utils.convertToSignedValue(in1, sizein);
|
||||
in2 = Utils.convertToSignedValue(in2, sizein);
|
||||
return (in1.compareTo(in2) < 0) ? BigInteger.ONE : BigInteger.ZERO;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntSlessEqual extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntSlessEqual() {
|
||||
super(PcodeOp.INT_SLESSEQUAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res, mask, bit1, bit2;
|
||||
|
||||
if (sizein <= 0)
|
||||
res = 0;
|
||||
else {
|
||||
mask = 0x80;
|
||||
mask <<= 8 * (sizein - 1);
|
||||
bit1 = in1 & mask; // Get the sign bits
|
||||
bit2 = in2 & mask;
|
||||
if (bit1 != bit2)
|
||||
res = (bit1 != 0) ? 1 : 0;
|
||||
else
|
||||
res = (in1 <= in2) ? 1 : 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
if (sizein <= 0)
|
||||
return BigInteger.ZERO;
|
||||
// convert to signed
|
||||
in1 = Utils.convertToSignedValue(in1, sizein);
|
||||
in2 = Utils.convertToSignedValue(in2, sizein);
|
||||
return (in1.compareTo(in2) <= 0) ? BigInteger.ONE : BigInteger.ZERO;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntSrem extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntSrem() {
|
||||
super(PcodeOp.INT_SREM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
if (in2 == 0)
|
||||
throw new LowlevelError("Remainder by 0");
|
||||
long val = in1;
|
||||
long mod = in2;
|
||||
// Convert inputs to signed values
|
||||
val = Utils.zzz_sign_extend(val, 8 * sizein - 1);
|
||||
mod = Utils.zzz_sign_extend(mod, 8 * sizein - 1);
|
||||
// Do the remainder
|
||||
long sres = val % mod;
|
||||
// Convert back to unsigned
|
||||
sres = Utils.zzz_zero_extend(sres, 8 * sizeout - 1);
|
||||
return sres;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
if (in2.signum() == 0)
|
||||
throw new LowlevelError("Remainder by 0");
|
||||
// convert to signed
|
||||
in1 = Utils.convertToSignedValue(in1, sizein);
|
||||
in2 = Utils.convertToSignedValue(in2, sizein);
|
||||
return in1.remainder(in2);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntSright extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntSright() {
|
||||
super(PcodeOp.INT_SRIGHT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long maxShift = (sizein * 8) - 1;
|
||||
if (in2 < 0 || in2 > maxShift) {
|
||||
if (Utils.signbit_negative(in1, sizein)) {
|
||||
return Utils.calc_mask(sizein);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
long res;
|
||||
if (Utils.signbit_negative(in1, sizein)) {
|
||||
res = in1 >> in2;
|
||||
long mask = Utils.calc_mask(sizein);
|
||||
mask = (mask >>> in2) ^ mask;
|
||||
res |= mask;
|
||||
}
|
||||
else {
|
||||
res = in1 >>> in2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
if (in1.signum() < 0 || in2.signum() < 0) {
|
||||
throw new AssertException("Expected unsigned in values");
|
||||
}
|
||||
int signbit = (sizein * 8) - 1;
|
||||
BigInteger maxShift = BigInteger.valueOf(signbit);
|
||||
if (in2.compareTo(maxShift) > 0) {
|
||||
in2 = maxShift;
|
||||
}
|
||||
if (in1.testBit(signbit)) {
|
||||
in1 = Utils.convertToSignedValue(in1, sizein);
|
||||
}
|
||||
return in1.shiftRight(in2.intValue());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntSub extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntSub() {
|
||||
super(PcodeOp.INT_SUB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = (in1 - in2) & Utils.calc_mask(sizeout);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.subtract(in2);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntXor extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntXor() {
|
||||
super(PcodeOp.INT_XOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = in1 ^ in2;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.xor(in2);
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorIntZext extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorIntZext() {
|
||||
super(PcodeOp.INT_ZEXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long in1) {
|
||||
return in1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger in1) {
|
||||
return in1;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public long recoverInputUnary(int sizeout, long out, int sizein) {
|
||||
// long mask = Utils.calc_mask(sizein);
|
||||
// if ((mask & out) != out)
|
||||
// throw new LowlevelError("Output is not in range of zext operation");
|
||||
// return out;
|
||||
// }
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
public class OpBehaviorLzcount extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorLzcount() {
|
||||
super(PcodeOp.LZCOUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long val) {
|
||||
long mask = 1L << ((sizein * 8) - 1);
|
||||
long count = 0;
|
||||
while (mask != 0) {
|
||||
if ((mask & val) != 0) {
|
||||
break;
|
||||
}
|
||||
++count;
|
||||
mask >>>= 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger unsignedIn1) {
|
||||
int bitcount = 0;
|
||||
sizein = sizein * 8 - 1;
|
||||
while (sizein >= 0) {
|
||||
if (unsignedIn1.testBit(sizein)) {
|
||||
break;
|
||||
}
|
||||
bitcount += 1;
|
||||
sizein -= 1;
|
||||
}
|
||||
if (sizeout == 1) {
|
||||
bitcount &= 0xff;
|
||||
}
|
||||
else if (sizeout == 2) {
|
||||
bitcount &= 0xffff;
|
||||
}
|
||||
return BigInteger.valueOf(bitcount);
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorNotEqual extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorNotEqual() {
|
||||
super(PcodeOp.INT_NOTEQUAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
return in1 != in2 ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
return in1.equals(in2) ? BigInteger.ZERO : BigInteger.ONE;
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorPiece extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorPiece() {
|
||||
super(PcodeOp.PIECE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = (in1 << (sizein * 8)) | in2;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
BigInteger res = in1.shiftLeft(sizein * 8).or(in2);
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
public class OpBehaviorPopcount extends UnaryOpBehavior {
|
||||
|
||||
public OpBehaviorPopcount() {
|
||||
super(PcodeOp.POPCOUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateUnary(int sizeout, int sizein, long val) {
|
||||
val = (val & 0x5555555555555555L) + ((val >>> 1) & 0x5555555555555555L);
|
||||
val = (val & 0x3333333333333333L) + ((val >>> 2) & 0x3333333333333333L);
|
||||
val = (val & 0x0f0f0f0f0f0f0f0fL) + ((val >>> 4) & 0x0f0f0f0f0f0f0f0fL);
|
||||
val = (val & 0x00ff00ff00ff00ffL) + ((val >>> 8) & 0x00ff00ff00ff00ffL);
|
||||
val = (val & 0x0000ffff0000ffffL) + ((val >>> 16) & 0x0000ffff0000ffffL);
|
||||
int res = (int) (val & 0xff);
|
||||
res += (int) ((val >> 32) & 0xff);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger unsignedIn1) {
|
||||
int bitcount = 0;
|
||||
while (sizein >= 8) {
|
||||
bitcount += evaluateUnary(1, 8, unsignedIn1.longValue());
|
||||
sizein -= 8;
|
||||
if (sizein == 0) {
|
||||
break;
|
||||
}
|
||||
unsignedIn1 = unsignedIn1.shiftRight(64);
|
||||
}
|
||||
if (sizein > 0) {
|
||||
long mask = sizein * 8 - 1;
|
||||
bitcount += evaluateUnary(1, 8, unsignedIn1.longValue() & mask);
|
||||
}
|
||||
if (sizeout == 1) {
|
||||
bitcount &= 0xff;
|
||||
}
|
||||
else if (sizeout == 2) {
|
||||
bitcount &= 0xffff;
|
||||
}
|
||||
return BigInteger.valueOf(bitcount);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class OpBehaviorSubpiece extends BinaryOpBehavior {
|
||||
|
||||
public OpBehaviorSubpiece() {
|
||||
super(PcodeOp.SUBPIECE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long evaluateBinary(int sizeout, int sizein, long in1, long in2) {
|
||||
long res = (in1 >>> (in2 * 8)) & Utils.calc_mask(sizeout);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger evaluateBinary(int sizeout, int sizein, BigInteger in1, BigInteger in2) {
|
||||
// must eliminate sign extension bits produced by BigInteger.shiftRight
|
||||
int signbit = (sizein * 8) - 1;
|
||||
BigInteger res = in1;
|
||||
boolean negative = res.testBit(signbit);
|
||||
if (negative) {
|
||||
res = res.and(Utils.calc_bigmask(sizein));
|
||||
res = res.clearBit(signbit);
|
||||
}
|
||||
int shift = in2.intValue() * 8;
|
||||
res = res.shiftRight(shift);
|
||||
signbit -= shift;
|
||||
if (negative && signbit >= 0) {
|
||||
res = res.setBit(signbit); // restore shifted sign bit
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
public class SpecialOpBehavior extends OpBehavior {
|
||||
|
||||
SpecialOpBehavior(int opcode) {
|
||||
super(opcode);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import ghidra.pcode.utils.Utils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public abstract class UnaryOpBehavior extends OpBehavior {
|
||||
|
||||
UnaryOpBehavior(int opcode) {
|
||||
super(opcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the unary operation using long data
|
||||
* @param sizeout intended output size (bytes)
|
||||
* @param sizein in1 size (bytes)
|
||||
* @param unsignedIn1 unsigned input 1
|
||||
* @return operation result. NOTE: if the operation overflows bits may be
|
||||
* set beyond the specified sizeout. Even though results should be treated
|
||||
* as unsigned it may be returned as a signed long value. It is expected that the
|
||||
* returned result always be properly truncated by the caller since the evaluation
|
||||
* may not - this is done to conserve emulation cycles.
|
||||
* @see Utils#longToBytes(long, int, boolean)
|
||||
* @see Utils#bytesToLong(byte[], int, boolean)
|
||||
*/
|
||||
public abstract long evaluateUnary(int sizeout, int sizein, long unsignedIn1);
|
||||
|
||||
/**
|
||||
* Evaluate the unary operation using BigInteger data
|
||||
* @param sizeout intended output size (bytes)
|
||||
* @param sizein in1 size (bytes)
|
||||
* @param unsignedIn1 unsigned input 1
|
||||
* @return operation result. NOTE: if the operation overflows bits may be
|
||||
* set beyond the specified sizeout. Even though results should be treated
|
||||
* as unsigned it may be returned as a signed value. It is expected that the
|
||||
* returned result always be properly truncated by the caller since the evaluation
|
||||
* may not - this is done to conserve emulation cycles.
|
||||
* @see Utils#bigIntegerToBytes(BigInteger, int, boolean)
|
||||
* @see Utils#bytesToBigInteger(byte[], int, boolean, boolean)
|
||||
*/
|
||||
public abstract BigInteger evaluateUnary(int sizeout, int sizein, BigInteger unsignedIn1);
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.pcoderaw;
|
||||
|
||||
import ghidra.pcode.opbehavior.OpBehavior;
|
||||
import ghidra.pcode.opbehavior.OpBehaviorFactory;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
public class PcodeOpRaw extends PcodeOp {
|
||||
|
||||
private OpBehavior behave;
|
||||
|
||||
public PcodeOpRaw(PcodeOp op) {
|
||||
super(op.getSeqnum(), op.getOpcode(), op.getInputs(), op.getOutput());
|
||||
behave = OpBehaviorFactory.getOpBehavior(op.getOpcode());
|
||||
}
|
||||
|
||||
// Get the underlying behavior object for this pcode operation. From this
|
||||
// object you can determine how the object evaluates inputs to get the output
|
||||
// \return the behavior object
|
||||
public OpBehavior getBehavior() {
|
||||
return behave;
|
||||
}
|
||||
|
||||
// This is a convenience function to get the address of the machine instruction
|
||||
// (of which this pcode op is a translation)
|
||||
// \return the machine instruction address
|
||||
public Address getAddress() {
|
||||
return getSeqnum().getTarget();
|
||||
}
|
||||
}
|
|
@ -1,255 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.memstate;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.pcode.memstate.UniqueMemoryBank.WordInfo;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.GenericAddressSpace;
|
||||
import ghidra.program.model.lang.SpaceNames;
|
||||
|
||||
public class UniqueMemoryBankTest extends AbstractGenericTest {
|
||||
|
||||
private AddressSpace uniqueSpace;
|
||||
private UniqueMemoryBank uniqueBank;
|
||||
private byte[] eightTestBytes = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 };
|
||||
private byte[] eightZeroBytes = new byte[8];
|
||||
private byte[] sixteenTestBytes = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
|
||||
0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
uniqueSpace =
|
||||
new GenericAddressSpace(SpaceNames.UNIQUE_SPACE_NAME, 64, AddressSpace.TYPE_UNIQUE, 0);
|
||||
uniqueBank = new UniqueMemoryBank(uniqueSpace, false);
|
||||
}
|
||||
|
||||
public UniqueMemoryBankTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void WordInfoBasicTest() {
|
||||
WordInfo info = new WordInfo();
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x0, 0);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x1, 1);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x2, 2);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x3, 3);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x4, 4);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x5, 5);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x6, 6);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x7, 7);
|
||||
assertTrue(info.isEntireWordInitialized());
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
assertEquals((byte) i, info.getByte(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = LowlevelError.class)
|
||||
public void testGetUninitializedByte() {
|
||||
WordInfo info = new WordInfo();
|
||||
info.setByte((byte) 0, 0);
|
||||
info.setByte((byte) 1, 1);
|
||||
info.setByte((byte) 3, 3);
|
||||
info.setByte((byte) 4, 4);
|
||||
info.setByte((byte) 5, 5);
|
||||
info.setByte((byte) 6, 6);
|
||||
info.setByte((byte) 7, 7);
|
||||
@SuppressWarnings("unused")
|
||||
byte val = info.getByte(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRead() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[8];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(8, numBytes);
|
||||
assertTrue(Arrays.equals(dest, eightTestBytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentlySizedReads() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[4];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 4, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertTrue(Arrays.equals(dest, new byte[] { 0x0, 0x1, 0x2, 0x3 }));
|
||||
numBytes = uniqueBank.getChunk(0x1004, 4, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertTrue(Arrays.equals(dest, new byte[] { 0x4, 0x5, 0x6, 0x7 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLargeReadWrite() {
|
||||
uniqueBank.setChunk(0x1004, 16, sixteenTestBytes);
|
||||
byte[] dest = new byte[16];
|
||||
int numBytes = uniqueBank.getChunk(0x1004, 16, dest, true);
|
||||
assertEquals(16, numBytes);
|
||||
assertTrue(Arrays.equals(dest, sixteenTestBytes));
|
||||
|
||||
byte[] largeSrc = new byte[64];
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
largeSrc[i] = (byte) (i + 1);
|
||||
}
|
||||
uniqueBank.setChunk(0x1007, 64, largeSrc);
|
||||
dest = new byte[64];
|
||||
numBytes = uniqueBank.getChunk(0x1007, 64, dest, true);
|
||||
assertEquals(64, numBytes);
|
||||
assertTrue(Arrays.equals(dest, largeSrc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAcrossUndefined() {
|
||||
byte[] fourBytes = new byte[] { 0x11, 0x22, 0x33, 0x44 };
|
||||
uniqueBank.setChunk(0x1007, 4, fourBytes);
|
||||
uniqueBank.setChunk(0x100c, 4, fourBytes);
|
||||
byte[] dest = new byte[9];
|
||||
int numBytes = uniqueBank.getChunk(0x1007, 9, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertEquals(0x11, dest[0]);
|
||||
assertEquals(0x22, dest[1]);
|
||||
assertEquals(0x33, dest[2]);
|
||||
assertEquals(0x44, dest[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonAlignedReadWrite() {
|
||||
byte[] fourBytes = new byte[] { 0x11, 0x22, 0x33, 0x44 };
|
||||
uniqueBank.setChunk(0x1004, 4, fourBytes);
|
||||
byte[] dest = new byte[4];
|
||||
int numBytes = uniqueBank.getChunk(0x1004, 4, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertTrue(Arrays.equals(fourBytes, dest));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlappingReadWrite() {
|
||||
uniqueBank.setChunk(0x1000, 16, sixteenTestBytes);
|
||||
uniqueBank.setChunk(0x1004, 8, eightZeroBytes);
|
||||
byte[] dest = new byte[16];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 16, dest, true);
|
||||
assertEquals(16, numBytes);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (i > 3 && i < 12) {
|
||||
assertEquals(0, dest[i]);
|
||||
}
|
||||
else {
|
||||
assertEquals(i, dest[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneByteRead() {
|
||||
byte[] one = new byte[] { (byte) 0x7f };
|
||||
uniqueBank.setChunk(0x1000, 1, one);
|
||||
byte[] dest = new byte[16];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 1, dest, false);
|
||||
assertEquals(1, numBytes);
|
||||
assertEquals(dest[0], (byte) 0x7f);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[8];
|
||||
uniqueBank.clear();
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 7, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 6, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 5, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 4, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 3, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 2, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 1, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 0, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOverwrite() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[8];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(8, numBytes);
|
||||
assertTrue(Arrays.equals(dest, eightTestBytes));
|
||||
uniqueBank.setChunk(0x1000, 8, eightZeroBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(8, numBytes);
|
||||
assertTrue(Arrays.equals(dest, eightZeroBytes));
|
||||
}
|
||||
|
||||
@Test(expected = LowlevelError.class)
|
||||
public void testUninitializedReadStop() {
|
||||
byte[] dest = new byte[16];
|
||||
uniqueBank.getChunk(0x1000, 0x10, dest, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUninitializedReadContinue() {
|
||||
byte[] dest = new byte[16];
|
||||
int bytesRead = uniqueBank.getChunk(0x1000, 0x10, dest, true);
|
||||
assertEquals(0, bytesRead);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testGetPageException() {
|
||||
MemoryPage page = uniqueBank.getPage(0);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testSetPageException() {
|
||||
uniqueBank.setPage(0, new byte[0], 0, 4096, 0);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testSetPageInitializedException() {
|
||||
uniqueBank.setPageInitialized(0, true, 0, 4096, 0);
|
||||
}
|
||||
|
||||
//possibly add:
|
||||
//zero-byte read/write
|
||||
//try to write more bytes than the array has
|
||||
//try to read more bytes into the array than it has
|
||||
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.util.StringUtilities;
|
||||
|
||||
public abstract class AbstractOpBehaviorTest extends AbstractGenericTest {
|
||||
|
||||
public AbstractOpBehaviorTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected void assertEquals(BigInteger expected, BigInteger result, int byteSize) {
|
||||
// discards irrelevant bytes before comparing - ignores overflow bytes
|
||||
byte[] resultBytes = Utils.bigIntegerToBytes(result, byteSize, true);
|
||||
byte[] expectedBytes = Utils.bigIntegerToBytes(expected, byteSize, true);
|
||||
org.junit.Assert.assertEquals(toHexString(expectedBytes), toHexString(resultBytes));
|
||||
}
|
||||
|
||||
protected void assertEquals(long expected, long result, int byteSize) {
|
||||
// discards irrelevant bytes before comparing - ignores overflow bytes
|
||||
byte[] resultBytes = Utils.longToBytes(result, byteSize, true);
|
||||
byte[] expectedBytes = Utils.longToBytes(expected, byteSize, true);
|
||||
org.junit.Assert.assertEquals(toHexString(expectedBytes), toHexString(resultBytes));
|
||||
}
|
||||
|
||||
private String toHexString(byte[] bytes) {
|
||||
StringBuilder buf = new StringBuilder("0x");
|
||||
for (byte b : bytes) {
|
||||
String valStr = StringUtilities.pad(Integer.toHexString(b & 0xff), '0', 2);
|
||||
buf.append(valStr);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected BigInteger getUnsignedBigInt(long val) {
|
||||
if (val > 0) {
|
||||
return BigInteger.valueOf(val);
|
||||
}
|
||||
return new BigInteger(1, Utils.longToBytes(val, 8, true));
|
||||
}
|
||||
|
||||
protected BigInteger getUnsignedBigInt(long val, int size) {
|
||||
if (val > 0) {
|
||||
return BigInteger.valueOf(val);
|
||||
}
|
||||
return new BigInteger(1, Utils.longToBytes(val, size, true));
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class OpBehaviorBoolAndTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorBoolAndTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorBoolOr op = new OpBehaviorBoolOr();
|
||||
|
||||
Assert.assertEquals(0, op.evaluateBinary(1, 1, 0, 0));
|
||||
Assert.assertEquals(1, op.evaluateBinary(1, 1, 0, 1));
|
||||
Assert.assertEquals(1, op.evaluateBinary(1, 1, 1, 0));
|
||||
Assert.assertEquals(1, op.evaluateBinary(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorBoolOr op = new OpBehaviorBoolOr();
|
||||
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(1, 1, BigInteger.ZERO, BigInteger.ZERO));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(1, 1, BigInteger.ZERO, BigInteger.ONE));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(1, 1, BigInteger.ONE, BigInteger.ZERO));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(1, 1, BigInteger.ONE, BigInteger.ONE));
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class OpBehaviorBoolNegateTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorBoolNegateTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorBoolNegate op = new OpBehaviorBoolNegate();
|
||||
|
||||
Assert.assertEquals(1, op.evaluateUnary(1, 1, 0));
|
||||
Assert.assertEquals(0, op.evaluateUnary(1, 1, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorBoolNegate op = new OpBehaviorBoolNegate();
|
||||
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateUnary(1, 1, BigInteger.ZERO));
|
||||
Assert.assertEquals(BigInteger.ZERO, op.evaluateUnary(1, 1, BigInteger.ONE));
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class OpBehaviorBoolOrTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorBoolOrTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorBoolOr op = new OpBehaviorBoolOr();
|
||||
|
||||
Assert.assertEquals(0, op.evaluateBinary(1, 1, 0, 0));
|
||||
Assert.assertEquals(1, op.evaluateBinary(1, 1, 0, 1));
|
||||
Assert.assertEquals(1, op.evaluateBinary(1, 1, 1, 0));
|
||||
Assert.assertEquals(1, op.evaluateBinary(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorBoolOr op = new OpBehaviorBoolOr();
|
||||
|
||||
Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(1, 1, BigInteger.ZERO, BigInteger.ZERO));
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(1, 1, BigInteger.ZERO, BigInteger.ONE));
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(1, 1, BigInteger.ONE, BigInteger.ZERO));
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(1, 1, BigInteger.ONE, BigInteger.ONE));
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class OpBehaviorBoolXorTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorBoolXorTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorBoolXor op = new OpBehaviorBoolXor();
|
||||
|
||||
Assert.assertEquals(0, op.evaluateBinary(1, 1, 0, 0));
|
||||
Assert.assertEquals(1, op.evaluateBinary(1, 1, 0, 1));
|
||||
Assert.assertEquals(1, op.evaluateBinary(1, 1, 1, 0));
|
||||
Assert.assertEquals(0, op.evaluateBinary(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorBoolXor op = new OpBehaviorBoolXor();
|
||||
|
||||
Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(1, 1, BigInteger.ZERO, BigInteger.ZERO));
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(1, 1, BigInteger.ZERO, BigInteger.ONE));
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(1, 1, BigInteger.ONE, BigInteger.ZERO));
|
||||
Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(1, 1, BigInteger.ONE, BigInteger.ONE));
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
|
||||
public class OpBehaviorFloatAbsTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorFloatAbsTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorFloatAbs op = new OpBehaviorFloatAbs();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
long a = ff.getEncoding(2.5);
|
||||
long result = op.evaluateUnary(8, 8, ff.opAbs(a));
|
||||
Assert.assertEquals(2.5, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(-2.5);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(2.5, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.POSITIVE_INFINITY);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.NEGATIVE_INFINITY);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.NaN);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorFloatAbs op = new OpBehaviorFloatAbs();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d));
|
||||
BigInteger result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getEncoding(ff.getBigFloat(-2.5d));
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigInfinityEncoding(false);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigInfinityEncoding(true);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigNaNEncoding(false);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
|
||||
public class OpBehaviorFloatAddTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorFloatAddTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorFloatAdd op = new OpBehaviorFloatAdd();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
long a = ff.getEncoding(1.234);
|
||||
long b = ff.getEncoding(1.123);
|
||||
long result = op.evaluateBinary(8, 8, a, b);// 1.234 + 1.123
|
||||
Assert.assertEquals(2.357, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(-1.123);
|
||||
result = op.evaluateBinary(8, 8, a, b);// -1.123 + 1.123
|
||||
Assert.assertEquals(0d, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.POSITIVE_INFINITY);
|
||||
result = op.evaluateBinary(8, 8, a, b);// +INFINITY + 1.123
|
||||
Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.NEGATIVE_INFINITY);
|
||||
result = op.evaluateBinary(8, 8, a, b);// -INFINITY + 1.123
|
||||
Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
b = ff.getEncoding(Double.NEGATIVE_INFINITY);
|
||||
result = op.evaluateBinary(8, 8, a, b);// -INFINITY + -INFINITY
|
||||
Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
b = ff.getEncoding(Double.POSITIVE_INFINITY);
|
||||
result = op.evaluateBinary(8, 8, a, b);// -INFINITY + +INFINITY
|
||||
Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.NaN);
|
||||
b = ff.getEncoding(1.123);
|
||||
result = op.evaluateBinary(8, 8, a, b);// NaN + 1.123
|
||||
Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorFloatAdd op = new OpBehaviorFloatAdd();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
BigInteger a = ff.getEncoding(ff.getBigFloat(1.234d));
|
||||
BigInteger b = ff.getEncoding(ff.getBigFloat(1.123d));
|
||||
BigInteger result = op.evaluateBinary(8, 8, a, b);// 1.234 + 1.123
|
||||
Assert.assertEquals(ff.getBigFloat(2.357), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getEncoding(ff.getBigFloat(-1.123d));
|
||||
result = op.evaluateBinary(8, 8, a, b);// -1.123 + 1.123
|
||||
Assert.assertEquals(ff.getBigZero(false), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getEncoding(ff.getBigInfinity(false));
|
||||
result = op.evaluateBinary(8, 8, a, b);// +INFINITY + 1.123
|
||||
Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigInfinityEncoding(true);
|
||||
result = op.evaluateBinary(8, 8, a, b);// -INFINITY + 1.123
|
||||
Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result));
|
||||
|
||||
b = ff.getBigInfinityEncoding(true);
|
||||
result = op.evaluateBinary(8, 8, a, b);// -INFINITY + -INFINITY
|
||||
Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result));
|
||||
|
||||
b = ff.getEncoding(ff.getBigInfinity(false));
|
||||
result = op.evaluateBinary(8, 8, a, b);// -INFINITY + +INFINITY
|
||||
Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigNaNEncoding(false);
|
||||
b = ff.getEncoding(ff.getBigFloat(1.123d));
|
||||
result = op.evaluateBinary(8, 8, a, b);// NaN + 1.123
|
||||
Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
|
||||
public class OpBehaviorFloatCeilTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorFloatCeilTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorFloatCeil op = new OpBehaviorFloatCeil();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
long a = ff.getEncoding(2.5);
|
||||
long result = ff.opCeil(a);
|
||||
Assert.assertEquals(3.0, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(-2.5);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(-2.0, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.POSITIVE_INFINITY);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.NEGATIVE_INFINITY);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.NaN);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorFloatCeil op = new OpBehaviorFloatCeil();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d));
|
||||
BigInteger result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getEncoding(ff.getBigFloat(-2.5d));
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigInfinityEncoding(false);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigInfinityEncoding(true);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigNaNEncoding(false);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
|
||||
public class OpBehaviorFloatDivTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorFloatDivTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorFloatDiv op = new OpBehaviorFloatDiv();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
long a = ff.getEncoding(3.75);
|
||||
long b = ff.getEncoding(1.5);
|
||||
long result = ff.opDiv(a, b);
|
||||
Assert.assertEquals(2.5, ff.getHostFloat(result), 0);
|
||||
|
||||
b = ff.getEncoding(0);
|
||||
result = op.evaluateBinary(8, 8, a, b);
|
||||
Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(-3.75);
|
||||
result = op.evaluateBinary(8, 8, a, b);
|
||||
Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
b = ff.getEncoding(Double.NaN);
|
||||
result = op.evaluateBinary(8, 8, a, b);
|
||||
Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorFloatDiv op = new OpBehaviorFloatDiv();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
BigInteger a = ff.getEncoding(ff.getBigFloat(3.75d));
|
||||
BigInteger b = ff.getEncoding(ff.getBigFloat(1.5d));
|
||||
BigInteger result = op.evaluateBinary(8, 8, a, b);
|
||||
Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result));
|
||||
|
||||
b = ff.getBigZeroEncoding(false);
|
||||
result = op.evaluateBinary(8, 8, a, b);
|
||||
Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getEncoding(ff.getBigFloat(-3.75d));
|
||||
result = op.evaluateBinary(8, 8, a, b);
|
||||
Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result));
|
||||
|
||||
b = ff.getBigNaNEncoding(false);
|
||||
result = op.evaluateBinary(8, 8, a, b);
|
||||
Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.pcode.floatformat.*;
|
||||
|
||||
public class OpBehaviorFloatEqualTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorFloatEqualTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorFloatEqual op = new OpBehaviorFloatEqual();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
Assert.assertEquals(1,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(1.234)));
|
||||
Assert.assertEquals(1,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234)));
|
||||
Assert.assertEquals(0,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234)));
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY),
|
||||
ff.getEncoding(Double.POSITIVE_INFINITY)));
|
||||
Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY),
|
||||
ff.getEncoding(Double.NEGATIVE_INFINITY)));
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY),
|
||||
ff.getEncoding(Double.NEGATIVE_INFINITY)));
|
||||
Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY),
|
||||
ff.getEncoding(Double.NaN)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorFloatEqual op = new OpBehaviorFloatEqual();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
BigFloat a = ff.getBigFloat(1.234d);
|
||||
BigFloat b = ff.getBigFloat(-1.234d);
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(a)));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(b)));
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(a)));
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8,
|
||||
ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false)));
|
||||
Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(8, 8,
|
||||
ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(true)));
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(true),
|
||||
ff.getBigInfinityEncoding(true)));
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(false), ff.getBigNaNEncoding(false)));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
|
||||
public class OpBehaviorFloatFloat2FloatTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorFloatFloat2FloatTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorFloatFloat2Float op = new OpBehaviorFloatFloat2Float();
|
||||
|
||||
FloatFormat ff8 = FloatFormatFactory.getFloatFormat(8);
|
||||
FloatFormat ff4 = FloatFormatFactory.getFloatFormat(4);
|
||||
|
||||
long a = ff4.getEncoding(1.75);
|
||||
long result = op.evaluateUnary(8, 4, a);
|
||||
Assert.assertEquals(1.75, ff8.getHostFloat(result), 0);
|
||||
|
||||
a = ff4.getEncoding(-1.75);
|
||||
result = op.evaluateUnary(8, 4, a);
|
||||
Assert.assertEquals(-1.75, ff8.getHostFloat(result), 0);
|
||||
|
||||
a = ff4.getEncoding(Float.POSITIVE_INFINITY);
|
||||
result = op.evaluateUnary(8, 4, a);
|
||||
Assert.assertEquals(Double.POSITIVE_INFINITY, ff8.getHostFloat(result), 0);
|
||||
|
||||
a = ff4.getEncoding(Float.NEGATIVE_INFINITY);
|
||||
result = op.evaluateUnary(8, 4, a);
|
||||
Assert.assertEquals(Double.NEGATIVE_INFINITY, ff8.getHostFloat(result), 0);
|
||||
|
||||
a = ff4.getEncoding(Float.NaN);
|
||||
result = op.evaluateUnary(8, 4, a);
|
||||
Assert.assertEquals(Double.NaN, ff8.getHostFloat(result), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorFloatFloat2Float op = new OpBehaviorFloatFloat2Float();
|
||||
|
||||
FloatFormat ff8 = FloatFormatFactory.getFloatFormat(8);
|
||||
FloatFormat ff4 = FloatFormatFactory.getFloatFormat(4);
|
||||
|
||||
BigInteger a = ff4.getEncoding(ff4.getBigFloat(1.75d));
|
||||
BigInteger result = op.evaluateUnary(8, 4, a);
|
||||
Assert.assertEquals(ff8.getBigFloat(1.75d), ff8.getHostFloat(result));
|
||||
|
||||
a = ff4.getEncoding(ff4.getBigFloat(-1.75d));
|
||||
result = op.evaluateUnary(8, 4, a);
|
||||
Assert.assertEquals(ff8.getBigFloat(-1.75d), ff8.getHostFloat(result));
|
||||
|
||||
a = ff4.getEncoding(ff4.getBigInfinity(false));
|
||||
result = op.evaluateUnary(8, 4, a);
|
||||
Assert.assertEquals(ff8.getBigInfinity(false), ff8.getHostFloat(result));
|
||||
|
||||
a = ff4.getEncoding(ff4.getBigInfinity(true));
|
||||
result = op.evaluateUnary(8, 4, a);
|
||||
Assert.assertEquals(ff8.getBigInfinity(true), ff8.getHostFloat(result));
|
||||
|
||||
a = ff4.getEncoding(ff4.getBigNaN(false));
|
||||
result = op.evaluateUnary(8, 4, a);
|
||||
Assert.assertEquals(ff8.getBigNaN(false), ff8.getHostFloat(result));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
|
||||
public class OpBehaviorFloatFloorTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorFloatFloorTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorFloatFloor op = new OpBehaviorFloatFloor();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
long a = ff.getEncoding(2.5);
|
||||
long result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(2.0, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(-2.0);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(-2.0, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(-2.5);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(-3.0, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.POSITIVE_INFINITY);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.NEGATIVE_INFINITY);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0);
|
||||
|
||||
a = ff.getEncoding(Double.NaN);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorFloatFloor op = new OpBehaviorFloatFloor();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d));
|
||||
BigInteger result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getEncoding(ff.getBigFloat(-2.0d));
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getEncoding(ff.getBigFloat(-2.5d));
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigFloat(-3.0d), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigInfinityEncoding(false);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigInfinityEncoding(true);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result));
|
||||
|
||||
a = ff.getBigNaNEncoding(false);
|
||||
result = op.evaluateUnary(8, 8, a);
|
||||
Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.pcode.floatformat.FloatFormatFactory;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
|
||||
public class OpBehaviorFloatInt2FloatTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorFloatInt2FloatTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorFloatInt2Float op = new OpBehaviorFloatInt2Float();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(4);
|
||||
|
||||
long result = op.evaluateUnary(4, 4, 2);
|
||||
Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used
|
||||
Assert.assertEquals(2.0d, ff.getHostFloat(result), 0);
|
||||
|
||||
result = op.evaluateUnary(4, 4, -2);
|
||||
Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used
|
||||
Assert.assertEquals(-2.0d, ff.getHostFloat(result), 0);
|
||||
|
||||
result = op.evaluateUnary(4, 4, 0);
|
||||
Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used
|
||||
Assert.assertEquals(0d, ff.getHostFloat(result), 0);
|
||||
|
||||
result = op.evaluateUnary(4, 4, 0x0ffffffffL);
|
||||
Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used
|
||||
Assert.assertEquals(-1.0d, ff.getHostFloat(result), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorFloatInt2Float op = new OpBehaviorFloatInt2Float();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(4);
|
||||
|
||||
BigInteger limit = BigInteger.ONE.shiftLeft(32);
|
||||
|
||||
BigInteger result = op.evaluateUnary(4, 4, BigInteger.valueOf(2));
|
||||
assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used
|
||||
Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result));
|
||||
|
||||
result = op.evaluateUnary(4, 4, BigInteger.valueOf(-2));
|
||||
assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used
|
||||
Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result));
|
||||
|
||||
result = op.evaluateUnary(4, 4, BigInteger.ZERO);
|
||||
assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used
|
||||
Assert.assertEquals(ff.getBigZero(false), ff.getHostFloat(result));
|
||||
|
||||
BigInteger NEG_ONE = Utils.bytesToBigInteger(
|
||||
new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 4, false, false);
|
||||
result = op.evaluateUnary(4, 4, NEG_ONE);
|
||||
Assert.assertEquals(ff.getBigFloat(-1.0d), ff.getHostFloat(result));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.pcode.floatformat.*;
|
||||
|
||||
public class OpBehaviorFloatLessEqualTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorFloatLessEqualTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorFloatLessEqual op = new OpBehaviorFloatLessEqual();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
Assert.assertEquals(1,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(1.234)));
|
||||
Assert.assertEquals(1,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234)));
|
||||
|
||||
Assert.assertEquals(0,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(-1.234)));
|
||||
Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(0), ff.getEncoding(-1.234)));
|
||||
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(0), ff.getEncoding(1.234)));
|
||||
Assert.assertEquals(1,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234)));
|
||||
|
||||
Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY),
|
||||
ff.getEncoding(1.234)));
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY),
|
||||
ff.getEncoding(1.234)));
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(1.234),
|
||||
ff.getEncoding(Double.POSITIVE_INFINITY)));
|
||||
Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(1.234),
|
||||
ff.getEncoding(Double.NEGATIVE_INFINITY)));
|
||||
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY),
|
||||
ff.getEncoding(Double.POSITIVE_INFINITY)));
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY),
|
||||
ff.getEncoding(Double.POSITIVE_INFINITY)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorFloatLessEqual op = new OpBehaviorFloatLessEqual();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
BigFloat a = ff.getBigFloat(1.234d);
|
||||
BigFloat b = ff.getBigFloat(-1.234d);
|
||||
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(a)));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(b)));
|
||||
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(b)));
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getBigZeroEncoding(false), ff.getEncoding(b)));
|
||||
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getBigZeroEncoding(false), ff.getEncoding(a)));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(a)));
|
||||
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(false), ff.getEncoding(a)));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(true), ff.getEncoding(a)));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getBigInfinityEncoding(false)));
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getBigInfinityEncoding(true)));
|
||||
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8,
|
||||
ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false)));
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(true),
|
||||
ff.getBigInfinityEncoding(false)));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.opbehavior;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.pcode.floatformat.*;
|
||||
|
||||
public class OpBehaviorFloatLessTest extends AbstractOpBehaviorTest {
|
||||
|
||||
public OpBehaviorFloatLessTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryLong() {
|
||||
|
||||
OpBehaviorFloatLess op = new OpBehaviorFloatLess();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
Assert.assertEquals(0,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(1.234)));
|
||||
Assert.assertEquals(0,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(-1.234)));
|
||||
Assert.assertEquals(0,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(1.234), ff.getEncoding(-1.234)));
|
||||
Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(0), ff.getEncoding(-1.234)));
|
||||
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(0), ff.getEncoding(1.234)));
|
||||
Assert.assertEquals(1,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(-1.234), ff.getEncoding(1.234)));
|
||||
|
||||
Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY),
|
||||
ff.getEncoding(1.234)));
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY),
|
||||
ff.getEncoding(1.234)));
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(1.234),
|
||||
ff.getEncoding(Double.POSITIVE_INFINITY)));
|
||||
Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(1.234),
|
||||
ff.getEncoding(Double.NEGATIVE_INFINITY)));
|
||||
|
||||
Assert.assertEquals(0, op.evaluateBinary(8, 8, ff.getEncoding(Double.POSITIVE_INFINITY),
|
||||
ff.getEncoding(Double.POSITIVE_INFINITY)));
|
||||
Assert.assertEquals(1, op.evaluateBinary(8, 8, ff.getEncoding(Double.NEGATIVE_INFINITY),
|
||||
ff.getEncoding(Double.POSITIVE_INFINITY)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateBinaryBigInteger() {
|
||||
|
||||
OpBehaviorFloatLess op = new OpBehaviorFloatLess();
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
BigFloat a = ff.getBigFloat(1.234d);
|
||||
BigFloat b = ff.getBigFloat(-1.234d);
|
||||
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(a)));
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(b)));
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getEncoding(b)));
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getBigZeroEncoding(false), ff.getEncoding(b)));
|
||||
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getBigZeroEncoding(false), ff.getEncoding(a)));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(b), ff.getEncoding(a)));
|
||||
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(false), ff.getEncoding(a)));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(true), ff.getEncoding(a)));
|
||||
Assert.assertEquals(BigInteger.ONE,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getBigInfinityEncoding(false)));
|
||||
Assert.assertEquals(BigInteger.ZERO,
|
||||
op.evaluateBinary(8, 8, ff.getEncoding(a), ff.getBigInfinityEncoding(true)));
|
||||
|
||||
Assert.assertEquals(BigInteger.ZERO, op.evaluateBinary(8, 8,
|
||||
ff.getBigInfinityEncoding(false), ff.getBigInfinityEncoding(false)));
|
||||
Assert.assertEquals(BigInteger.ONE, op.evaluateBinary(8, 8, ff.getBigInfinityEncoding(true),
|
||||
ff.getBigInfinityEncoding(false)));
|
||||
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue