# How Ghidra's Emulation Framework Works: A Deep Dive into Pcode-Based Execution

> Explore Ghidra's emulation framework, translating machine code to p-code for execution. Understand legacy and modern approaches for efficient analysis.

- Repository: [National Security Agency/ghidra](https://github.com/NationalSecurityAgency/ghidra)
- Tags: deep-dive
- Published: 2026-03-04

---

**Ghidra's emulation framework translates machine code into p-code intermediate representation and executes it using two distinct stacks: the deprecated `EmulatorHelper`/`DefaultEmulator` for legacy scripts and the modern `PcodeEmulator` built on generic `PcodeMachine` interfaces.**

The NationalSecurityAgency/ghidra repository provides a sophisticated emulation engine that enables reverse engineers to execute binary code symbolically or concretely without hardware. The framework decodes processor-specific instructions into language-agnostic p-code operations, then interprets those operations through pluggable arithmetic engines, memory states, and thread models.

## Two Architectures: Legacy and Modern

Ghidra maintains two emulation stacks that share the same p-code foundation but differ significantly in API design and extensibility:

- **Legacy Stack**: Built around `EmulatorHelper` and `DefaultEmulator`, this high-level API mimics a full processor with convenience methods for registers, breakpoints, and memory. It is functional but **deprecated** as of recent releases.
- **Modern Stack**: Centered on `PcodeEmulator`, this generic, type-parameterized architecture (`PcodeMachine<T>`) supports concrete byte execution, symbolic analysis, and custom value types through interchangeable arithmetic and state components.

## The Legacy Stack: EmulatorHelper and DefaultEmulator

The legacy stack, located in `ghidra.app.emulator`, provides a simplified façade for quick scripts and unit tests. While marked `@Deprecated`, it remains in use throughout existing Ghidra scripts.

### Core Components

**`EmulatorHelper`** acts as the primary façade. According to the source in [`Ghidra/Framework/Emulation/src/main/java/ghidra/app/emulator/EmulatorHelper.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/Ghidra/Framework/Emulation/src/main/java/ghidra/app/emulator/EmulatorHelper.java), it wraps a `DefaultEmulator` instance and implements `MemoryFaultHandler` and `EmulatorConfiguration`. It exposes convenience methods for register read/write, memory access, breakpoint management, and disassembly.

**`DefaultEmulator`** (in [`DefaultEmulator.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/DefaultEmulator.java)) is the concrete implementation of the `Emulator` interface. It constructs the low-level `Emulate` engine, a `FilteredMemoryState` with page-overlay memory banks for each address space, and a `BreakTableCallBack` for breakpoint handling.

**`Emulate`** (in [`ghidra.pcode.emulate.Emulate.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/ghidra.pcode.emulate.Emulate.java)) serves as the core p-code interpreter. It decodes the current instruction, generates the corresponding p-code operations, and executes them via `PcodeExecutor`.

### Execution Flow

1. **Construction**: `new EmulatorHelper(program)` instantiates a `DefaultEmulator` using the helper's configuration.
2. **State Initialization**: `DefaultEmulator` builds a `FilteredMemoryState` and `RegisterState` (wrapped as `FilteredRegisterBank`) for each address space.
3. **Program Counter Setup**: The PC register name is obtained from the language definition (`cfg.getProgramCounterName()`), and the initial value is written.
4. **Execution**: `EmulatorHelper.run()` invokes `DefaultEmulator.executeInstruction`, which calls `Emulate.decodeAndExecute`. This method decodes the instruction, generates p-code, and executes it, updating the PC and context registers.
5. **Event Handling**: Memory faults route to the `MemoryFaultHandler` interface, while `CALL_OTHER` p-code operations trigger registered callbacks via `registerCallOtherCallback`.

## The Modern Stack: PcodeEmulator Architecture

The modern emulation framework, located in `ghidra.pcode.emu`, replaces the monolithic legacy design with a modular, generic hierarchy optimized for extension and multi-threaded analysis.

### Core Hierarchy

**`PcodeEmulator`** (in [`PcodeEmulator.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/PcodeEmulator.java)) is the recommended entry point. As a concrete subclass of `AbstractPcodeMachine<byte[]>`, it instantiates `BytesPcodeArithmetic` for concrete byte operations, a shared `BytesPcodeExecutorState` for memory, and one or more `BytesPcodeThread` instances.

