Skip to content

Latest commit

 

History

History
434 lines (331 loc) · 11.9 KB

File metadata and controls

434 lines (331 loc) · 11.9 KB

Wasminspect Integration for CodeApp (iPad)

This document describes how to integrate wasminspect debugger into CodeApp for iPad.

Overview

This integration provides two approaches:

  1. VSCode Extension (Desktop): For debugging WebAssembly in VSCode using wasminspect
  2. CodeApp Integration (iPad): For debugging WebAssembly in CodeApp on iPad

Approach 1: VSCode Extension (Desktop)

Files Created

vscode-extension/
├── package.json              # Extension manifest
├── tsconfig.json            # TypeScript configuration
├── .vscodeignore            # Files to ignore in package
├── .eslintrc.json           # Linting configuration
├── .vscode/
│   ├── launch.json          # Extension development launch config
│   └── tasks.json           # Build tasks
├── src/
│   ├── extension.ts         # Extension activation
│   ├── debugAdapter.ts      # DAP protocol implementation
│   └── wasminspectSession.ts # Process communication with wasminspect
└── README.md                # Usage documentation

Installation & Usage

  1. Build wasminspect:

    cd /Users/lilyhuang/Documents/wasminspect
    cargo build --release
  2. Install dependencies:

    cd vscode-extension
    npm install
  3. Run extension:

    npm run compile
    # Press F5 in VSCode to launch extension development host
  4. Create launch.json in your WebAssembly project:

    {
        "version": "0.2.0",
        "configurations": [
            {
                "type": "wasm",
                "request": "launch",
                "name": "Debug WebAssembly",
                "program": "${workspaceFolder}/program.wasm",
                "stopOnEntry": true
            }
        ]
    }

Architecture

┌─────────────┐         ┌──────────────────┐         ┌─────────────────┐
│             │  DAP    │                  │ stdin/  │                 │
│  VSCode UI  │ <-----> │  Debug Adapter   │ stdout  │  wasminspect    │
│             │         │                  │ <-----> │  CLI Process    │
└─────────────┘         └──────────────────┘         └─────────────────┘

Approach 2: CodeApp Integration (iPad) - Reusing Infrastructure

Strategy

Reuse the existing DebuggerService infrastructure but extend it to support multiple debugger backends.

Architecture

Instead of creating a separate WasminspectService, we modify the existing DebuggerService to support multiple debugger backends:

┌──────────────────┐
│  DebuggerService │
│                  │
│  + backend: enum │────┐
│  + launch()      │    │
│  + sendCommand() │    │
└──────────────────┘    │
                        │
            ┌───────────┴────────────┐
            │                        │
    ┌───────▼────────┐      ┌───────▼───────┐
    │  GDB Backend   │      │ Wasminspect   │
    │  (MI2 parser)  │      │ Backend       │
    │                │      │ (LLDB parser) │
    └────────────────┘      └───────────────┘

Recommended Implementation

Option A: Extend DebuggerService (Recommended for reusing infrastructure)

Modify CodeApp/Services/DebuggerService.swift to:

  1. Add backend selection:
enum DebuggerBackend {
    case gdb    // MI2 protocol
    case wasminspect  // LLDB-style commands
}

@Published var backend: DebuggerBackend = .gdb
  1. Use polymorphic parsing:
private func parseLine(_ line: String) {
    switch backend {
    case .gdb:
        parseMI(line)
    case .wasminspect:
        parseWasminspect(line)
    }
}
  1. Add wasminspect command adapter:
private func sendCommand(_ cmd: String) {
    let translatedCmd: String
    switch backend {
    case .gdb:
        translatedCmd = cmd  // MI2 format
    case .wasminspect:
        translatedCmd = translateToWasminspect(cmd)
    }
    writeToStdin(translatedCmd)
}

private func translateToWasminspect(_ cmd: String) -> String {
    // Translate common operations to wasminspect commands
    switch cmd {
    case "-exec-run": return "process launch"
    case "-exec-continue": return "process continue"
    case "-exec-next": return "thread step-over"
    case "-exec-step": return "thread step-in"
    case "-exec-finish": return "thread step-out"
    default: return cmd
    }
}

Option B: Separate Service (Already implemented in files above)

Use the standalone WasminspectService.swift and WasminspectSidebarView.swift created earlier.

File Locations (Option B)

CodeApp/
├── Services/
│   ├── DebuggerService.swift        # Existing GDB integration
│   └── WasminspectService.swift     # New wasminspect integration
├── Views/
│   ├── DebuggerSidebarView.swift    # Existing GDB UI
│   └── WasminspectSidebarView.swift # New wasminspect UI
└── Extensions/
    ├── Debugger/
    │   └── DebuggerExtension.swift  # Existing GDB extension
    └── Wasminspect/
        └── WasminspectExtension.swift # New wasminspect extension

Building wasminspect.wasm for iPad

Wasminspect is written in Rust and needs to be compiled to WASM to run on iPad via Wasmer.

Prerequisites

# Install wasm32-wasi target
rustup target add wasm32-wasi

# Install wasi-sdk (optional, for C dependencies)
# Download from https://github.com/WebAssembly/wasi-sdk

Compilation

cd /Users/lilyhuang/Documents/wasminspect

# Build for wasm32-wasi target
cargo build --target wasm32-wasi --release

# The output will be at:
# target/wasm32-wasi/release/wasminspect.wasm

