Package ghidra.pcode.emu

# Interface PcodeMachine<T>

Type Parameters:
  `T` - the type of objects in the machine's state

All Known Implementing Classes:
  `AbstractPcodeMachine`, `AuxPcodeEmulator`, `JitPcodeEmulator`, `PcodeEmulator`, `TaintPcodeEmulator`

public interface PcodeMachine<T>
A machine which execute p-code on state of an abstract type

- ## Nested Class Summary

  Nested Classes
  Modifier and Type
  Interface
  Description
  `static enum`
  `PcodeMachine.AccessKind`
  The kind of access breakpoint
  `static enum`
  `PcodeMachine.SwiMode`
  Specifies whether or not to interrupt on p-code breakpoints

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `addAccessBreakpoint(AddressRange range, PcodeMachine.AccessKind kind)`
  Add an access breakpoint over the given range
  `void`
  `addBreakpoint(Address address, String sleighCondition)`
  Add a conditional execution breakpoint at the given address
  `void`
  `clearAccessBreakpoints()`
  Remove all access breakpoints from this machine
  `void`
  `clearAllInjects()`
  Remove all injects from this machine
  `void`
  `clearInject(Address address)`
  Remove the inject, if present, at the given address
  `PcodeProgram`
  `compileSleigh(String sourceName, String source)`
  Compile the given Sleigh code for execution by a thread of this machine
  `Collection<? extends PcodeThread<T>>`
  `getAllThreads()`
  Collect all threads present in the machine
  `PcodeArithmetic<T>`
  `getArithmetic()`
  Get the arithmetic applied by the machine
  `PcodeProgram`
  `getInject(Address address)`
  Check for a p-code injection (override) at the given address
  `SleighLanguage`
  `getLanguage()`
  Get the machine's Sleigh language (processor model)
  `PcodeExecutorState<T>`
  `getSharedState()`
  Get the machine's shared (memory) state
  `PcodeMachine.SwiMode`
  `getSoftwareInterruptMode()`
  Get the current software interrupt mode
  `PcodeUseropLibrary<T>`
  `getStubUseropLibrary()`
  Get a userop library which at least declares all userops available in each thread userop library.
  `PcodeThread<T>`
  `getThread(String name, boolean createIfAbsent)`
  Get the thread, if present, with the given name
  `PcodeUseropLibrary<T>`
  `getUseropLibrary()`
  Get the userop library common to all threads in the machine.
  `void`
  `inject(Address address, String source)`
  Override the p-code at the given address with the given Sleigh source
  `boolean`
  `isSuspended()`
  Check the suspension state of the machine
  `PcodeThread<T>`
  `newThread()`
  Create a new thread with a default name in this machine
  `PcodeThread<T>`
  `newThread(String name)`
  Create a new thread with the given name in this machine
  `void`
  `setSoftwareInterruptMode(PcodeMachine.SwiMode mode)`
  Change the efficacy of p-code breakpoints
  `void`
  `setSuspended(boolean suspended)`
  Set the suspension state of the machine