**`AbstractPcodeMachine<T>`** (in [`AbstractPcodeMachine.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/AbstractPcodeMachine.java)) provides the generic core engine. It manages thread lifecycles, shared state composition, user-op libraries (`PcodeUseropLibrary`), and the `inject` API for p-code injection.

**`BytesPcodeThread`** (in [`BytesPcodeThread.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/BytesPcodeThread.java)) implements `PcodeThread<byte[]>`. Each thread owns an `InstructionDecoder` and `PcodeExecutor` that operate on the shared `BytesPcodeExecutorState`.

**`BytesPcodeExecutorState`** (in [`BytesPcodeExecutorState.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/BytesPcodeExecutorState.java)) implements `PcodeExecutorState<byte[]>`, providing read/write access to shared memory banks and thread-local registers.

**`BytesPcodeArithmetic`** performs concrete arithmetic operations (addition, shifts, bitwise logic) on byte arrays, automatically selected based on the target language's endianness.

**`PcodeEmulationCallbacks<T>`** (in [`PcodeEmulationCallbacks.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/PcodeEmulationCallbacks.java)) offers optional hooks for memory events, system calls, thread start/stop, and `CALL_OTHER` operations. The default implementation supplies no-op behavior.

### Execution Flow

1. **Instantiation**: `new PcodeEmulator(language)` constructs the arithmetic engine, allocates the shared `BytesPcodeExecutorState`, and creates the initial thread.
2. **State Population**: Analysts populate memory via `emu.getSharedState().setChunk()` and initialize registers through `emu.getThread(0).setProgramCounter()` or `setValue()`.
3. **Injection (Optional)**: `emu.inject(addr, "CALL_OTHER my_syscall")` stubs library functions or system calls by injecting p-code at specific addresses.
4. **Stepwise Execution**: `emu.getThread(0).step(monitor)` executes a single instruction:
   - The thread's `InstructionDecoder` fetches bytes and generates a `PcodeProgram`.
   - `PcodeExecutor` walks the p-code ops, invoking `BytesPcodeArithmetic` for calculations and `BytesPcodeExecutorState` for memory/register access.
   - Context registers propagate automatically (flowing bits only).
5. **Callback Invocation**: At memory accesses, breakpoints, or `CALL_OTHER` operations, the framework invokes the registered `PcodeEmulationCallbacks`, enabling simulation of OS services or custom instrumentation.

## Practical Implementation Examples

### Legacy Approach: Quick Scripting with EmulatorHelper

Use this approach only for maintaining existing scripts. The helper provides a high-level API but lacks the extensibility of the modern stack.

```java
import ghidra.app.emulator.EmulatorHelper;
import ghidra.util.task.TaskMonitor;
import java.util.Arrays;

// Load a program (assume `program` is already opened)
EmulatorHelper emu = new EmulatorHelper(program);

// Initialize registers
emu.writeRegister("R0", 0x1000L);

// Set breakpoint at 0x401000
emu.setBreakpoint(emu.genAddress("0x401000"));

// Run until breakpoint or error
emu.run(emu.getPCRegister(), null, TaskMonitor.DUMMY);

// Read results
byte[] data = emu.readMemory(emu.genAddress("0x401010"), 8);
System.out.printf("Memory @401010: %s%n", Arrays.toString(data));

```

*Key classes*: `EmulatorHelper`, `DefaultEmulator`  
*Source*: [`Ghidra/Framework/Emulation/src/main/java/ghidra/app/emulator/EmulatorHelper.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/Ghidra/Framework/Emulation/src/main/java/ghidra/app/emulator/EmulatorHelper.java)

### Modern Approach: Concrete Byte Emulation

This is the recommended approach for new development, offering precise control over memory layout and execution.

```java
import ghidra.pcode.emu.PcodeEmulator;
import ghidra.pcode.exec.PcodeExecutorState;
import ghidra.program.model.lang.Language;
import ghidra.util.task.TaskMonitor;

// 1. Obtain the language (e.g., x86:LE:64:default)
Language lang = program.getLanguage();

// 2. Create emulator
PcodeEmulator emulator = new PcodeEmulator(lang);

// 3. Load program bytes into shared memory
PcodeExecutorState<byte[]> sharedState = emulator.getSharedState();
byte[] progBytes = program.getMemory().getBytes(startAddr, length);
sharedState.setChunk(progBytes, startAddr.getAddressSpace(),
                     startAddr.getOffset(), length, false);

// 4. Initialize program counter
emulator.getThread(0).setProgramCounter(startAddr.getOffset());

// 5. Execute instruction-by-instruction
TaskMonitor monitor = TaskMonitor.DUMMY;
boolean more = emulator.getThread(0).step(monitor);
while (more) {
    more = emulator.getThread(0).step(monitor);
}
System.out.println("Emulation finished at: " + 
    emulator.getThread(0).getProgramCounter());

```

*Key classes*: `PcodeEmulator`, `BytesPcodeThread`, `BytesPcodeExecutorState`  
*Source*: [`Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/PcodeEmulator.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/PcodeEmulator.java)

