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.

  • Field Details

  • Constructor Details

    • AbstractPcodeMachine

      public AbstractPcodeMachine(Language language)
      Construct a p-code machine with the given language and arithmetic
      Parameters:
      language - the processor language to be emulated
  • 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:
    • getPluggableInitializer

      protected static PcodeStateInitializer getPluggableInitializer(Language language)
      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

      protected void doPluggableInitialization()
      Execute the initializer upon this machine, if applicable
      See Also:
    • 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:
    • 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:
    • getInject

      protected 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
    • 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. The 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