- ## Method Details

  - ### getLanguage

    SleighLanguage getLanguage()
    Get the machine's Sleigh language (processor model)
    Returns:
      the language

  - ### getArithmetic

    PcodeArithmetic<T> getArithmetic()
    Get the arithmetic applied by the machine
    Returns:
      the arithmetic

  - ### setSoftwareInterruptMode

    void setSoftwareInterruptMode(PcodeMachine.SwiMode mode)
    Change the efficacy of p-code breakpoints

    This is used to prevent breakpoints from interrupting at inappropriate times, e.g., upon continuing from a breakpoint.

    Parameters:
      `mode` - the new mode

  - ### getSoftwareInterruptMode

    PcodeMachine.SwiMode getSoftwareInterruptMode()
    Get the current software interrupt mode
    Returns:
      the mode

  - ### getUseropLibrary

    PcodeUseropLibrary<T> getUseropLibrary()
    Get the userop library common to all threads in the machine.

    Note that threads may have larger libraries, but each contains all the userops in this library.

    Returns:
      the userop library

  - ### getStubUseropLibrary

    PcodeUseropLibrary<T> getStubUseropLibrary()
    Get a userop library which at least declares all userops available in each thread userop library.

    Thread userop libraries may have more userops than are defined in the machine's userop library. However, to compile Sleigh programs linked to thread libraries, the thread's userops must be known to the compiler. The stub library will name all userops common among the threads, even if their definitions vary. WARNING: The stub library is not required to provide implementations of the userops. Often they will throw exceptions, so do not attempt to use the returned library in an executor.

    Returns:
      the stub library

  - ### newThread

    PcodeThread<T> newThread()
    Create a new thread with a default name in this machine
    Returns:
      the new thread

  - ### newThread

    PcodeThread<T> newThread(String name)
    Create a new thread with the given name in this machine
    Parameters:
      `name` - the name
    Returns:
      the new thread

  - ### getThread

    PcodeThread<T> getThread(String name, boolean createIfAbsent)
    Get the thread, if present, with the given name
    Parameters:
      `name` - the name
      `createIfAbsent` - create a new thread if the thread does not already exist
    Returns:
      the thread, or `null` if absent and not created

  - ### getAllThreads

    Collection<? extends PcodeThread<T>> getAllThreads()
    Collect all threads present in the machine
    Returns:
      the collection of threads

  - ### getSharedState

    PcodeExecutorState<T> getSharedState()
    Get the machine's shared (memory) state

    The returned state will may throw `IllegalArgumentException` if the client requests register values of it. This state is shared among all threads in this machine.

    Returns:
      the memory state

  - ### setSuspended

    void setSuspended(boolean suspended)
    Set the suspension state of the machine

    This does not simply suspend all threads, but sets a machine-wide flag. A thread is suspended if either the thread's flag is set, or the machine's flag is set.

    Parameters:
      `suspended` - true to suspend the machine, false to let it run
    See Also:
      - `PcodeThread.setSuspended(boolean)`

  - ### isSuspended

    boolean isSuspended()
    Check the suspension state of the machine
    Returns:
      true if suspended
    See Also:
      - `PcodeThread.isSuspended()`

  - ### compileSleigh

    PcodeProgram compileSleigh(String sourceName, String source)
    Compile the given Sleigh code for execution by a thread of this machine

    This links in the userop library given at construction time and those defining the emulation userops, e.g., `emu_swi`.

    Parameters:
      `sourceName` - a user-defined source name for the resulting "program"
      `source` - the Sleigh source
    Returns:
      the compiled program

  - ### inject

    void inject(Address address, String source)
    Override the p-code at the given address with the given Sleigh source

    This will attempt to compile the given source against this machine's userop library and then inject it at the given address. The resulting p-code replaces that which would be executed by decoding the instruction at the given address. That means the machine will not decode, nor advance its counter, unless the Sleigh causes it. In most cases, the Sleigh will call `DefaultPcodeThread.PcodeEmulationLibrary.emu_exec_decoded()` to cause the machine to decode and execute the overridden instruction.

    Each address can have at most a single inject. If there is already one present, it is replaced and the old inject completely forgotten. The injector does not support chaining or double-wrapping, etc.

    No synchronization is provided on the internal injection storage. Clients should ensure the machine is not executing when injecting p-code. Additionally, the client must ensure only one thread is injecting p-code to the machine at a time.

    Parameters:
      `address` - the address to inject at
      `source` - the Sleigh source to compile and inject

  - ### getInject

    PcodeProgram getInject(Address address)
    Check for a p-code injection (override) at the given address
    Parameters:
      `address` - the address, usually the program counter
    Returns:
      the injected program, most likely `null`

  - ### clearInject

    void clearInject(Address address)
    Remove the inject, if present, at the given address
    Parameters:
      `address` - the address to clear

  - ### clearAllInjects

    void clearAllInjects()
    Remove all injects from this machine

    This will clear execution breakpoints, but not access breakpoints. See `clearAccessBreakpoints()`.

  - ### addBreakpoint

    void addBreakpoint(Address address, String sleighCondition)
    Add a conditional execution breakpoint at the given address

    Breakpoints are implemented at the p-code level using an inject, without modification to the emulated image. As such, it cannot coexist with another inject. A client needing to break during an inject must use `DefaultPcodeThread.PcodeEmulationLibrary.emu_swi()` in the injected Sleigh.

    No synchronization is provided on the internal breakpoint storage. Clients should ensure the machine is not executing when adding breakpoints. Additionally, the client must ensure only one thread is adding breakpoints to the machine at a time.

    Parameters:
      `address` - the address at which to break
      `sleighCondition` - a Sleigh expression which controls the breakpoint

  - ### addAccessBreakpoint

    void addAccessBreakpoint(AddressRange range, PcodeMachine.AccessKind kind)
    Add an access breakpoint over the given range

    Access breakpoints are implemented out of band, without modification to the emulated image. The breakpoints are only effective for p-code `PcodeOp.LOAD` and `PcodeOp.STORE` operations with concrete offsets. Thus, an operation that refers directly to a memory address, e.g., a memory-mapped register, will not be trapped. Similarly, access breakpoints on registers or unique variables will not work. Access to an abstract offset that cannot be made concrete, i.e., via `PcodeArithmetic.toConcrete(Object, Purpose)` cannot be trapped. To interrupt on direct and/or abstract accesses, consider wrapping the relevant state and/or overriding `PcodeExecutorStatePiece.getVar(Varnode, Reason)` and related. For accesses to abstract offsets, consider overriding `AbstractPcodeMachine.checkLoad(AddressSpace, Object, int)` and/or `AbstractPcodeMachine.checkStore(AddressSpace, Object, int)` instead.

    A breakpoint's range cannot cross more than one page boundary. Pages are 4096 bytes each. This allows implementations to optimize checking for breakpoints. If a breakpoint does not follow this rule, the behavior is undefined. Breakpoints may overlap, but currently no indication is given as to which breakpoint interrupted emulation.

    No synchronization is provided on the internal breakpoint storage. Clients should ensure the machine is not executing when adding breakpoints. Additionally, the client must ensure only one thread is adding breakpoints to the machine at a time.

    Parameters:
      `range` - the address range to trap
      `kind` - the kind of access to trap

  - ### clearAccessBreakpoints

    void clearAccessBreakpoints()
    Remove all access breakpoints from this machine