Package ghidra.pcode.exec

# Interface PcodeArithmetic<T>

Type Parameters:
  `T` - the type of values operated on

All Known Implementing Classes:
  `AddressesReadPcodeArithmetic`, `BytesPcodeArithmetic`, `LocationPcodeArithmetic`, `PairedPcodeArithmetic`

public interface PcodeArithmetic<T>
An interface that defines arithmetic p-code operations on values of type `T`.

See `BytesPcodeArithmetic` for the typical pattern when implementing an arithmetic. There are generally two cases: 1) Where endianness matters, 2) Where endianness does not matter. The first is typical. The implementation should be an `Enum` with two constants, one for the big endian implementation, and one for the little endian implementation. The class should also provide static methods: `forEndian(boolean isBigEndian)` for getting the correct one based on endianness, and `forLanguage(Language language)` for getting the correct one given a language. If endianness does not matter, then the implementation should follow a singleton pattern. See notes on `getEndian()` for the endian-agnostic case.

- ## Nested Class Summary

  Nested Classes
  Modifier and Type
  Interface
  Description
  `static enum`
  `PcodeArithmetic.Purpose`
  Reasons for requiring a concrete value

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `static final int`
  `SIZEOF_SIZEOF`
  The number of bytes needed to encode the size (in bytes) of any value

- ## Method Summary

  Modifier and Type
  Method
  Description
  `T`
  `binaryOp(int opcode, int sizeout, int sizein1, T in1, int sizein2, T in2)`
  Apply a binary operator to the given inputs
  `default T`
  `binaryOp(PcodeOp op, T in1, T in2)`
  Apply a binary operator to the given input
  `T`
  `fromConst(byte[] value)`
  Convert the given constant concrete value to type `T` having the same size.
  `default T`
  `fromConst(long value, int size)`
  Convert the given constant concrete value to type `T` having the given size.
  `default T`
  `fromConst(BigInteger value, int size)`
  Convert the given constant concrete value to type `T` having the given size.
  `default T`
  `fromConst(BigInteger value, int size, boolean isContextreg)`
  Convert the given constant concrete value to type `T` having the given size.
  `Endian`
  `getEndian()`
  Get the endianness of this arithmetic
  `default boolean`
  `isTrue(T cond, PcodeArithmetic.Purpose purpose)`
  Convert, if possible, the given abstract condition to a concrete boolean value
  `T`
  `modAfterLoad(int sizeout, int sizeinAddress, T inAddress, int sizeinValue, T inValue)`
  Apply any modifications after a value is loaded
  `T`
  `modBeforeStore(int sizeout, int sizeinAddress, T inAddress, int sizeinValue, T inValue)`
  Apply any modifications before a value is stored
  `default T`
  `ptrAdd(int sizeout, int sizeinBase, T inBase, int sizeinIndex, T inIndex, int inSize)`
  Apply the `PcodeOp.PTRADD` operator to the given inputs
  `default T`
  `ptrSub(int sizeout, int sizeinBase, T inBase, int sizeinOffset, T inOffset)`
  Apply the `PcodeOp.PTRSUB` operator to the given inputs
  `long`
  `sizeOf(T value)`
  Get the size in bytes, if possible, of the given abstract value
  `default T`
  `sizeOfAbstract(T value)`
  Get the size in bytes, if possible, of the given abstract value, as an abstract value
  `default BigInteger`
  `toBigInteger(T value, PcodeArithmetic.Purpose purpose)`
  Convert, if possible, the given abstract value to a concrete big integer
  `byte[]`
  `toConcrete(T value, PcodeArithmetic.Purpose purpose)`
  Convert, if possible, the given abstract value to a concrete byte array
  `default long`
  `toLong(T value, PcodeArithmetic.Purpose purpose)`
  Convert, if possible, the given abstract value to a concrete long
  `T`
  `unaryOp(int opcode, int sizeout, int sizein1, T in1)`
  Apply a unary operator to the given input
  `default T`
  `unaryOp(PcodeOp op, T in1)`
  Apply a unary operator to the given input

- ## Field Details

  - ### SIZEOF_SIZEOF

    static final int SIZEOF_SIZEOF
    The number of bytes needed to encode the size (in bytes) of any value
    See Also:
      - Constant Field Values

