Class DefaultPcodeThread<T>

java.lang.Object
ghidra.pcode.emu.DefaultPcodeThread<T>
All Implemented Interfaces:
PcodeThread<T>
Direct Known Subclasses:
ModifiedPcodeThread

public class DefaultPcodeThread<T> extends Object implements PcodeThread<T>
The default implementation of PcodeThread suitable for most applications

When emulating on concrete state, consider using ModifiedPcodeThread, so that state modifiers from the older Emulator are incorporated. In either case, it may be worthwhile to examine existing state modifiers to ensure they are appropriately represented in any abstract state. It may be necessary to port them.

This class implements the control-flow logic of the target machine, cooperating with the p-code program flow implemented by the PcodeExecutor. This implementation exists primarily in beginInstructionOrInject() and advanceAfterFinished().

  • Field Details

  • Constructor Details

  • Method Details

    • createInstructionDecoder

      protected SleighInstructionDecoder createInstructionDecoder(PcodeExecutorState<T> sharedState)
      A factory method for the instruction decoder
      Parameters:
      sharedState - the machine's shared (memory state)
      Returns:
    • createUseropLibrary

      protected PcodeUseropLibrary<T> createUseropLibrary()
      A factory method to create the complete userop library for this thread

      The returned library must compose the containing machine's shared userop library. See PcodeUseropLibrary.compose(PcodeUseropLibrary).

      Returns:
      the thread's complete userop library
    • createExecutor

      protected DefaultPcodeThread.PcodeThreadExecutor<T> createExecutor()
      A factory method to create the executor for this thread
      Returns:
      the executor
    • getName

      public String getName()
      Description copied from interface: PcodeThread
      Get the name of this thread
      Specified by:
      getName in interface PcodeThread<T>
      Returns:
      the name
    • getMachine

      public AbstractPcodeMachine<T> getMachine()
      Description copied from interface: PcodeThread
      Get the machine within which this thread executes
      Specified by:
      getMachine in interface PcodeThread<T>
      Returns:
      the containing machine
    • setCounter

      public void setCounter(Address counter)
      Description copied from interface: PcodeThread
      Set the thread's program counter without writing to its executor state
      Specified by:
      setCounter in interface PcodeThread<T>
      Parameters:
      counter - the new target address
      See Also:
    • getCounter

      public Address getCounter()
      Description copied from interface: PcodeThread
      Get the value of the program counter of this thread
      Specified by:
      getCounter in interface PcodeThread<T>
      Returns:
      the value
    • branchToAddress

      protected void branchToAddress(Address target)
    • writeCounter

      protected void writeCounter(Address counter)
    • overrideCounter

      public void overrideCounter(Address counter)
      Description copied from interface: PcodeThread
      Set the thread's program counter and write the pc register of its executor state

      Warning: Setting the counter into the middle of group constructs, e.g., parallel instructions or delay-slotted instructions, may cause undefined behavior.

      Specified by:
      overrideCounter in interface PcodeThread<T>
      Parameters:
      counter - the new target address
      See Also:
    • assignContext

      public void assignContext(RegisterValue context)
      Description copied from interface: PcodeThread
      Adjust the thread's decoding context without writing to its executor state

      As in RegisterValue.assign(Register, RegisterValue), only those bits having a value in the given context are applied to the current context.

      Specified by:
      assignContext in interface PcodeThread<T>
      Parameters:
      context - the new context
      See Also:
    • getContext

      public RegisterValue getContext()
      Description copied from interface: PcodeThread
      Get the thread's decoding context
      Specified by:
      getContext in interface PcodeThread<T>
      Returns:
      the context
    • overrideContext

      public void overrideContext(RegisterValue context)
      Description copied from interface: PcodeThread
      Adjust the thread's decoding context and write the contextreg of its executor state
      Specified by:
      overrideContext in interface PcodeThread<T>
      Parameters:
      context - the new context
      See Also:
    • overrideContextWithDefault

      public void overrideContextWithDefault()
      Description copied from interface: PcodeThread
      Set the context at the current counter to the default given by the language

      This also writes the context to the thread's state. For languages without context, this call does nothing.

      Specified by:
      overrideContextWithDefault in interface PcodeThread<T>
    • doPluggableInitialization

      protected void doPluggableInitialization()
      Execute the initializer upon this thread, if applicable
      See Also:
    • reInitialize

      public void reInitialize()
      Description copied from interface: PcodeThread
      Re-sync the decode context and counter address from the machine state
      Specified by:
      reInitialize in interface PcodeThread<T>
    • stepInstruction

      public void stepInstruction()
      Description copied from interface: PcodeThread
      Step emulation a single instruction

      Note because of the way Ghidra and Sleigh handle delay slots, the execution of an instruction with delay slots cannot be separated from the instructions filling those slots. It and its slotted instructions are executed in a single "step." However, stepping the individual p-code ops is still possible using PcodeThread.stepPcodeOp().

      Specified by:
      stepInstruction in interface PcodeThread<T>
    • stepPcodeOp

      public void stepPcodeOp()
      Description copied from interface: PcodeThread
      Step emulation a single p-code operation

      Execution of the current instruction begins if there is no current frame: A new frame is constructed and its counter is initialized. If a frame is present, and it has not been completed, its next operation is executed and its counter is stepped. If the current frame is completed, the machine's program counter is advanced and the current frame is removed.

      Consider the case of a fall-through instruction: The first p-code step decodes the instruction and sets up the p-code frame. The second p-code step executes the first p-code op of the frame. Each subsequent p-code step executes the next p-code op until no ops remain. The final p-code step detects the fall-through result, advances the counter, and disposes the frame. The next p-code step is actually the first p-code step of the next instruction.

      Consider the case of a branching instruction: The first p-code step decodes the instruction and sets up the p-code frame. The second p-code step executes the first p-code op of the frame. Each subsequent p-code step executes the next p-code op until an (external) branch is executed. That branch itself sets the program counter appropriately. The final p-code step detects the branch result and simply disposes the frame. The next p-code step is actually the first p-code step of the next instruction.

      The decode step in both examples is subject to p-code injections. In order to provide the most flexibility, there is no enforcement of various emulation state on this method. Expect strange behavior for strange call sequences.

      While this method heeds injects, such injects will obscure the p-code of the instruction itself. If the inject executes the instruction, the entire instruction will be executed when stepping the DefaultPcodeThread.PcodeEmulationLibrary.emu_exec_decoded() userop, since there is not (currently) any way to "step into" a userop.

      Specified by:
      stepPcodeOp in interface PcodeThread<T>
    • skipPcodeOp

      public void skipPcodeOp()
      Description copied from interface: PcodeThread
      Skip emulation of a single p-code operation

      If there is no current frame, this behaves as in PcodeThread.stepPcodeOp(). Otherwise, this skips the current pcode op, advancing as if a fall-through op. If no ops remain in the frame, this behaves as in PcodeThread.stepPcodeOp(). Please note to skip an extranal branch, the op itself must be skipped. "Skipping" the following op, which disposes the frame, cannot prevent the branch.

      Specified by:
      skipPcodeOp in interface PcodeThread<T>
    • stepPatch

      public void stepPatch(String sleigh)
      Description copied from interface: PcodeThread
      Apply a patch to the emulator
      Specified by:
      stepPatch in interface PcodeThread<T>
      Parameters:
      sleigh - a line of sleigh semantic source to execute (excluding the final semicolon)
    • beginInstructionOrInject

      protected void beginInstructionOrInject()
      Start execution of the instruction or inject at the program counter
    • getContextAfterCommits

      protected RegisterValue getContextAfterCommits()
    • advanceAfterFinished

      protected void advanceAfterFinished()
      Resolve a finished instruction, advancing the program counter if necessary
    • getFrame

      public PcodeFrame getFrame()
      Description copied from interface: PcodeThread
      Get the current frame, if present

      If the client only calls PcodeThread.stepInstruction() and execution completes normally, this method will always return null. If interrupted, the frame marks where execution of an instruction or inject should resume. Depending on the case, the frame may need to be stepped back in order to retry the failed p-code operation. If this frame is present, it means that the instruction has not been executed completed. Even if the frame PcodeFrame.isFinished(),

      Specified by:
      getFrame in interface PcodeThread<T>
      Returns:
      the current frame
    • getInstruction

      public Instruction getInstruction()
      Description copied from interface: PcodeThread
      Get the current decoded instruction, if applicable
      Specified by:
      getInstruction in interface PcodeThread<T>
      Returns:
      the instruction
    • assertCompletedInstruction

      protected void assertCompletedInstruction()
      A sanity-checking measure: Cannot start a new instruction while one is still being executed
    • assertMidInstruction

      protected void assertMidInstruction()
      A sanity-checking measure: Cannot finish an instruction unless one is currently being executed
    • preExecuteInstruction

      protected void preExecuteInstruction()
      Extension point: Extra behavior before executing an instruction

      This is currently used for incorporating state modifiers from the older Emulator framework. There is likely utility here when porting those to this framework.

    • postExecuteInstruction

      protected void postExecuteInstruction()
      Extension point: Extra behavior after executing an instruction

      This is currently used for incorporating state modifiers from the older Emulator framework. There is likely utility here when porting those to this framework.

    • onMissingUseropDef

      protected boolean onMissingUseropDef(PcodeOp op, String opName)
      Extension point: Behavior when a p-code userop definition is not found
      Parameters:
      op - the op
      opName - the name of the p-code userop
      Returns:
      true if handle, false if still undefined
    • executeInstruction

      public void executeInstruction()
      Description copied from interface: PcodeThread
      Execute the next instruction, ignoring injects

      WARNING: This method should likely only be used internally. It steps the current instruction, but without any consideration for user injects, e.g., breakpoints. Most clients should call PcodeThread.stepInstruction() instead.

      Specified by:
      executeInstruction in interface PcodeThread<T>
    • finishInstruction

      public void finishInstruction()
      Description copied from interface: PcodeThread
      Finish execution of the current instruction or inject

      In general, this method is only used after an interrupt or fault in order to complete the p-code of the faulting instruction. Depending on the nature of the interrupt, this behavior may not be desired.

      Specified by:
      finishInstruction in interface PcodeThread<T>
    • skipInstruction

      public void skipInstruction()
      Description copied from interface: PcodeThread
      Decode, but skip the next instruction
      Specified by:
      skipInstruction in interface PcodeThread<T>
    • dropInstruction

      public void dropInstruction()
      Description copied from interface: PcodeThread
      If there is a current instruction, drop its frame of execution

      WARNING: This does not revert any state changes caused by a partially-executed instruction. It is up to the client to revert the underlying machine state if desired. Note the thread's program counter will not be advanced. Likely, the next call to PcodeThread.stepInstruction() will re-start the same instruction. If there is no current instruction, this method has no effect.

      Specified by:
      dropInstruction in interface PcodeThread<T>
    • run

      public void run()
      Description copied from interface: PcodeThread
      Emulate indefinitely

      This begins or resumes execution of the emulator. If there is a current instruction, that instruction is finished. By calling this method, you are "donating" the current Java thread to the emulator. This method will not likely return, but instead only terminates via exception, e.g., hitting a user breakpoint or becoming suspended. Depending on the use case, this method might be invoked from a Java thread dedicated to this emulated thread.

      Specified by:
      run in interface PcodeThread<T>
    • setSuspended

      public void setSuspended(boolean suspended)
      Description copied from interface: PcodeThread
      Set the suspension state of the thread's executor

      When PcodeThread.run() is invoked by a dedicated thread, suspending the pcode thread is the most reliable way to halt execution. Note the emulator may halt mid instruction. If this is not desired, then upon catching the exception, un-suspend the p-code thread and call PcodeThread.finishInstruction() or PcodeThread.dropInstruction().

      Specified by:
      setSuspended in interface PcodeThread<T>
      Parameters:
      suspended - true to suspend the machine, false to let it run
      See Also:
    • isSuspended

      public boolean isSuspended()
      Description copied from interface: PcodeThread
      Check the suspension state of the thread's executor
      Specified by:
      isSuspended in interface PcodeThread<T>
      Returns:
      true if suspended
    • getLanguage

      public SleighLanguage getLanguage()
      Description copied from interface: PcodeThread
      Get the thread's Sleigh language (processor model)
      Specified by:
      getLanguage in interface PcodeThread<T>
      Returns:
      the language
    • getArithmetic

      public PcodeArithmetic<T> getArithmetic()
      Description copied from interface: PcodeThread
      Get the thread's p-code arithmetic
      Specified by:
      getArithmetic in interface PcodeThread<T>
      Returns:
      the arithmetic
    • getExecutor

      public PcodeExecutor<T> getExecutor()
      Description copied from interface: PcodeThread
      Get the thread's p-code executor

      This can be used to execute injected p-code, e.g., as part of implementing a userop, or as part of testing, outside the thread's usual control flow. Any new frame generated by the executor is ignored by the thread. It retains the instruction frame, if any. Note that suspension is implemented by the executor, so if this p-code thread is suspended, the executor cannot execute any code.

      Specified by:
      getExecutor in interface PcodeThread<T>
      Returns:
      the executor
    • getUseropLibrary

      public PcodeUseropLibrary<T> getUseropLibrary()
      Description copied from interface: PcodeThread
      Get the complete userop library for this thread
      Specified by:
      getUseropLibrary in interface PcodeThread<T>
      Returns:
      the library
    • getState

      public ThreadPcodeExecutorState<T> getState()
      Description copied from interface: PcodeThread
      Get the thread's memory and register state

      The memory part of this state is shared among all threads in the same machine. See PcodeMachine.getSharedState().

      Specified by:
      getState in interface PcodeThread<T>
      Returns:
      the state
    • getInject

      protected PcodeProgram getInject(Address address)
      Check for a p-code injection (override) at the given address

      This checks this thread's particular injects and then defers to the machine's injects.

      Parameters:
      address - the address, usually the program counter
      Returns:
      the injected program, most likely null
    • inject

      public void inject(Address address, String source)
      Description copied from interface: PcodeThread
      Override the p-code at the given address with the given Sleigh source for only this thread

      This works the same PcodeMachine.inject(Address, String) but on a per-thread basis. Where there is both a machine-level and thread-level inject the thread inject takes precedence. Furthermore, the machine-level inject cannot be accessed by the thread-level inject.

      Specified by:
      inject in interface PcodeThread<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: PcodeThread
      Remove the per-thread inject, if present, at the given address

      This has no effect on machine-level injects. If there is one present, it will still override this thread's p-code if execution reaches the address.

      Specified by:
      clearInject in interface PcodeThread<T>
      Parameters:
      address - the address to clear
    • clearAllInjects

      public void clearAllInjects()
      Description copied from interface: PcodeThread
      Remove all per-thread injects from this thread

      All machine-level injects are still effective after this call.

      Specified by:
      clearAllInjects in interface PcodeThread<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