Package ghidra.pcode.emu

# Class AbstractPcodeMachine<T>

java.lang.Object
ghidra.pcode.emu.AbstractPcodeMachine<T>

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

All Implemented Interfaces:
  `PcodeMachine<T>`

Direct Known Subclasses:
  `AuxPcodeEmulator`, `PcodeEmulator`

public abstract class AbstractPcodeMachine<T> extends Object implements PcodeMachine<T>
An abstract implementation of `PcodeMachine` suitable as a base for most implementations

A note regarding terminology: A p-code "machine" refers to any p-code-based machine simulator, whether or not it operates on abstract or concrete values. The term "emulator" is reserved for machines whose values always include a concrete piece. That piece doesn't necessarily have to be a (derivative of) `BytesPcodeExecutorStatePiece`, but it usually is. To be called an "emulator" implies that `PcodeArithmetic.toConcrete(Object, Purpose)` never throws `ConcretionError` for any value in its state.

For a complete example of a p-code emulator, see `PcodeEmulator`. For an alternative implementation incorporating an abstract piece, see the Taint Analyzer.

- ## Nested Class Summary

  ## Nested classes/interfaces inherited from interface ghidra.pcode.emu.PcodeMachine

  `PcodeMachine.AccessKind, PcodeMachine.SwiMode`

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `protected final SparseAddressRangeMap<PcodeMachine.AccessKind>`
  `accessBreakpoints`
  `protected final PcodeArithmetic<T>`
  `arithmetic`
  `protected final PcodeEmulationCallbacks<T>`
  `cb`
  `protected final Map<Address,PcodeProgram>`
  `injects`
  `protected final SleighLanguage`
  `language`
  `protected final PcodeUseropLibrary<T>`
  `library`
  `protected final PcodeUseropLibrary<T>`
  `stubLibrary`
  `protected boolean`
  `suspended`
  `protected PcodeMachine.SwiMode`
  `swiMode`
  `protected final Map<String,PcodeThread<T>>`
  `threads`
  `protected final Collection<PcodeThread<T>>`
  `threadsView`

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `AbstractPcodeMachine(Language language, PcodeEmulationCallbacks<T> cb)`
  Construct a p-code machine with the given language and arithmetic