- ## Method Details

  - ### getEndian

    Endian getEndian()
    Get the endianness of this arithmetic

    Often T is a byte array, or at least represents one abstractly. Ideally, it is an array where each element is an abstraction of a byte. If that is the case, then the arithmetic likely has to interpret those bytes as integral values according to an endianness. This should return that endianness.

    If the abstraction has no notion of endianness, return null. In that case, the both `fromConst(BigInteger, int, boolean)` and `fromConst(long, int)` must be overridden. Furthermore, unless `toConcrete(Object, Purpose)` is guaranteed to throw an exception, then `toBigInteger(Object, Purpose)` and `toLong(Object, Purpose)` must also be overridden.

    Returns:
      the endianness or null

  - ### unaryOp

    T unaryOp(int opcode, int sizeout, int sizein1, T in1)
    Apply a unary operator to the given input

    Note the sizes of variables are given, because values don't necessarily have an intrinsic size. For example, a `BigInteger` may have a minimum encoding size, but that does not necessarily reflect the size of the variable from which is was read.

    Parameters:
      `opcode` - the p-code opcode
      `sizeout` - the size (in bytes) of the output variable
      `sizein1` - the size (in bytes) of the input variable
      `in1` - the input value
    Returns:
      the output value

  - ### unaryOp

    default T unaryOp(PcodeOp op, T in1)
    Apply a unary operator to the given input

    This provides the full p-code op, allowing deeper inspection of the code. For example, an arithmetic may wish to distinguish immediate (constant) values from variables. By default, this unpacks the details and defers to `unaryOp(int, int, int, Object)`.

    Parameters:
      `op` - the operation
      `in1` - the input value
    Returns:
      the output value

  - ### binaryOp

    T binaryOp(int opcode, int sizeout, int sizein1, T in1, int sizein2, T in2)
    Apply a binary operator to the given inputs

    Note the sizes of variables are given, because values don't necessarily have an intrinsic size. For example, a `BigInteger` may have a minimum encoding size, but that does not necessarily reflect the size of the variable from which is was read.

    Parameters:
      `opcode` - the operation's opcode. See `PcodeOp`.
      `sizeout` - the size (in bytes) of the output variable
      `sizein1` - the size (in bytes) of the first (left) input variable
      `in1` - the first (left) input value
      `sizein2` - the size (in bytes) of the second (right) input variable
      `in2` - the second (right) input value
    Returns:
      the output value

  - ### binaryOp

    default T binaryOp(PcodeOp op, T in1, T in2)
    Apply a binary operator to the given input

    This provides the full p-code op, allowing deeper inspection of the code. For example, an arithmetic may wish to distinguish immediate (constant) values from variables. By default, this unpacks the details and defers to `binaryOp(int, int, int, Object, int, Object)`.

    Parameters:
      `op` - the operation
      `in1` - the first (left) input value
      `in2` - the second (right) input value
    Returns:
      the output value

  - ### ptrAdd

    default T ptrAdd(int sizeout, int sizeinBase, T inBase, int sizeinIndex, T inIndex, int inSize)
    Apply the `PcodeOp.PTRADD` operator to the given inputs

    The "pointer add" op takes three operands: base, index, size; and is used as a more compact representation of array index address computation. The `size` operand must be constant. Suppose `arr` is an array whose elements are `size` bytes each, and the address of its first element is `base`. The decompiler would likely render the `PcodeOp.PTRADD` op as `&arr[index]`. An equivalent SLEIGH expression is `base + index*size`.

    NOTE: This op is always a result of decompiler simplification, not low p-code generation, and so are not ordinarily used by a `PcodeExecutor`.

    Parameters:
      `sizeout` - the size (in bytes) of the output variable
      `sizeinBase` - the size (in bytes) of the variable used for the array's base address
      `inBase` - the value used as the array's base address
      `sizeinIndex` - the size (in bytes) of the variable used for the index
      `inIndex` - the value used as the index
      `inSize` - the size of each array element in bytes
    Returns:
      the output value

  - ### ptrSub

    default T ptrSub(int sizeout, int sizeinBase, T inBase, int sizeinOffset, T inOffset)
    Apply the `PcodeOp.PTRSUB` operator to the given inputs

    The "pointer subfield" op takes two operands: base, offset; and is used as a more specific representation of structure field address computation. Its behavior is exactly equivalent to `PcodeOp.INT_ADD`. Suppose `st` is a structure pointer with a field `f` located `inOffset` bytes into the structure, and `st` has the value `base`. The decompiler would likely render the `PcodeOp.PTRSUB` op as `&st->f`. An equivalent SLEIGH expression is `base + offset`.

    NOTE: This op is always a result of decompiler simplification, not low p-code generation, and so are not ordinarily used by a `PcodeExecutor`.

    Parameters:
      `sizeout` - the size (in bytes) of the output variable
      `sizeinBase` - the size (in bytes) of the variable used for the structure's base address
      `inBase` - the value used as the structure's base address
      `sizeinOffset` - the size (in bytes) of the variable used for the offset
      `inOffset` - the value used as the offset
    Returns:
      the output value

  - ### modBeforeStore

    T modBeforeStore(int sizeout, int sizeinAddress, T inAddress, int sizeinValue, T inValue)
    Apply any modifications before a value is stored

    This implements any abstractions associated with `PcodeOp.STORE`. This is called on the address/offset and the value before the value is actually stored into the state.

    Parameters:
      `sizeout` - the size (in bytes) of the output variable
      `sizeinAddress` - the size (in bytes) of the variable used for indirection
      `inAddress` - the value used as the address (or offset)
      `sizeinValue` - the size (in bytes) of the variable to store
      `inValue` - the value to store
    Returns:
      the modified value to store

  - ### modAfterLoad

    T modAfterLoad(int sizeout, int sizeinAddress, T inAddress, int sizeinValue, T inValue)
    Apply any modifications after a value is loaded

    This implements any abstractions associated with `PcodeOp.LOAD`. This is called on the address/offset and the value after the value is actually loaded from the state.

    Parameters:
      `sizeout` - the size (in bytes) of the output variable
      `sizeinAddress` - the size (in bytes) of the variable used for indirection
      `inAddress` - the value used as the address (or offset)
      `sizeinValue` - the size (in bytes) of the variable loaded
      `inValue` - the value loaded
    Returns:
      the modified value loaded

  - ### fromConst

    T fromConst(byte[] value)
    Convert the given constant concrete value to type `T` having the same size.
    Parameters:
      `value` - the constant value
    Returns:
      the value as a `T`

  - ### fromConst

    default T fromConst(long value, int size)
    Convert the given constant concrete value to type `T` having the given size.

    Note that the size may not be applicable to `T`. It is given to ensure the value can be held in a variable of that size when passed to downstream operators or stored in the executor state.

    Parameters:
      `value` - the constant value
      `size` - the size (in bytes) of the variable into which the value is to be stored
    Returns:
      the value as a `T`

  - ### fromConst

    default T fromConst(BigInteger value, int size, boolean isContextreg)
    Convert the given constant concrete value to type `T` having the given size.

    Note that the size may not be applicable to `T`. It is given to ensure the value can be held in a variable of that size when passed to downstream operators or stored in the executor state.

    Parameters:
      `value` - the constant value
      `size` - the size (in bytes) of the variable into which the value is to be stored
      `isContextreg` - true to indicate the value is from the disassembly context register. If `T` represents bytes, and the value is the contextreg, then the bytes are in big endian, no matter the machine language's endianness.
    Returns:
      the value as a `T`

  - ### fromConst

    default T fromConst(BigInteger value, int size)
    Convert the given constant concrete value to type `T` having the given size.

    The value is assumed not to be for the disassembly context register.

    See Also:
      - `fromConst(BigInteger, int, boolean)`

  - ### toConcrete

    byte[] toConcrete(T value, PcodeArithmetic.Purpose purpose)
    Convert, if possible, the given abstract value to a concrete byte array
    Parameters:
      `value` - the abstract value
      `purpose` - the purpose for which the emulator needs a concrete value
    Returns:
      the array
    Throws:
      `ConcretionError` - if the value cannot be made concrete

  - ### isTrue

    default boolean isTrue(T cond, PcodeArithmetic.Purpose purpose)
    Convert, if possible, the given abstract condition to a concrete boolean value
    Parameters:
      `cond` - the abstract condition
      `purpose` - probably `PcodeArithmetic.Purpose.CONDITION`
    Returns:
      the boolean value

  - ### toBigInteger

    default BigInteger toBigInteger(T value, PcodeArithmetic.Purpose purpose)
    Convert, if possible, the given abstract value to a concrete big integer

    If the conversion is not possible, throw an exception.

    Parameters:
      `value` - the abstract value
      `purpose` - the reason why the emulator needs a concrete value
    Returns:
      the concrete value
    Throws:
      `ConcretionError` - if the value cannot be made concrete

  - ### toLong

    default long toLong(T value, PcodeArithmetic.Purpose purpose)
    Convert, if possible, the given abstract value to a concrete long

    If the conversion is not possible, throw an exception.

    Parameters:
      `value` - the abstract value
      `purpose` - the reason why the emulator needs a concrete value
    Returns:
      the concrete value
    Throws:
      `ConcretionError` - if the value cannot be made concrete

  - ### sizeOf

    long sizeOf(T value)
    Get the size in bytes, if possible, of the given abstract value

    If the abstract value does not conceptually have a size, throw an exception.

    Parameters:
      `value` - the abstract value
    Returns:
      the size in bytes

  - ### sizeOfAbstract

    default T sizeOfAbstract(T value)
    Get the size in bytes, if possible, of the given abstract value, as an abstract value

    The returned size should itself has a size of `SIZEOF_SIZEOF`.

    Parameters:
      `value` - the abstract value
    Returns:
      the size in bytes, as an abstract value