Deployment to iPad

  1. Option 1: Bundle in App

    • Copy wasminspect.wasm to CodeApp/Resources/
    • Add to Xcode project
    • Service will auto-detect at Bundle.main.url(forResource: "wasminspect", withExtension: "wasm")
  2. Option 2: User-provided

    • User copies wasminspect.wasm to Documents/Tools/
    • Service will auto-detect at Documents/Tools/wasminspect.wasm

Usage in CodeApp

Setup

  1. Place wasminspect.wasm in one of the locations above
  2. Place your target WASM file (compiled with -g debug info) in Documents
  3. Open right sidebar → Wasminspect panel

Debugging Workflow

  1. Configure paths:

    • Wasminspect WASM: Auto-detected or manually set
    • Target WASM: Select your program (e.g., Documents/program.wasm)
    • Arguments: Optional command-line args
  2. Launch debugger:

    • Click "Launch" button
    • Program stops at entry point
  3. Set breakpoints:

    • In editor: Click gutter to toggle breakpoint
    • In panel: View breakpoint list
  4. Control execution:

    • Continue: Run until next breakpoint
    • Step Over: Execute current line
    • Step In: Enter function call
    • Step Out: Return from function
  5. Inspect state:

    • Console: View raw debugger output
    • Stack: View call stack frames
    • Variables: View locals and globals
    • Breakpoints: Manage breakpoint list

Compiling Debug WebAssembly

Your target WASM must be compiled with DWARF debug information.

C/C++ (with wasi-sdk)

clang --target=wasm32-wasi -g -O0 -o program.wasm program.c

Rust

cargo build --target wasm32-wasi
# Debug build (in target/wasm32-wasi/debug/) has debug info by default

Checking Debug Info

# Check if WASM has debug sections
wasm-objdump -h program.wasm | grep debug

# Should see sections like:
# .debug_info
# .debug_line
# .debug_str

Limitations & Known Issues

iPad/WASM Limitations

  1. No native iOS debugging: This debugs WASM programs only, not native iOS code
  2. Sandbox restrictions: File system access limited to app sandbox
  3. Memory constraints: Large WASM programs may hit iPad memory limits
  4. Performance: WASM-in-WASM has overhead (wasminspect.wasm debugging target.wasm)

Wasminspect Limitations

  1. Source paths: May need path remapping if build paths don't match iPad paths
  2. Complex types: Swift-specific types require optional swift-extension feature
  3. Expression evaluation: Limited compared to native debuggers

Workarounds

Path remapping: If your DWARF debug info has absolute paths like /home/user/src/program.c, you may need to:

  • Use --mapdir when launching (not yet exposed in UI)
  • Or rebuild with relative paths

Memory issues:

  • Use release builds with just -g flag (no -O0)
  • Close other apps on iPad
  • Use incremental debugging (don't load huge programs)

Extending the Integration

Adding Editor Integration

To enable breakpoint toggling in the editor (like with GDB):

  1. Modify WasminspectService to expose breakpoint toggle
  2. Hook editor gutter tap events
  3. Post breakpoint commands to service

Example:

// In editor view
.onTapGesture { location in
    let line = getLineNumber(at: location)
    WasminspectService.shared.toggleBreakpoint(
        file: currentFile,
        line: line
    )
}

Adding Command Input

To allow manual command entry:

// In WasminspectSidebarView.swift
TextField("Enter command", text: $manualCommand)
    .onSubmit {
        service.sendCommand(manualCommand)
        manualCommand = ""
    }

Supporting Remote Debugging

Wasminspect has optional remote-api feature (WebSocket server).

To use it:

  1. Build wasminspect with --features remote-api
  2. Run wasminspect-server on desktop
  3. Connect from iPad via WebSocket
  4. Modify service to use WebSocket instead of stdin/stdout

Testing

Test Program

Create a simple test program:

// test.c
#include <stdio.h>

int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

int main() {
    int result = factorial(5);
    printf("Result: %d\n", result);
    return 0;
}

Compile:

clang --target=wasm32-wasi -g -O0 -o test.wasm test.c

Expected Behavior

  1. Launch debugger
  2. Set breakpoint at factorial function
  3. Continue execution
  4. Should stop at breakpoint
  5. Step through function calls
  6. Inspect n variable
  7. View call stack showing recursive calls

Troubleshooting

Debugger won't launch

  • Check wasminspect.wasm exists and is readable
  • Check target WASM exists
  • View Console tab for error messages

Breakpoints don't work

  • Ensure target compiled with -g
  • Check DWARF sections exist (wasm-objdump -h)
  • Verify file paths match between build and runtime

Variables not showing

  • Compile with -O0 (no optimizations)
  • Some variables may be optimized away even at -O1
  • Check Console for "frame variable" command output

Crashes or hangs

  • Reduce target WASM size
  • Close other apps
  • Check for infinite loops in target program
  • View stderr output in Console

Future Enhancements

  1. DAP protocol support: Implement Debug Adapter Protocol for standardized debugging
  2. Visual breakpoint UI: Show breakpoints in editor gutter
  3. Expression evaluator: Add REPL-style expression evaluation
  4. Memory viewer: Hex dump of linear memory
  5. Disassembly view: Show WebAssembly instructions
  6. Remote debugging: Connect to desktop wasminspect-server
  7. Multi-target: Debug multiple WASM programs simultaneously

References