How to Debug shadPS4-Emu Runtime Errors: A Complete Technical Guide

Enable synchronous logging in config.toml, run shadPS4 under gdb or Visual Studio, and use the built-in ImGui devtools (Ctrl+F10) to capture frame dumps and inspect GPU state when runtime errors occur.

shadPS4 is a PlayStation 4 emulator with a layered architecture separating the core emulation engine, Vulkan renderer, and ImGui-based developer UI. When debugging shadPS4-emu runtime errors, developers must correlate logs from src/common/logging/log.h, assertions from src/common/assert.h, and real-time GPU state from the devtools overlay.

Understanding the Logging Infrastructure

shadPS4 uses a centralized logging system that supports both asynchronous (default) and synchronous modes. The logging macros, assertion handlers, and debug state singleton work together to provide a complete picture of runtime behavior.

Core Logging Macros

The primary logging interface is defined in src/common/logging/log.h. This file provides severity-based macros (LOG_CRITICAL, LOG_ERROR, LOG_WARNING, LOG_INFO, LOG_DEBUG) that automatically capture source file and line information.

// Example: Logging a critical Vulkan error
LOG_CRITICAL(Render_Vulkan, "Failed to allocate image with error {}", vkResult);

Each macro expands to LOG_GENERIC with the appropriate Class:: and Level:: enum values, ensuring consistent formatting across the codebase.

Assertion Handling

For fatal error conditions, src/common/assert.h provides ASSERT and ASSERT_MSG macros. When a condition fails, these call assert_fail_impl() and emit a LOG_CRITICAL message before aborting.

#include "common/assert.h"

void InitGraphics() {
    bool ok = InitializeVulkanDevice();
    ASSERT_MSG(ok, "Vulkan device initialization failed");
}

Debug State Singleton

The DebugState singleton in src/core/debug_state.h maintains per-frame debug data including frame counters, GPU dump requests, and message pop-ups. This class bridges the logging system and the ImGui devtools UI.

// Request a frame dump from code (useful for automated tests)
DebugState.RequestFrameDump(1);  // Capture the next frame

Configuration via config.toml

Logging behavior is controlled through <executable>/user/config.toml. Key settings include:

  • logType = "sync" – Forces synchronous logging for deterministic output order
  • logFilter = "*:Debug" – Sets verbosity level (e.g., Render.Vulkan:Error for specific subsystems)

The synchronous mode is essential when debugging race conditions or crashes that occur near the end of the log, as the default asynchronous mode may interleave messages from different threads.

Using the ImGui Developer Tools

shadPS4 includes a comprehensive developer interface implemented in src/core/devtools/ using ImGui. This overlay renders on top of the Vulkan output and provides real-time inspection capabilities.

Accessing the Debug UI

Press Ctrl+F10 (bound to "Video Debug Info" by default) to toggle the devtools overlay. The UI state is managed by the DebugState singleton and implemented in src/core/devtools/layer.cpp.

You can also enable the UI programmatically:

// Force enable devtools menu bar
DebugState.IsShowingDebugMenuBar() = true;

GPU Tools and Frame Dumps

The GPU Tools menu provides critical debugging capabilities:

  • Dump frames – Captures command buffers, register state, and shader binaries to user/dumps/
  • Frame Graph – Visual timeline of GPU queues (DCB, CCB, ACB) and their submit numbers (src/core/devtools/widget/frame_graph.cpp)
  • Pause in Submit – Breaks execution at the next GPU command submission

Requesting a frame dump via the UI calls DebugState.RequestFrameDump(), which signals the renderer to capture the next frame's complete GPU state.

Shader Debugging and Memory Inspection

For graphics-related runtime errors:

Step-by-Step Workflow to Debug Runtime Errors

