Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/eden-emulator/mirror/llms.txt

Use this file to discover all available pages before exploring further.

Effective debugging in Eden spans several layers: issue reporting with proper logs, host-side debugger configuration, guest-side GDB stubs, graphics debugging with RenderDoc, and structured PR testing. This page covers all of them.

Accessing debug logs

Debug logs are the first thing to include in any bug report.
  • Desktop: Go to General → Debug → Open Log Location.
  • Android: Use the Share Debug Logs option.
Logs must be included in all bug reports except certain UI-only issues — though they are still strongly recommended even then.

Issue reports

When reporting a bug, include backtraces, debug logs, or both depending on the issue type.

Graphics bugs

If the issue is graphical (mismatched colors, vertex explosions, flickering, etc.), enable Graphics Debugging before reproducing the problem:
  • Desktop: General → Debug → Graphics Debugging
  • Android: Advanced Settings → Debug
Desktop users may also need to install the Vulkan Validation Layers:
Install the Vulkan SDK. The validation layers are bundled with it.
Once enabled, run the problematic game and capture the log. Note that graphics debugging can significantly reduce performance on weak hardware.

Debug builds and CCache

When building for debugging, use the Debug CMake build type:
cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build -- -j$(nproc)
CCache may cache stale results when switching between Debug and Release build types. If you see unexpected behavior after a build type switch, clear the CCache cache with ccache --clear before rebuilding.

Debugging host code

When debugging Eden itself (not the guest Switch application), signal handling needs adjusting so the debugger does not stop on SIGSEGV, which Eden uses internally.
handle SIGSEGV nostop pass

Debugging guest code with GDB

To debug the Switch application running inside the emulator, you need a GDB build targeting AArch64.

Installing AArch64 GDB

sudo pacman -Syu aarch64-linux-gnu-gdb

Launching the GDB stub

Run eden-cli with the debug flag, substituting your actual config path and game path:
./build/bin/eden-cli \
  -c <path-to-config-file> \
  -d \
  -g <path-to-game>
Alternatively, enable GDB Stub in General → Debug in the desktop UI. The stub listens on port 6543. Then connect from AArch64 GDB:
target remote localhost:6543
Type c to continue. If the emulator crashes, run bt (backtrace) and layout asm to inspect the failure.

GDB cheatsheet

CommandDescription
btPrint backtrace
p <expr>Print a variable (p/x for hex)
display <expr>Display a variable after every step
frame <n>Switch to frame n from backtrace
info threadsList all active threads
thread <n>Switch to thread n
layout asmShow disassembly TUI
CommandDescription
br <expr>Set breakpoint at expression or address
deleteDelete all breakpoints
catch throwBreak at any C++ exception throw (also br __cxa_throw)
br _mesa_errorBreak on Mesa errors (set MESA_DEBUG=1 first)
CommandDescription
mo helpList available monitor commands
mo get infoPrint emulator info
mo get fastmemPrint fast-memory mapping info
mo get mappingsPrint memory mappings
Expressions accept variable names, numeric literals (1234), pointer dereferences (*var), and computed expressions (*(1 + var)). For full reference, run info gdb or read the GDB man page.

RenderDoc — graphics debugging checklist

RenderDoc is a free, cross-platform graphics API debugger with Vulkan support. Before using it to chase black screen issues, confirm there are no validation errors — any validation error means behavior is undefined. When debugging a black screen, work through this checklist:
  • Draw call counts are non-zero (and, if rendering many triangles, not just 3).
  • Vertex buffers are bound.
  • Vertex attributes match the expected size and offset for each attribute.
  • Viewport: x=0, y=0, width and height match screen dimensions, minDepth=0, maxDepth=1, NDC depth range is 0, 1.
  • Fill mode: solid (unless wireframe is intentional).
  • Cull mode: back or none, as expected.
  • Winding direction: typically counter-clockwise (CCW).
  • Scissor region matches the viewport x, y, width, height.
  • Push constants and descriptor data contain correct values.
  • Model, view, and projection matrices are uploaded correctly.
  • Blend state is correct.
  • Depth state is enabled with function set to Less than or Equal.
  • Swapchain images are bound when rendering to the swapchain.
  • The image being rendered to is the same image being presented.
The WhereIsMyDraw RenderDoc extension automates many of the manual checklist steps above.

Testing pull requests

When testing a PR, always compare against the master branch it was based on to distinguish regressions from pre-existing bugs.
Before testing, delete the shader cache and use matching settings on both the PR build and the master build. A leftover shader cache can make a PR look like it introduced a regression when it did not.

What to test

  • Test PRs relevant to your platform. If a PR is marked [linux], test on Linux; [android] means Android; NCE means Android and Linux ARM64.
  • Skip PRs marked [docs] or trivial cosmetic changes unless you specifically want to test them.
  • WIP PRs do not need testing unless the author explicitly asks.

Testing checklist

For regressions or bugs from a PR or commit:
  • Does the issue occur on master?
    • If yes, does it occur on the previous stable release?
      • If yes, does it occur on older releases? (Some bugs predate Eden.)
      • If no, bisect between the previous stable release and the current master HEAD.
    • If no, the PR likely introduced it — bisect within the PR’s commits.
