Interface PcodeThread<T>

Type Parameters:
T - the type of values in the emulated machine state
All Known Implementing Classes:
AuxPcodeThread, BytesPcodeThread, DefaultPcodeThread, ModifiedPcodeThread

public interface PcodeThread<T>
An emulated thread of execution
  • Method Details

    • getName

      String getName()
      Get the name of this thread
      Returns:
      the name
    • getMachine

      PcodeMachine<T> getMachine()
      Get the machine within which this thread executes
      Returns:
      the containing machine
    • setCounter

      void setCounter(Address counter)
      Set the thread's program counter without writing to its executor state
      Parameters:
      counter - the new target address
      See Also:
    • getCounter

      Address getCounter()
      Get the value of the program counter of this thread
      Returns:
      the value
    • overrideCounter

      void overrideCounter(Address counter)
      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.

      Parameters:
      counter - the new target address
      See Also:
    • assignContext

      void assignContext(RegisterValue context)
      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.

      Parameters:
      context - the new context
      See Also:
    • getContext

      RegisterValue getContext()
      Get the thread's decoding context
      Returns:
      the context
    • overrideContext

      void overrideContext(RegisterValue context)
      Adjust the thread's decoding context and write the contextreg of its executor state
      Parameters:
      context - the new context
      See Also:
    • overrideContextWithDefault

      void overrideContextWithDefault()
      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.

    • reInitialize

      void reInitialize()
      Re-sync the decode context and counter address from the machine state
    • stepInstruction

      void stepInstruction()
      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 stepPcodeOp().

    • stepInstruction

      default void stepInstruction(long count)
      Repeat stepInstruction() count times
      Parameters:
      count - the number of instructions to step
    • stepPcodeOp

      void stepPcodeOp()
      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.

    • stepPcodeOp

      default void stepPcodeOp(long count)
      Repeat stepPcodeOp() count times
      Parameters:
      count - the number of p-code operations to step
    • skipPcodeOp

      void skipPcodeOp()
      Skip emulation of a single p-code operation

      If there is no current frame, this behaves as in 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 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.

    • stepPatch

      void stepPatch(String sleigh)
      Apply a patch to the emulator
      Parameters:
      sleigh - a line of sleigh semantic source to execute (excluding the final semicolon)
    • getFrame

      PcodeFrame getFrame()
      Get the current frame, if present

      If the client only calls 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(),

      Returns:
      the current frame
    • getInstruction

      Instruction getInstruction()
      Get the current decoded instruction, if applicable
      Returns:
      the instruction
    • executeInstruction

      void executeInstruction()
      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 stepInstruction() instead.

      Throws:
      IllegalStateException - if the emulator is still in the middle of an instruction. That can happen if the machine is interrupted, or if the client has called stepPcodeOp().
    • finishInstruction

      void finishInstruction()
      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.

      Throws:
      IllegalStateException - if there is no current instruction, i.e., the emulator has not started executing the next instruction, yet.
    • skipInstruction

      void skipInstruction()
      Decode, but skip the next instruction
    • dropInstruction

      void dropInstruction()
      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 stepInstruction() will re-start the same instruction. If there is no current instruction, this method has no effect.

    • run

      void run()
      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.

    • setSuspended

      void setSuspended(boolean suspended)
      Set the suspension state of the thread's executor

      When 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 finishInstruction() or dropInstruction().

      Parameters:
      suspended - true to suspend the machine, false to let it run
      See Also:
    • isSuspended

      boolean isSuspended()
      Check the suspension state of the thread's executor
      Returns:
      true if suspended
    • getLanguage

      SleighLanguage getLanguage()
      Get the thread's Sleigh language (processor model)
      Returns:
      the language
    • getArithmetic

      PcodeArithmetic<T> getArithmetic()
      Get the thread's p-code arithmetic
      Returns:
      the arithmetic
    • getExecutor

      PcodeExecutor<T> getExecutor()
      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.

      Returns:
      the executor
    • getUseropLibrary

      PcodeUseropLibrary<T> getUseropLibrary()
      Get the complete userop library for this thread
      Returns:
      the library
    • getState

      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().

      Returns:
      the state
    • inject

      void inject(Address address, String source)
      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.

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

      void clearInject(Address address)
      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.

      Parameters:
      address - the address to clear
    • clearAllInjects

      void clearAllInjects()
      Remove all per-thread injects from this thread

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