Files
yaze/docs/internal/wasm/debugging.md

5.7 KiB

WASM Debugging Guide

This guide provides a comprehensive walkthrough for debugging and developing with the WASM version of YAZE. It covers common workflows such as loading ROMs, switching editors, and using the built-in debugging tools.

1. Getting Started

Running the WASM Server

To run the WASM version locally, use the provided script:

./scripts/serve-wasm.sh --dist build-wasm/dist --port 8080

This script ensures that the necessary Cross-Origin headers (COOP/COEP) are set, which are required for SharedArrayBuffer support.

Accessing the App

Open your browser (Chrome or Edge recommended) and navigate to: http://localhost:8080

2. Loading a ROM

There are two ways to load a ROM file:

  1. File Input: Click the "Open ROM" folder icon in the top-left toolbar and select your .sfc or .smc file.
  2. Drag and Drop: Drag a ROM file directly onto the application window.

Once loaded, the ROM info (name and size) will appear in the header status bar.

3. Switching Editors

YAZE provides multiple editors for different aspects of the ROM. You can switch between them using:

  • Dropdown Menu: Click the "Editor" dropdown in the toolbar and select the desired editor (e.g., Dungeon, Overworld, Graphics).
  • Command Palette: Press Ctrl+K (or Cmd+K on Mac) and type "Editor" to filter the list. Select an editor and press Enter.

4. Editor Selection Dialog

Some editors, like the Dungeon Editor, may prompt you with a selection dialog when first opened (e.g., to select a dungeon room).

  • Navigation: Use the mouse to click on a room or item in the list.
  • Search: If available, use the search box to filter items.
  • Confirm: Double-click an item or select it and click "OK".

5. Setting Layouts

You can customize the workspace layout using presets:

  • Layout Menu: Click the "Layout" dropdown (grid icon) in the toolbar.
  • Presets:
    • Default: Standard layout for the current editor.
    • Minimal: Maximizes the main view.
    • All Cards: Shows all available tool cards.
    • Debug: Opens additional debugging panels (Memory, Disassembly).

6. Debugging Tools

Emulator Controls

Control the emulation state via the "Emulator" dropdown or Command Palette:

  • Run/Pause: Toggle execution.
  • Step: Advance one frame.
  • Reset: Soft reset the emulator.

Pixel Inspector

Debug palette and rendering issues:

  1. Click the "Pixel Inspector" icon (eyedropper) in the toolbar.
  2. Hover over the canvas to see pixel coordinates and palette indices.
  3. Click to log the current pixel's details to the browser console.

VSCode-Style Panels

Toggle the bottom panel using the terminal icon (~ or ` key) or the "Problems" icon (bug).

  • Terminal: Execute WASM commands (type /help for a list).
  • Problems: View errors and warnings, including palette validation issues.
  • Output: General application logs.

Browser Console

Open the browser's developer tools (F12) to access the window.yazeDebug API for advanced debugging:

// Dump full application state
window.yazeDebug.dumpAll();

// Get graphics diagnostics
window.yazeDebug.graphics.getDiagnostics();

// Check memory usage
window.yazeDebug.memory.getUsage();

7. Debugging Memory Access Errors

Quick Methods to Find Out-of-Bounds Accesses

Method 1: Enable Emscripten SAFE_HEAP (Easiest)

Add -s SAFE_HEAP=1 to your Emscripten flags. This adds bounds checking to all memory accesses and will give you a precise error location.

In CMakePresets.json, add to CMAKE_CXX_FLAGS:

"CMAKE_CXX_FLAGS": "... -s SAFE_HEAP=1 -s ASSERTIONS=2"

Pros: Catches all out-of-bounds accesses automatically Cons: Slower execution (debugging only)

Method 2: Map WASM Function Number to Source

The error shows wasm-function[3704]. You can map this to source:

  1. Build with source maps: Add -g4 -s SOURCE_MAP_BASE='http://localhost:8080/' to linker flags
  2. Use wasm-objdump to list functions:
    wasm-objdump -x build-wasm/bin/yaze.wasm | grep -A 5 "func\[3704\]"
    
  3. Or use browser DevTools: The stack trace should show function names if source maps are enabled

Method 3: Add Logging Wrapper

Create a ROM access wrapper that logs all accesses:

#ifdef __EMSCRIPTEN__
class DebugRomAccess {
public:
  static bool CheckAccess(const uint8_t* data, size_t offset, size_t size,
                          size_t rom_size, const char* func_name) {
    if (offset + size > rom_size) {
      emscripten_log(EM_LOG_ERROR,
        "OUT OF BOUNDS: %s accessing offset %zu + %zu (ROM size: %zu)",
        func_name, offset, size, rom_size);
      return false;
    }
    return true;
  }
};
#endif

Common Pitfalls When Adding Bounds Checking

Pitfall 1: DecompressV2 Size Parameter

The DecompressV2 function has an early-exit when size == 0. Always pass 0x800 for the size parameter, not 0.

// CORRECT
DecompressV2(rom.data(), offset, 0x800, 1, rom.size())

// BROKEN - returns empty immediately
DecompressV2(rom.data(), offset, 0, 1, rom.size())

Pitfall 2: SMC Header Detection

The SMC header detection must use modulo 1MB, not 32KB:

// CORRECT
size % 1048576 == 512

// BROKEN - causes false positives
size % 0x8000 == 512

8. Common Issues & Solutions

  • "SharedArrayBuffer is not defined": Ensure you are running the server with serve-wasm.sh to set the correct headers.
  • ROM not loading: Check the browser console for errors. Ensure the file is a valid SNES ROM.
  • Canvas blank: Try resizing the window or toggling fullscreen to force a redraw.
  • Out of bounds memory access: Enable SAFE_HEAP (see Section 7) to get precise error locations.