If a bug is sporadic, run multiple passes. A bug that triggers 1 in 4 runs requires at least 4 runs per bisect step to have a reasonable chance of reproducing.

Bisecting

Git bisect uses binary search to find the commit that introduced a regression:
git bisect start
git bisect bad HEAD          # current state is broken
git bisect good <known-good-commit>
# Git checks out the midpoint — test it, then:
git bisect good   # or: git bisect bad
# Repeat until git identifies the faulty commit
git bisect reset

Reporting findings

Always state explicitly whether the behavior was also present on master:
Bad result: tested on based master — issue not present. Likely regression introduced by this PR.
Good result: tested on based master — issue already present. Not a regression.
Include relevant debug logs with every report.

Adding boolean settings toggles

This section is intended for developers only. For temporary testing flags, use debug knobs instead.
To add a permanent boolean setting across both the Qt (desktop) and Kotlin (Android) frontends:
1

Declare the setting in common/settings.h

SwitchableSetting<bool> your_setting_name{
    linkage, false, "your_setting_name", Category::RendererExtensions
};
Common categories include Category::Renderer, Category::RendererAdvanced, Category::RendererExtensions, Category::System, and Category::Core. Change false to true only if the setting should be on by default.
2

Register the translation (Qt)

In src/qt_common/config/shared_translation.cpp:
INSERT(Settings,
       your_setting_name,
       tr("Your Setting Display Name"),
       tr("Detailed description of what this setting does.\n"
          "You can use multiple lines.\n"
          "Explain any caveats or requirements."));
3

Add the enum entry (Android)

In BooleanSetting.kt:
RENDERER_YOUR_SETTING_NAME("your_setting_name"),
4

Add to the Android settings item list

In SettingsItem.kt:
put(
    SwitchSetting(
        BooleanSetting.RENDERER_YOUR_SETTING_NAME,
        titleId = R.string.your_setting_name,
        descriptionId = R.string.your_setting_name_description
    )
)
5

Place it in the right section (Android)

In SettingsFragmentPresenter.kt, add within the correct category block:
add(BooleanSetting.RENDERER_YOUR_SETTING_NAME.key)
Order matters — settings appear in the UI in the order they are added.
6

Add localized strings (Android)

In src/android/app/src/main/res/values/strings.xml:
<string name="your_setting_name">Your Setting Display Name</string>
<string name="your_setting_name_description">Detailed description. Explain caveats and requirements.</string>
7

Read the value in C++

const bool your_value = Settings::values.your_setting_name.GetValue();

if (your_value) {
    // Do something when enabled
}

Debug knobs

Debug knobs provide a lightweight way to gate temporary debug behavior without deploying a full settings toggle. The debug_knobs setting is a 16-bit integer (0–65535) used as a bitmask — each of the 16 bits independently enables a debug feature. This is the preferred approach for features that are only needed during development and will be removed before merging.

Accessing knobs in code

#include "common/settings.h"

// Check if bit 0 is set
bool feature_enabled = Settings::getDebugKnobAt(0);

// Check if bit 15 is set
bool another_feature = Settings::getDebugKnobAt(15);

Setting knob values

InterfaceLocation
DesktopDebug tab → “Debug knobs” spinbox (0–65535)
AndroidDebug section → integer setting
Config fileSet debug_knobs directly
To enable specific bits, calculate the decimal value from the bit positions:
GoalValue
Enable bit 0 only1 (2⁰)
Enable bit 1 only2 (2¹)
Enable bits 0 and 13 (2⁰ + 2¹)
Enable bit 1532768 (2¹⁵)

Terminology

Debug knobs are zero-based. When communicating about them:
  • Use plural “knobs” when referring to the setting value as a whole: knobs=3 means knob0 and knob1 are enabled.
  • Use singular “knob” with an index when referring to a specific bit: knob0, knob1, or “knobs 0 and 2”.
This avoids the common confusion between “knob 1” (the index) and “knobs=1” (the value that enables only bit 0).

Code examples

void SomeFunction() {
    if (Settings::getDebugKnobAt(0)) {
        LOG_DEBUG(Common, "Debug feature 0 is enabled");
    }

    if (Settings::getDebugKnobAt(1)) {
        LOG_DEBUG(Common, "Debug feature 1 is enabled");
    }
}
bool UseOptimizedPath() {
    // Skip optimization if debug bit 2 is set
    return !Settings::getDebugKnobAt(2);
}
void ExperimentalFeature() {
    static constexpr u8 EXPERIMENTAL_FEATURE_BIT = 3;

    if (!Settings::getDebugKnobAt(EXPERIMENTAL_FEATURE_BIT)) {
        StableImplementation();
        return;
    }

    ExperimentalImplementation();
}
Knobs must be unwired (removed from code) before a PR is submitted for merge. They are intended exclusively for development-phase testing.

Native application development

When developing homebrew or native Switch applications and testing them under Eden, two debug settings are particularly useful:
  • Standard key prefix — Redirects the key manager to a file other than prod.keys. For example, setting this to other makes Eden look for other.keys. Useful for testing multiple key sets without overwriting your main keys.
  • Changing serial — Sets a debug serial and battery number. Only the leading digits (excluding the last) are used. Region settings influence the generated serial, which corresponds to a non-OLED/non-Lite console.

Build docs developers (and LLMs) love