- ## 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
  `protected static SleighLanguage`
  `assertSleigh(Language language)`
  Check and cast the language to Sleigh
  `protected void`
  `checkLoad(AddressSpace space, T offset, int size)`
  Perform checks on a requested LOAD
  `protected void`
  `checkStore(AddressSpace space, T offset, int size)`
  Perform checks on a requested STORE
  `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
  `protected abstract PcodeArithmetic<T>`
  `createArithmetic()`
  A factory method to create the arithmetic used by this machine
  `protected abstract PcodeExecutorState<T>`
  `createLocalState(PcodeThread<T> thread)`
  A factory method to create the (register) state local to the given thread
  `protected abstract PcodeExecutorState<T>`
  `createSharedState()`
  A factory method to create the (memory) state shared by all threads in this machine
  `protected PcodeThread<T>`
  `createThread(String name)`
  A factory method to create a new thread in this machine
  `protected PcodeUseropLibrary<T>`
  `createThreadStubLibrary()`
  A factory method to create a stub library for compiling thread-local Sleigh source
  `protected abstract PcodeUseropLibrary<T>`
  `createUseropLibrary()`
  A factory method to create the userop library shared by all threads in this machine
  `protected void`
  `doPluggableInitialization()`
  Deprecated, for removal: This API element is subject to removal in a future version.
  `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)
  `protected static PcodeStateInitializer`
  `getPluggableInitializer(Language language)`
  Deprecated, for removal: This API element is subject to removal in a future version.
  `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
  `protected void`
  `stepped()`
  Notify the machine a thread has been stepped a p-code op, so that it may re-enable software interrupts, if applicable
  `protected void`
  `swi()`
  Throw a software interrupt exception if those interrupts are active

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Field Details

  - ### language

    protected final SleighLanguage language

  - ### arithmetic

    protected final PcodeArithmetic<T> arithmetic

  - ### library

    protected final PcodeUseropLibrary<T> library

  - ### stubLibrary

    protected final PcodeUseropLibrary<T> stubLibrary

  - ### swiMode

    protected PcodeMachine.SwiMode swiMode

  - ### threads

    protected final Map<String,PcodeThread<T>> threads

  - ### threadsView

    protected final Collection<PcodeThread<T>> threadsView

  - ### suspended

    protected volatile boolean suspended

  - ### injects

    protected final Map<Address,PcodeProgram> injects

  - ### accessBreakpoints

    protected final SparseAddressRangeMap<PcodeMachine.AccessKind> accessBreakpoints

  - ### cb

    protected final PcodeEmulationCallbacks<T> cb

- ## Constructor Details

  - ### AbstractPcodeMachine

    public AbstractPcodeMachine(Language language, PcodeEmulationCallbacks<T> cb)
    Construct a p-code machine with the given language and arithmetic
    Parameters:
      `language` - the processor language to be emulated
      `cb` - callbacks to receive emulation events

- ## Method Details

  - ### assertSleigh

    protected static SleighLanguage assertSleigh(Language language)
    Check and cast the language to Sleigh

    Sleigh is currently the only realization, but this should give a decent error should that ever change.

    Parameters:
      `language` - the language
    Returns:
      the same language, cast to Sleigh

  - ### createArithmetic

    protected abstract PcodeArithmetic<T> createArithmetic()
    A factory method to create the arithmetic used by this machine
    Returns:
      the arithmetic

  - ### createUseropLibrary

    protected abstract PcodeUseropLibrary<T> createUseropLibrary()
    A factory method to create the userop library shared by all threads in this machine
    Returns:
      the library

  - ### getLanguage

    public SleighLanguage getLanguage()
    Description copied from interface: `PcodeMachine`
    Get the machine's Sleigh language (processor model)
    Specified by:
      `getLanguage` in interface `PcodeMachine<T>`
    Returns:
      the language

  - ### getArithmetic

    public PcodeArithmetic<T> getArithmetic()
    Description copied from interface: `PcodeMachine`
    Get the arithmetic applied by the machine
    Specified by:
      `getArithmetic` in interface `PcodeMachine<T>`
    Returns:
      the arithmetic

  - ### getUseropLibrary

    public PcodeUseropLibrary<T> getUseropLibrary()
    Description copied from interface: `PcodeMachine`
    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.

    Specified by:
      `getUseropLibrary` in interface `PcodeMachine<T>`
    Returns:
      the userop library

  - ### getStubUseropLibrary

    public PcodeUseropLibrary<T> getStubUseropLibrary()
    Description copied from interface: `PcodeMachine`
    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.

    Specified by:
      `getStubUseropLibrary` in interface `PcodeMachine<T>`
    Returns:
      the stub library

  - ### createSharedState

    protected abstract PcodeExecutorState<T> createSharedState()
    A factory method to create the (memory) state shared by all threads in this machine
    Returns:
      the shared state

  - ### createLocalState

    protected abstract PcodeExecutorState<T> createLocalState(PcodeThread<T> thread)
    A factory method to create the (register) state local to the given thread
    Parameters:
      `thread` - the thread
    Returns:
      the thread-local state

  - ### createThreadStubLibrary

    protected PcodeUseropLibrary<T> createThreadStubLibrary()
    A factory method to create a stub library for compiling thread-local Sleigh source

    Because threads may introduce p-code userops using libraries unique to that thread, it becomes necessary to at least export stub symbols, so that p-code programs can be compiled from Sleigh source before the thread has necessarily been created. A side effect of this strategy is that all threads, though they may have independent libraries, must export identically-named symbols.

    Returns:
      the stub library for all threads

  - ### setSoftwareInterruptMode

    public void setSoftwareInterruptMode(PcodeMachine.SwiMode mode)
    Description copied from interface: `PcodeMachine`
    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.

    Specified by:
      `setSoftwareInterruptMode` in interface `PcodeMachine<T>`
    Parameters:
      `mode` - the new mode

  - ### getSoftwareInterruptMode

    public PcodeMachine.SwiMode getSoftwareInterruptMode()
    Description copied from interface: `PcodeMachine`
    Get the current software interrupt mode
    Specified by:
      `getSoftwareInterruptMode` in interface `PcodeMachine<T>`
    Returns:
      the mode

  - ### createThread

    protected PcodeThread<T> createThread(String name)
    A factory method to create a new thread in this machine
    Parameters:
      `name` - the name of the new thread
    Returns:
      the new thread
    See Also:
      - `newThread(String)`

  - ### getPluggableInitializer

    @Deprecated(forRemoval=true, since="12.0") protected static PcodeStateInitializer getPluggableInitializer(Language language)
    Deprecated, for removal: This API element is subject to removal in a future version.
    Search the classpath for an applicable state initializer

    If found, the initializer is executed immediately upon creating this machine's shared state and upon creating each thread.

    TODO: This isn't really being used. At one point in development it was used to initialize x86's FS_OFFSET and GS_OFFSET registers. Those only exist in p-code, not the real processor, and replace what might have been `segment(FS)`. There seems more utility in detecting when those registers are uninitialized, requiring the user to initialize them, than it is to silently initialize them to 0. Unless we find utility in this, it will likely be removed in the near future.

    Parameters:
      `language` - the language requiring pluggable initialization
    Returns:
      the initializer
    See Also:
      - `doPluggableInitialization()`
      - `DefaultPcodeThread.doPluggableInitialization()`

  - ### doPluggableInitialization

    @Deprecated(forRemoval=true, since="12.0") protected void doPluggableInitialization()
    Deprecated, for removal: This API element is subject to removal in a future version.
    Execute the initializer upon this machine, if applicable
    See Also:
      - `getPluggableInitializer(Language)`

  - ### newThread

    public PcodeThread<T> newThread()
    Description copied from interface: `PcodeMachine`
    Create a new thread with a default name in this machine
    Specified by:
      `newThread` in interface `PcodeMachine<T>`
    Returns:
      the new thread

  - ### newThread

    public PcodeThread<T> newThread(String name)
    Description copied from interface: `PcodeMachine`
    Create a new thread with the given name in this machine
    Specified by:
      `newThread` in interface `PcodeMachine<T>`
    Parameters:
      `name` - the name
    Returns:
      the new thread

  - ### getThread

    public PcodeThread<T> getThread(String name, boolean createIfAbsent)
    Description copied from interface: `PcodeMachine`
    Get the thread, if present, with the given name
    Specified by:
      `getThread` in interface `PcodeMachine<T>`
    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

    public Collection<? extends PcodeThread<T>> getAllThreads()
    Description copied from interface: `PcodeMachine`
    Collect all threads present in the machine
    Specified by:
      `getAllThreads` in interface `PcodeMachine<T>`
    Returns:
      the collection of threads

  - ### getSharedState

    public PcodeExecutorState<T> getSharedState()
    Description copied from interface: `PcodeMachine`
    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.

    Specified by:
      `getSharedState` in interface `PcodeMachine<T>`
    Returns:
      the memory state

  - ### setSuspended

    public void setSuspended(boolean suspended)
    Description copied from interface: `PcodeMachine`
    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.

    Specified by:
      `setSuspended` in interface `PcodeMachine<T>`
    Parameters:
      `suspended` - true to suspend the machine, false to let it run
    See Also:
      - `PcodeThread.setSuspended(boolean)`

  - ### isSuspended

    public boolean isSuspended()
    Description copied from interface: `PcodeMachine`
    Check the suspension state of the machine
    Specified by:
      `isSuspended` in interface `PcodeMachine<T>`
    Returns:
      true if suspended
    See Also:
      - `PcodeThread.isSuspended()`

  - ### getInject

    public PcodeProgram getInject(Address address)
    Description copied from interface: `PcodeMachine`
    Check for a p-code injection (override) at the given address
    Specified by:
      `getInject` in interface `PcodeMachine<T>`
    Parameters:
      `address` - the address, usually the program counter
    Returns:
      the injected program, most likely `null`

  - ### compileSleigh

    public PcodeProgram compileSleigh(String sourceName, String source)
    Description copied from interface: `PcodeMachine`
    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`.

    Specified by:
      `compileSleigh` in interface `PcodeMachine<T>`
    Parameters:
      `sourceName` - a user-defined source name for the resulting "program"
      `source` - the Sleigh source
    Returns:
      the compiled program

  - ### inject

    public void inject(Address address, String source)
    Description copied from interface: `PcodeMachine`
    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.

    Specified by:
      `inject` in interface `PcodeMachine<T>`
    Parameters:
      `address` - the address to inject at
      `source` - the Sleigh source to compile and inject

  - ### clearInject

    public void clearInject(Address address)
    Description copied from interface: `PcodeMachine`
    Remove the inject, if present, at the given address
    Specified by:
      `clearInject` in interface `PcodeMachine<T>`
    Parameters:
      `address` - the address to clear

  - ### clearAllInjects

    public void clearAllInjects()
    Description copied from interface: `PcodeMachine`
    Remove all injects from this machine

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

    Specified by:
      `clearAllInjects` in interface `PcodeMachine<T>`

  - ### addBreakpoint

    public void addBreakpoint(Address address, String sleighCondition)
    Description copied from interface: `PcodeMachine`
    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.

    Specified by:
      `addBreakpoint` in interface `PcodeMachine<T>`
    Parameters:
      `address` - the address at which to break
      `sleighCondition` - a Sleigh expression which controls the breakpoint

  - ### addAccessBreakpoint

    public void addAccessBreakpoint(AddressRange range, PcodeMachine.AccessKind kind)
    Description copied from interface: `PcodeMachine`
    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 `checkLoad(AddressSpace, Object, int)` and/or `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.

    Specified by:
      `addAccessBreakpoint` in interface `PcodeMachine<T>`
    Parameters:
      `range` - the address range to trap
      `kind` - the kind of access to trap

  - ### clearAccessBreakpoints

    public void clearAccessBreakpoints()
    Description copied from interface: `PcodeMachine`
    Remove all access breakpoints from this machine
    Specified by:
      `clearAccessBreakpoints` in interface `PcodeMachine<T>`

  - ### checkLoad

    protected void checkLoad(AddressSpace space, T offset, int size)
    Perform checks on a requested LOAD

    Throw an exception if the LOAD should cause an interrupt.

    Parameters:
      `space` - the address space being accessed
      `offset` - the offset being accessed
      `size` - the size of the variable being accessed

  - ### checkStore

    protected void checkStore(AddressSpace space, T offset, int size)
    Perform checks on a requested STORE

    Throw an exception if the STORE should cause an interrupt.

    Parameters:
      `space` - the address space being accessed
      `offset` - the offset being accessed
      `size` - the size of the variable being accessed

  - ### swi

    protected void swi()
    Throw a software interrupt exception if those interrupts are active

  - ### stepped

    protected void stepped()
    Notify the machine a thread has been stepped a p-code op, so that it may re-enable software interrupts, if applicable