Package ghidra.pcode.emu

# Interface PcodeThread<T>

Type Parameters:
  `T` - the type of values in the emulated machine state

All Known Implementing Classes:
  `AuxPcodeThread`, `BytesPcodeThread`, `DefaultPcodeThread`, `JitPcodeThread`, `ModifiedPcodeThread`

public interface PcodeThread<T>
An emulated thread of execution

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `assignContext(RegisterValue context)`
  Adjust the thread's decoding context without writing to its executor state
  `void`
  `clearAllInjects()`
  Remove all per-thread injects from this thread
  `void`
  `clearInject(Address address)`
  Remove the per-thread inject, if present, at the given address
  `void`
  `dropInstruction()`
  If there is a current instruction, drop its frame of execution
  `void`
  `executeInstruction()`
  Execute the next instruction, ignoring injects
  `void`
  `finishInstruction()`
  Finish execution of the current instruction or inject
  `PcodeArithmetic<T>`
  `getArithmetic()`
  Get the thread's p-code arithmetic
  `RegisterValue`
  `getContext()`
  Get the thread's decoding context
  `Address`
  `getCounter()`
  Get the value of the program counter of this thread
  `PcodeExecutor<T>`
  `getExecutor()`
  Get the thread's p-code executor
  `PcodeFrame`
  `getFrame()`
  Get the current frame, if present
  `Instruction`
  `getInstruction()`
  Get the current decoded instruction, if applicable
  `SleighLanguage`
  `getLanguage()`
  Get the thread's Sleigh language (processor model)
  `PcodeMachine<T>`
  `getMachine()`
  Get the machine within which this thread executes
  `String`
  `getName()`
  Get the name of this thread
  `ThreadPcodeExecutorState<T>`
  `getState()`
  Get the thread's memory and register state
  `PcodeUseropLibrary<T>`
  `getUseropLibrary()`
  Get the complete userop library for this thread
  `void`
  `inject(Address address, String source)`
  Override the p-code at the given address with the given Sleigh source for only this thread
  `boolean`
  `isSuspended()`
  Check the suspension state of the thread's executor
  `void`
  `overrideContext(RegisterValue context)`
  Adjust the thread's decoding context and write the contextreg of its executor state
  `void`
  `overrideContextWithDefault()`
  Set the context at the current counter to the default given by the language
  `void`
  `overrideCounter(Address counter)`
  Set the thread's program counter and write the pc register of its executor state
  `void`
  `reInitialize()`
  Re-sync the decode context and counter address from the machine state
  `void`
  `run()`
  Emulate indefinitely
  `void`
  `setCounter(Address counter)`
  Set the thread's program counter without writing to its executor state
  `void`
  `setSuspended(boolean suspended)`
  Set the suspension state of the thread's executor
  `void`
  `skipInstruction()`
  Decode, but skip the next instruction
  `void`
  `skipPcodeOp()`
  Skip emulation of a single p-code operation
  `void`
  `stepInstruction()`
  Step emulation a single instruction
  `default void`
  `stepInstruction(long count)`
  Repeat `stepInstruction()` count times
  `void`
  `stepPatch(String sleigh)`
  Apply a patch to the emulator
  `void`
  `stepPcodeOp()`
  Step emulation a single p-code operation
  `default void`
  `stepPcodeOp(long count)`
  Repeat `stepPcodeOp()` count times

- ## 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:
      - `overrideCounter(Address)`

  - ### 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:
      - `setCounter(Address)`

  - ### 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:
      - `overrideContext(RegisterValue)`

  - ### 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:
      - `assignContext(RegisterValue)`

  - ### 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:
      - `PcodeMachine.setSuspended(boolean)`

  - ### 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

    ThreadPcodeExecutorState<T> 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.