### Advanced: Injecting System Call Handlers

Override `PcodeEmulationCallbacks` to intercept `CALL_OTHER` operations and simulate system services.

```java
import ghidra.pcode.emu.PcodeEmulationCallbacks;
import ghidra.pcode.emu.PcodeThread;
import ghidra.program.model.address.Address;
import java.util.List;

PcodeEmulationCallbacks<byte[]> callbacks = new PcodeEmulationCallbacks<>() {
    @Override
    public boolean executeCallOther(PcodeThread<byte[]> thread,
                                    Address addr, String useropName,
                                    List<byte[]> args, List<byte[]> out) {
        if ("my_syscall".equals(useropName)) {
            // Return 0 in R0
            thread.getExecutorState().setValue("R0", new byte[]{0});
            return true; // Handled
        }
        return false; // Delegate to default
    }
};

PcodeEmulator emu = new PcodeEmulator(lang, callbacks);
emu.inject(syscallAddr, "CALL_OTHER my_syscall");

```

*Source*: [`Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/PcodeEmulationCallbacks.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/PcodeEmulationCallbacks.java)

## Summary

- **Ghidra's emulation framework** operates by translating machine code to p-code, then interpreting those operations through configurable engines.
- **Two stacks coexist**: The legacy `EmulatorHelper`/`DefaultEmulator` (deprecated) offers convenience for simple scripts, while `PcodeEmulator` provides the modern, extensible architecture.
- **Modern architecture** uses generic types (`PcodeMachine<T>`), allowing analysts to swap `BytesPcodeArithmetic` for symbolic or other value representations.
- **Key extension points** include `PcodeEmulationCallbacks` for event interception and the `inject` API for stubbing functions.
- **Source locations**: Legacy classes reside in `ghidra.app.emulator`, while modern implementations are in `ghidra.pcode.emu`.

## Frequently Asked Questions

### What is the difference between `EmulatorHelper` and `PcodeEmulator`?

`EmulatorHelper` (in `ghidra.app.emulator`) provides a high-level, script-friendly API that hides the underlying p-code details but is deprecated and less flexible. `PcodeEmulator` (in `ghidra.pcode.emu`) exposes the full generic `PcodeMachine` architecture, supporting custom arithmetic types, multi-threading, and precise memory state control.

### How does Ghidra's emulator handle memory faults?

In the legacy stack, `DefaultEmulator` routes undefined-address or uninitialized-read events to the `MemoryFaultHandler` interface implemented by `EmulatorHelper`. In the modern stack, memory access violations and events are handled through `PcodeEmulationCallbacks`, where methods like `onMemoryRead()` or `onMemoryWrite()` can intercept or simulate hardware behavior.

### Can the emulation framework support symbolic execution?

Yes. Because `AbstractPcodeMachine<T>` is generic, analysts can replace the concrete `byte[]` type with symbolic expression types. By implementing custom `PcodeArithmetic<T>` and `PcodeExecutorState<T>` interfaces, the framework supports symbolic execution, taint analysis, or other abstract interpretation schemes without modifying the core p-code interpreter.

### Where are the main emulation classes located in the Ghidra source tree?

The legacy emulation API resides in `Ghidra/Framework/Emulation/src/main/java/ghidra/app/emulator/` (classes like [`EmulatorHelper.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/EmulatorHelper.java) and [`DefaultEmulator.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/DefaultEmulator.java)). The modern framework is located in `Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/` (classes like [`PcodeEmulator.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/PcodeEmulator.java), [`AbstractPcodeMachine.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/AbstractPcodeMachine.java), and [`BytesPcodeThread.java`](https://github.com/NationalSecurityAgency/ghidra/blob/main/BytesPcodeThread.java)).