This document describes how to integrate wasminspect debugger into CodeApp for iPad.
This integration provides two approaches:
- VSCode Extension (Desktop): For debugging WebAssembly in VSCode using wasminspect
- CodeApp Integration (iPad): For debugging WebAssembly in CodeApp on iPad
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
-
Build wasminspect:
cd /Users/lilyhuang/Documents/wasminspect cargo build --release -
Install dependencies:
cd vscode-extension npm install -
Run extension:
npm run compile # Press F5 in VSCode to launch extension development host -
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 } ] }
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ │ DAP │ │ stdin/ │ │
│ VSCode UI │ <-----> │ Debug Adapter │ stdout │ wasminspect │
│ │ │ │ <-----> │ CLI Process │
└─────────────┘ └──────────────────┘ └─────────────────┘
Reuse the existing DebuggerService infrastructure but extend it to support multiple debugger backends.
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) │
└────────────────┘ └───────────────┘
Option A: Extend DebuggerService (Recommended for reusing infrastructure)
Modify CodeApp/Services/DebuggerService.swift to:
- Add backend selection:
enum DebuggerBackend {
case gdb // MI2 protocol
case wasminspect // LLDB-style commands
}
@Published var backend: DebuggerBackend = .gdb- Use polymorphic parsing:
private func parseLine(_ line: String) {
switch backend {
case .gdb:
parseMI(line)
case .wasminspect:
parseWasminspect(line)
}
}- 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.
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
Wasminspect is written in Rust and needs to be compiled to WASM to run on iPad via Wasmer.
# Install wasm32-wasi target
rustup target add wasm32-wasi
# Install wasi-sdk (optional, for C dependencies)
# Download from https://github.com/WebAssembly/wasi-sdkcd /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-
Option 1: Bundle in App
- Copy
wasminspect.wasmtoCodeApp/Resources/ - Add to Xcode project
- Service will auto-detect at
Bundle.main.url(forResource: "wasminspect", withExtension: "wasm")
- Copy
-
Option 2: User-provided
- User copies
wasminspect.wasmtoDocuments/Tools/ - Service will auto-detect at
Documents/Tools/wasminspect.wasm
- User copies
- Place
wasminspect.wasmin one of the locations above - Place your target WASM file (compiled with
-gdebug info) in Documents - Open right sidebar → Wasminspect panel
-
Configure paths:
- Wasminspect WASM: Auto-detected or manually set
- Target WASM: Select your program (e.g.,
Documents/program.wasm) - Arguments: Optional command-line args
-
Launch debugger:
- Click "Launch" button
- Program stops at entry point
-
Set breakpoints:
- In editor: Click gutter to toggle breakpoint
- In panel: View breakpoint list
-
Control execution:
- Continue: Run until next breakpoint
- Step Over: Execute current line
- Step In: Enter function call
- Step Out: Return from function
-
Inspect state:
- Console: View raw debugger output
- Stack: View call stack frames
- Variables: View locals and globals
- Breakpoints: Manage breakpoint list
Your target WASM must be compiled with DWARF debug information.
clang --target=wasm32-wasi -g -O0 -o program.wasm program.ccargo build --target wasm32-wasi
# Debug build (in target/wasm32-wasi/debug/) has debug info by default# Check if WASM has debug sections
wasm-objdump -h program.wasm | grep debug
# Should see sections like:
# .debug_info
# .debug_line
# .debug_str- No native iOS debugging: This debugs WASM programs only, not native iOS code
- Sandbox restrictions: File system access limited to app sandbox
- Memory constraints: Large WASM programs may hit iPad memory limits
- Performance: WASM-in-WASM has overhead (wasminspect.wasm debugging target.wasm)
- Source paths: May need path remapping if build paths don't match iPad paths
- Complex types: Swift-specific types require optional
swift-extensionfeature - Expression evaluation: Limited compared to native debuggers
Path remapping:
If your DWARF debug info has absolute paths like /home/user/src/program.c, you may need to:
- Use
--mapdirwhen launching (not yet exposed in UI) - Or rebuild with relative paths
Memory issues:
- Use release builds with just
-gflag (no-O0) - Close other apps on iPad
- Use incremental debugging (don't load huge programs)
To enable breakpoint toggling in the editor (like with GDB):
- Modify
WasminspectServiceto expose breakpoint toggle - Hook editor gutter tap events
- Post breakpoint commands to service
Example:
// In editor view
.onTapGesture { location in
let line = getLineNumber(at: location)
WasminspectService.shared.toggleBreakpoint(
file: currentFile,
line: line
)
}To allow manual command entry:
// In WasminspectSidebarView.swift
TextField("Enter command", text: $manualCommand)
.onSubmit {
service.sendCommand(manualCommand)
manualCommand = ""
}Wasminspect has optional remote-api feature (WebSocket server).
To use it:
- Build wasminspect with
--features remote-api - Run wasminspect-server on desktop
- Connect from iPad via WebSocket
- Modify service to use WebSocket instead of stdin/stdout
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- Launch debugger
- Set breakpoint at
factorialfunction - Continue execution
- Should stop at breakpoint
- Step through function calls
- Inspect
nvariable - View call stack showing recursive calls
- Check wasminspect.wasm exists and is readable
- Check target WASM exists
- View Console tab for error messages
- Ensure target compiled with
-g - Check DWARF sections exist (
wasm-objdump -h) - Verify file paths match between build and runtime
- Compile with
-O0(no optimizations) - Some variables may be optimized away even at
-O1 - Check Console for "frame variable" command output
- Reduce target WASM size
- Close other apps
- Check for infinite loops in target program
- View stderr output in Console
- DAP protocol support: Implement Debug Adapter Protocol for standardized debugging
- Visual breakpoint UI: Show breakpoints in editor gutter
- Expression evaluator: Add REPL-style expression evaluation
- Memory viewer: Hex dump of linear memory
- Disassembly view: Show WebAssembly instructions
- Remote debugging: Connect to desktop wasminspect-server
- Multi-target: Debug multiple WASM programs simultaneously