Follow this systematic approach when investigating shadPS4 crashes or incorrect behavior:

  1. Enable deterministic logging – Edit <exe>/user/config.toml:

    logType = "sync"
    logFilter = "*:Debug"
  2. Run under a native debugger:

    • Linux/macOS: gdb --args ./shadps4 <game_path>
    • Windows: Open in Visual Studio with x64-Clang-Debug configuration and press F5
  3. Reproduce the crash – The debugger breaks on unhandled exceptions. For ASSERT failures, execution stops at assert_fail_impl() with the call stack pointing to the source (e.g., src/video_core/renderer_vulkan/vk_swapchain.cpp:121).

  4. Inspect the log – Check the console or user/log/shad_log.txt. The most recent LOG_CRITICAL or LOG_ERROR entry explains the failure. Filter noise by adjusting logFilter (e.g., Render.Vulkan:Error).

  5. Use the devtools UI – Press Ctrl+F10 and navigate to:

    • GPU Tools → Dump frames (Ctrl+Alt+F9) to capture GPU state
    • Shader List to verify failed shader compilation
    • Memory Map to check for corrupted allocations
  6. Optional: Enable RenderDoc – Set rdocEnable = true in config.toml. The emulator launches RenderDoc automatically on the next frame for detailed Vulkan command inspection.

  7. Analyze the stack trace – Focus on calls originating in src/core/ or src/video_core/ rather than game code. These indicate emulator bugs requiring patches.

  8. Apply a fix – Common solutions include:

    • Vulkan resource states – Check vk::Result handling in src/video_core/renderer_vulkan/*.cpp
    • Shader compilation – Verify CollectShader in vk_pipeline_cache.cpp
    • Memory mapping – Check Memory::Allocate in src/core/memory.cpp
  9. Re-run the test – Repeat steps 1-7. Resolution is confirmed when the emulator runs without crashes and logs contain no CRITICAL entries.

Configuration Knobs for Advanced Debugging

Fine-tune shadPS4's behavior using these config.toml settings documented in src/documents/Debugging/Debugging.md:

Setting Value Effect
logType "sync" Forces synchronous logging for deterministic output order
logFilter "*:Debug" or "Render.Vulkan:Error" Controls verbosity per subsystem
rdocEnable true Auto-launches RenderDoc for Vulkan debugging
vkValidation true Enables Vulkan validation layers for detailed error messages
shouldDumpShaders true Writes SPIR-V binaries to user/shader/dumps

These settings can also be adjusted at runtime via GPU Tools → Options in the devtools UI.

Platform-Specific Debugger Setup

Linux and macOS (gdb/LLDB)

Attach to shadPS4 using standard Unix debuggers:


# GDB

gdb --args ./shadps4 /path/to/game/eboot.bin

# LLDB (macOS)

lldb -- ./shadps4 /path/to/game/eboot.bin

Set breakpoints on critical functions:

break assert_fail_impl
break vk::Device::createImage

Windows (Visual Studio)

  1. Open shadPS4.sln in Visual Studio 2022
  2. Set configuration to x64-Clang-Debug (or x64-Debug)
  3. Set startup project to shadps4
  4. Press F5 to launch with debugging

Configure exception handling to ignore intentional guard exceptions used by the emulator's memory management (as noted in the Debugging guide).

Summary

  • Enable synchronous logging via logType = "sync" in config.toml to ensure ordered log output during crashes.
  • Run under gdb, LLDB, or Visual Studio to catch assertions and exceptions at assert_fail_impl() and inspect call stacks.
  • Use the ImGui devtools (Ctrl+F10) to access GPU frame dumps, shader lists, and memory maps in real-time.
  • Configure advanced options like rdocEnable and vkValidation for Vulkan-specific debugging with RenderDoc and validation layers.
  • Focus on emulator code in src/core/ and src/video_core/ when analyzing stack traces to identify bugs requiring patches.

Frequently Asked Questions

How do I enable synchronous logging in shadPS4?

Edit the config.toml file located in <executable>/user/config.toml and set logType = "sync". This forces the logging system defined in src/common/logging/log.h to write messages immediately rather than buffering them asynchronously, ensuring that log output appears in the correct chronological order when debugging race conditions or crashes.

What is the keyboard shortcut to open the devtools UI?

Press Ctrl+F10 to toggle the ImGui-based developer overlay implemented in src/core/devtools/layer.cpp. This shortcut, bound to "Video Debug Info" by default, opens the debug menu bar where you can access GPU Tools, Shader Lists, Memory Maps, and Frame Graphs without restarting the emulator.

How can I capture a GPU frame dump when a runtime error occurs?

Open the devtools UI (Ctrl+F10), navigate to GPU Tools, and select Dump frames (or press Ctrl+Alt+F9). This triggers DebugState.RequestFrameDump() defined in src/core/debug_state.h, which captures the next frame's command buffers, register state, and shader binaries to user/dumps/. You can also call DebugState.RequestFrameDump(1) programmatically from C++ code.

Which debugger should I use for shadPS4 on Windows?

Use Visual Studio 2022 with the x64-Clang-Debug or x64-Debug configuration. Set the shadps4 project as the startup project and press F5 to launch. Visual Studio integrates seamlessly with the emulator's assertion handling in src/common/assert.h and allows you to inspect Vulkan resource states in src/video_core/renderer_vulkan/ when runtime errors trigger assert_fail_impl().

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →