Overview
Debugging Dolphin requires a combination of traditional debugging tools, emulator-specific features, and knowledge of GameCube/Wii hardware. This guide covers the essential debugging workflows.
Development Builds
Debug vs Release Builds
Debug Build
RelWithDebInfo
Release Build
Build with debug symbols and assertions enabled: cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build
Benefits:
Full debug symbols
Assertions enabled
No optimization (easier to step through)
Better stack traces
Drawbacks:
Significantly slower execution
Larger binary size
Build with optimizations but retain debug symbols: cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build
Benefits:
Debug symbols available
Optimized performance
Good balance for debugging performance issues
Drawbacks:
Harder to step through optimized code
Some variables may be optimized away
Fully optimized production build: cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
Use this for performance testing, not debugging.
For most debugging work, use Debug builds. For performance profiling, use RelWithDebInfo .
Debugger Setup
Visual Studio (Windows)
Open solution
Open the generated Dolphin.sln in Visual Studio after running CMake.
Set startup project
Right-click the dolphin-emu project and select “Set as Startup Project”.
Configure debugging
Set breakpoints by clicking in the left margin of the code editor.
Start debugging
Press F5 to start debugging, or Ctrl+F5 to run without debugging.
Useful shortcuts:
F5: Start/continue debugging
F9: Toggle breakpoint
F10: Step over
F11: Step into
Shift+F11: Step out
Visual Studio Code
Create .vscode/launch.json: {
"version" : "0.2.0" ,
"configurations" : [
{
"name" : "Debug Dolphin" ,
"type" : "cppdbg" ,
"request" : "launch" ,
"program" : "${workspaceFolder}/build/Binaries/dolphin-emu" ,
"args" : [],
"stopAtEntry" : false ,
"cwd" : "${workspaceFolder}" ,
"environment" : [],
"externalConsole" : false ,
"MIMode" : "gdb" ,
"setupCommands" : [
{
"description" : "Enable pretty-printing" ,
"text" : "-enable-pretty-printing" ,
"ignoreFailures" : true
}
]
}
]
}
Create .vscode/tasks.json for building: {
"version" : "2.0.0" ,
"tasks" : [
{
"label" : "Build Dolphin" ,
"type" : "shell" ,
"command" : "cmake --build build --config Debug" ,
"group" : {
"kind" : "build" ,
"isDefault" : true
}
}
]
}
GDB (Linux)
# Start with GDB
gdb ./build/Binaries/dolphin-emu
# Common GDB commands
( gdb ) break Core::RunLoop # Set breakpoint
( gdb ) run # Start program
( gdb ) next # Step over (n)
( gdb ) step # Step into (s)
( gdb ) continue # Continue execution (c)
( gdb ) print variable_name # Print variable (p)
( gdb ) backtrace # Show stack trace (bt)
( gdb ) quit # Exit GDB
Enable pretty printing for STL containers:
# Add to ~/.gdbinit
set print pretty on
set print object on
set print static-members on
python
import sys
sys.path.insert(0, '/usr/share/gcc/python' )
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers(None )
end
LLDB (macOS)
# Start with LLDB
lldb ./build/Binaries/dolphin-emu
# Common LLDB commands
( lldb ) breakpoint set -n Core::RunLoop # Set breakpoint
( lldb ) run # Start program
( lldb ) next # Step over (n)
( lldb ) step # Step into (s)
( lldb ) continue # Continue execution (c)
( lldb ) frame variable variable_name # Print variable
( lldb ) bt # Show stack trace
Logging and Diagnostics
Log Levels
Dolphin uses different log levels for diagnostic output:
#include "Common/Logging/Log.h"
// Different log levels
DEBUG_LOG_FMT (VIDEO, "Debug message: {}" , value);
INFO_LOG_FMT (VIDEO, "Info message: {}" , value);
NOTICE_LOG_FMT (VIDEO, "Notice message: {}" , value);
WARN_LOG_FMT (VIDEO, "Warning message: {}" , value);
ERROR_LOG_FMT (VIDEO, "Error message: {}" , value);
Log types (first parameter):
VIDEO: Video backend
AUDIO: Audio processing
CORE: Core emulation
BOOT: Boot process
POWERPC: PowerPC CPU
IOS: IOS emulation
DSP: DSP emulation
Viewing Logs
In Dolphin’s UI:
View → Show Log
View → Show Log Configuration
Enable desired log types and levels
Run Dolphin from terminal to see logs in real-time: ./dolphin-emu 2>&1 | tee dolphin.log
Logs are saved to:
Windows : %USERPROFILE%\Documents\Dolphin Emulator\Logs\
Linux : ~/.local/share/dolphin-emu/Logs/
macOS : ~/Library/Application Support/Dolphin/Logs/
Adding Debug Logging
When debugging issues, add temporary logging:
INFO_LOG_FMT (CORE, "Function called with value: {:#x}" , value);
DEBUG_LOG_FMT (VIDEO, "Texture cache size: {}" , texture_cache . size ());
// Format multiple values
DEBUG_LOG_FMT (POWERPC, "PC: {:#010x}, LR: {:#010x}, Instr: {:#010x}" ,
PC, LR, instruction);
Remove or disable verbose debug logging before submitting pull requests.
Message Handlers
Custom Assertions
Dolphin uses a custom message handler for assertions and errors:
#include "Common/MsgHandler.h"
// In tests, assertions are caught
bool TestMsgHandler ( const char* caption , const char* text ,
bool yes_no , Common :: MsgType style )
{
fmt :: print (stderr, "{} \n " , text);
ADD_FAILURE (); // For test framework
return true ; // Return yes to any question
}
Common :: RegisterMsgAlertHandler (TestMsgHandler);
This prevents the emulator from breaking on assertions during testing.
Common Debugging Scenarios
Debugging Crashes
Get stack trace
When Dolphin crashes, capture the stack trace:
Windows : Check Event Viewer or use Visual Studio debugger
Linux : ulimit -c unlimited && ./dolphin-emu then gdb dolphin-emu core
macOS : Check Console.app for crash reports
Enable core dumps
Configure system to save core dumps: # Linux
ulimit -c unlimited
sudo sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t
Analyze with debugger
Load core dump: gdb ./dolphin-emu /tmp/core-dolphin-emu.12345
( gdb ) backtrace full
Debugging JIT Code
For JIT compiler issues:
// Enable JIT logging
DEBUG_LOG_FMT (DYNA_REC, "Compiling block at {:#010x}" , address);
// Disable JIT for specific functions
if (address == 0x 80001234 )
{
// Fall back to interpreter
return false ;
}
Use the “Enable Debugging UI” option in Dolphin settings to access JIT-related debugging features.
Memory Issues
AddressSanitizer
Valgrind
Memory Debugger
Build with ASan to detect memory errors: cmake -B build -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS= "-fsanitize=address -fno-omit-frame-pointer"
cmake --build build
Run under Valgrind (Linux): valgrind --leak-check=full --track-origins=yes ./dolphin-emu
Use Dolphin’s built-in memory viewer:
View → Memory
Navigate to address
Set memory breakpoints
Profile with built-in tools
Enable performance statistics:
View → Show Performance Monitor
View → Show FPS counter
Use external profilers
Linux: perf record -g ./dolphin-emu
perf report
Windows:
Visual Studio Profiler
Intel VTune
macOS:
Identify bottlenecks
Look for hot paths in profiler output and optimize accordingly.
Emulator-Specific Debugging
Code Breakpoints
Dolphin includes a debugger for the emulated PowerPC CPU:
View → Code : Open the code debugger
Set breakpoints on PowerPC addresses
Step through emulated code instruction by instruction
View registers, memory, and call stack
Memory Breakpoints
Break when emulated code accesses specific memory:
View → Memory : Open memory viewer
Right-click on address → Add Breakpoint
Choose read, write, or read/write breakpoint
Register Tracking
Monitor PowerPC register changes:
View → Registers : Open register window
Watch values change as code executes
Edit registers to test different scenarios
Unit Test Debugging
When debugging failing tests:
# Run specific test under debugger
gdb --args ./Binaries/Tests/tests --gtest_filter= "BitField.Storage"
# Set breakpoint in GDB
( gdb ) break BitFieldTest.cpp:59
( gdb ) run
# When breakpoint hits, inspect
( gdb ) print object
( gdb ) print object.hex
See the Testing guide for more information on running and writing tests.
Best Practices
Use assertions
Add assertions to catch invalid states early: ASSERT (pointer != nullptr );
DEBUG_ASSERT (index < size);
Validate assumptions
Check preconditions and postconditions: void Process ( const Data * data )
{
ASSERT (data != nullptr );
// ... processing ...
ASSERT ( result . IsValid ());
}
Use descriptive variable names
Makes debugging easier when inspecting variables: // Good - clear in debugger
int texture_cache_hits = 0 ;
// Bad - unclear in debugger
int tch = 0 ;
Isolate the problem
Narrow down the issue:
Binary search commits with git bisect
Disable features to identify culprit
Create minimal reproduction case
Document findings
Keep notes about:
What you tried
What worked/didn’t work
Root cause analysis
Compiler Warnings
Always fix compiler warnings. They often indicate real bugs.
Enable additional warnings:
cmake -B build -DCMAKE_CXX_FLAGS= "-Wall -Wextra -Wpedantic"
Treat warnings as errors during development:
cmake -B build -DCMAKE_CXX_FLAGS= "-Werror"
Getting Help
If you’re stuck debugging an issue:
Search existing issues : Check GitHub for similar problems
Ask on IRC : #dolphin-emu @ irc.libera.chat
Create detailed report : Include:
Steps to reproduce
Expected vs actual behavior
Stack traces or logs
Build configuration
System information
Next Steps
Code Style Review coding standards and formatting
Testing Learn about unit testing practices