# How SharpEmu Handles CPU Traps and Memory Faults in PS5 Emulation

> Discover how SharpEmu handles CPU traps and memory faults. Get detailed diagnostics like opcode previews, disassembly, and control-transfer history to simplify debugging guest binaries.

- Repository: [Berk/sharpemu](https://github.com/par274/sharpemu)
- Tags: internals
- Published: 2026-07-16

---

**SharpEmu detects CPU traps and memory faults in the runtime loop of [`SharpEmu.Core/Runtime/SharpEmuRuntime.cs`](https://github.com/par274/sharpemu/blob/main/SharpEmu.Core/Runtime/SharpEmuRuntime.cs), enriching raw error codes with detailed diagnostics including opcode previews, disassembly, import-stub mappings, and control-transfer history to simplify debugging of guest binaries.**

The `par274/sharpemu` project implements a PlayStation 5 emulator that requires precise handling of CPU traps and memory faults to diagnose misbehaving guest code. When the emulation engine encounters invalid instructions or inaccessible memory, the runtime transforms low-level error signals into human-readable diagnostic traces that reveal exactly what went wrong inside the virtual CPU.

## The Central Runtime Loop

After dispatching the guest entry point, `SharpEmuRuntime` checks the result code returned by the CPU dispatcher. If the dispatcher reports `ORBIS_GEN2_ERROR_CPU_TRAP` or `ORBIS_GEN2_ERROR_MEMORY_FAULT`, the runtime immediately constructs a comprehensive diagnostic snapshot by reading `_cpuDispatcher.LastTrapInfo` or `_cpuDispatcher.LastMemoryFaultInfo`.

## Handling CPU Traps

When the dispatcher returns `ORBIS_GEN2_ERROR_CPU_TRAP`, SharpEmu extracts trap metadata from `_cpuDispatcher.LastTrapInfo` and executes a seven-step diagnostic pipeline (lines 194-242 of [`SharpEmu.Core/Runtime/SharpEmuRuntime.cs`](https://github.com/par274/sharpemu/blob/main/SharpEmu.Core/Runtime/SharpEmuRuntime.cs)).

### Opcode Preview and Disassembly

First, the runtime calls `ReadOpcodePreview` to fetch up to 8 bytes at the faulting RIP (instruction pointer), providing the raw instruction bytes that triggered the trap. If `EnableDisasmDiagnostics` is enabled in the execution options, the runtime invokes `TryDecodeInstructionAt` using the ICE decoder ([`IcedDecoder.cs`](https://github.com/par274/sharpemu/blob/main/IcedDecoder.cs)) to translate the raw bytes into a human-readable instruction mnemonic.

### Special-Case Pattern Detection

The runtime scans for the `UD2` illegal-instruction pattern (`0F 0B`). When detected, it appends `trap=ud2` to the diagnostic string, immediately flagging intentional illegal instruction traps. The system also calls `IsInvalidLongModeOpcode` to detect instructions that are illegal in x86-64 long mode, helping identify compatibility issues with the guest binary's architecture assumptions.

### SELF Image and Import-Stub Resolution

When a trap occurs at address 0 with opcode `0xCC` inside a self-encrypted ELF (SELF), the runtime adds a specific hint indicating the image may be encrypted or unresolved. Additionally, the runtime looks up the faulting RIP in the active import-stub table to determine which NID (library function identifier) caused the trap, revealing when guest code attempts to call unimplemented or unresolved imported functions.

### Control-Transfer Context

Finally, if the CPU dispatcher recorded a recent control-transfer (branch, call, or jump), the diagnostic includes the source address, destination address, opcode, and decoded instruction that led to the trap, providing execution flow context.

The assembled diagnostic follows this format:

```text
CPU trap at RIP=0xXXXXXXXXXXXX, opcode=0xYY, bytes=…, inst=…, import_stubs=…, trap=ud2, hint=…, rip_stub=…, last_transfer=…

```

## Handling Memory Faults

For `ORBIS_GEN2_ERROR_MEMORY_FAULT` results, the runtime reads `_cpuDispatcher.LastMemoryFaultInfo` and constructs a similar diagnostic (lines 61-96). The memory fault diagnostic includes:

1. **Opcode Information** – The first byte of the faulting instruction or its decoded mnemonic if available.
2. **Access Type** – Whether the operation was a read or write, along with the faulting guest virtual address.
3. **Access Size** – The size of the memory access in bytes (1, 2, 4, or 8).
4. **Import-Stub Mapping** – Any NID mapped at the faulting RIP, indicating if the fault occurred during an import resolution attempt.
5. **Control-Transfer History** – The most recent branch or call that preceded the fault, identical to the trap handling context.

Like CPU traps, this information is stored in `LastExecutionDiagnostics` as a formatted string ready for logging or display.

## Configuring and Querying Diagnostics

Developers can programmatically access these diagnostics after a run fails.

### Querying the Last Diagnostic

```csharp
var runtime = SharpEmuRuntime.CreateDefault();
var result = runtime.Run("path/to/eboot.bin");

// If the guest crashed, the diagnostic is ready:
if (result != OrbisGen2Result.ORBIS_GEN2_OK)
{
    Console.WriteLine(runtime.LastExecutionDiagnostics);
}

```

### Enabling Disassembly Diagnostics

```csharp
var options = new CpuExecutionOptions
{
    EnableDisasmDiagnostics = true,   // <-- turn on instruction decoding
    CpuEngine = CpuEngineType.Amd64, // choose the backend you prefer
};
var runtime = new SharpEmuRuntime(..., options);

```

### Detecting Specific Trap Types

```csharp
if (runtime.LastExecutionDiagnostics?.Contains("trap=ud2") == true)
{
    Console.WriteLine("Encountered an illegal instruction (UD2).");
}

```

## Key Implementation Files

The fault handling system spans several core components:

- **[`SharpEmu.Core/Runtime/SharpEmuRuntime.cs`](https://github.com/par274/sharpemu/blob/main/SharpEmu.Core/Runtime/SharpEmuRuntime.cs)** – The central runtime that orchestrates CPU trap and memory fault detection, building the diagnostic strings stored in `LastExecutionDiagnostics`.

- **[`SharpEmu.Core/Cpu/ICpuDispatcher.cs`](https://github.com/par274/sharpemu/blob/main/SharpEmu.Core/Cpu/ICpuDispatcher.cs)** – Defines the interface providing `LastTrapInfo` and `LastMemoryFaultInfo` properties that expose raw fault data from the CPU backend to the runtime.

- **[`SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs`](https://github.com/par274/sharpemu/blob/main/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs)** – Implements the low-level CPU dispatch that raises `ORBIS_GEN2_ERROR_CPU_TRAP` and `ORBIS_GEN2_ERROR_MEMORY_FAULT` when guest execution fails.

- **[`SharpEmu.Core/Memory/IVirtualMemory.cs`](https://github.com/par274/sharpemu/blob/main/SharpEmu.Core/Memory/IVirtualMemory.cs)** – Abstracts guest memory access, used by the diagnostic system to read opcode previews and verify fault addresses.

- **[`SharpEmu.Core/Cpu/Disasm/IcedDecoder.cs`](https://github.com/par274/sharpemu/blob/main/SharpEmu.Core/Cpu/Disasm/IcedDecoder.cs)** – Wraps the ICE decoder library to convert raw instruction bytes into `DecodedInst` objects for human-readable disassembly output.

## Summary

- SharpEmu intercepts CPU traps and memory faults in [`SharpEmu.Core/Runtime/SharpEmuRuntime.cs`](https://github.com/par274/sharpemu/blob/main/SharpEmu.Core/Runtime/SharpEmuRuntime.cs) by checking dispatcher result codes after guest execution.
- CPU trap diagnostics include opcode previews, optional ICE-based disassembly, UD2 detection, long-mode validation, SELF encryption hints, import-stub NID resolution, and control-transfer history.
- Memory fault diagnostics specify the access type, size, faulting address, opcode bytes, import-stub context, and recent control-transfer information.
- Both fault types store their human-readable output in `LastExecutionDiagnostics`, accessible immediately after a failed `Run()` call.
- The system supports `EnableDisasmDiagnostics` to toggle instruction decoding, allowing developers to balance diagnostic detail against performance.

## Frequently Asked Questions

### How does SharpEmu distinguish between a CPU trap and a memory fault?

SharpEmu distinguishes these conditions by examining the `OrbisGen2Result` returned by the CPU dispatcher. A return value of `ORBIS_GEN2_ERROR_CPU_TRAP` triggers the trap diagnostic pipeline, while `ORBIS_GEN2_ERROR_MEMORY_FAULT` initiates memory fault analysis. Each path extracts specific metadata from either `LastTrapInfo` or `LastMemoryFaultInfo` to build the appropriate diagnostic context.

### What is the UD2 pattern detection used for?

The UD2 pattern (`0F 0B`) detection identifies intentional illegal instruction traps that compilers or packers insert into PlayStation 5 binaries. When SharpEmu encounters this opcode, it appends `trap=ud2` to the diagnostic string, alerting developers that the guest software deliberately triggered an invalid instruction exception, often for debugging or anti-tampering purposes.

### Can I enable detailed diagnostics without disassembly to improve performance?

Yes. You can instantiate `SharpEmuRuntime` with `CpuExecutionOptions` where `EnableDisasmDiagnostics` is set to `false`. This configuration still provides opcode byte previews, fault addresses, import-stub mappings, and control-transfer history, but skips the expensive ICE decoder step, reducing overhead while maintaining essential debugging information.

### Where does SharpEmu store the diagnostic output after a fault occurs?

The runtime stores the complete diagnostic string in the `LastExecutionDiagnostics` property of the `SharpEmuRuntime` instance. This property is populated immediately after the dispatcher returns an error code, allowing you to inspect the fault details programmatically using `runtime.LastExecutionDiagnostics` following a call to `Run()`.