Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
eb5f169
Basic LLDB remote protocol scaffolding
MaxDesiatov Oct 8, 2025
0baf7a5
Implement more packet handling, update naming
MaxDesiatov Oct 8, 2025
85a695a
Provide original license notice in `wasmkit-gdb-tool/Entrypoint.swift`
MaxDesiatov Oct 8, 2025
eba97a0
Apply formatter
MaxDesiatov Oct 8, 2025
6546754
Make naming of types more specific to avoid future collisions
MaxDesiatov Oct 8, 2025
7b2c6f6
More cleanups for type naming
MaxDesiatov Oct 8, 2025
4a1c998
Remove unused `import struct Foundation.Date`
MaxDesiatov Oct 8, 2025
f8c08dd
Remove unused `else` clause from command decoder
MaxDesiatov Oct 8, 2025
77bdb04
Add `swift-nio` in `SWIFTCI_USE_LOCAL_DEPS` clause
MaxDesiatov Oct 8, 2025
256c70c
Add FIXME note for `.supportedFeatures` response
MaxDesiatov Oct 8, 2025
111deb8
Use `Logger`, `NIOAsyncChannel`
MaxDesiatov Oct 9, 2025
e392d30
Add required dependencies to `[email protected]`
MaxDesiatov Oct 9, 2025
a7c62b0
Add `iSeqToWasmMapping` to `InstanceEntity`
MaxDesiatov Oct 9, 2025
21e1b44
Fix formatting and iOS compatibility
MaxDesiatov Oct 9, 2025
329e4f5
Update [email protected]
MaxDesiatov Oct 9, 2025
a3d20af
Update doc comment of `func instantiate` in `Module.swift`
MaxDesiatov Oct 9, 2025
8d15b99
Add `targetStatus`/`?` host command
MaxDesiatov Oct 10, 2025
d9b60b1
Fix use of `OK#9a` instead of incorrect `ok#da` response
MaxDesiatov Oct 10, 2025
05583d0
Add `CSystemExtras` to `[email protected]`
MaxDesiatov Oct 10, 2025
39242d6
Handle `targetStatus` in `WasmKitDebugger`
MaxDesiatov Oct 10, 2025
cbff974
Build only `wasmkit-cli` product for WASI in `main.yml`
MaxDesiatov Oct 10, 2025
982fa91
Fix formatting in `WasmKitDebugger.swift`
MaxDesiatov Oct 10, 2025
3a74a91
Fix `QStartNoAckMode` handling
MaxDesiatov Oct 14, 2025
bc539e8
Add `qRegisterInfo` parsing to `GDBHostCommand.init`
MaxDesiatov Oct 14, 2025
fb4e2a2
Use `KeyValuePairs` response for `.registerInfo`
MaxDesiatov Oct 14, 2025
042a2c4
Fix formatting and tests build error
MaxDesiatov Oct 14, 2025
197abd3
Exclude `wasmkit-gdb-tool` on Windows, address PR feedback
MaxDesiatov Oct 14, 2025
a2899f7
Remove retroactive `FilePath` conformance
MaxDesiatov Oct 14, 2025
0b42724
Handle more host commands, up to `qWasmCallStack`
MaxDesiatov Oct 14, 2025
1783176
Fix formatting
MaxDesiatov Oct 14, 2025
c0a9cf6
Address PR feedback, add comment for `DebuggingAddress` sendability
MaxDesiatov Oct 16, 2025
806e7ec
Add `DebuggerExecution` wrapper type
MaxDesiatov Oct 16, 2025
26ea4e5
Implement `.readMemory` command handling
MaxDesiatov Oct 16, 2025
8343902
Fix formatting
MaxDesiatov Oct 16, 2025
ff2fa0d
Pass `-package-name` in CMake to enable use of `package`
MaxDesiatov Oct 16, 2025
3ed9013
Disable `WasmKitGDBHandler` on Windows
MaxDesiatov Oct 16, 2025
3ea5aab
Fix formatting
MaxDesiatov Oct 16, 2025
3fc8fdc
Try nightly `main` for `build-cmake` job
MaxDesiatov Oct 17, 2025
ea83134
Revert "Try nightly `main` for `build-cmake` job"
MaxDesiatov Oct 17, 2025
2893799
Rename `DebuggerExecution` to `Debugger`, hide behind a trait
MaxDesiatov Oct 17, 2025
7bdb16c
Enable `WasmDebuggingSupport` on CI where possible
MaxDesiatov Oct 17, 2025
4ea0fb0
Fix formatting
MaxDesiatov Oct 17, 2025
ee3c7bf
Revert "Pass `-package-name` in CMake to enable use of `package`"
MaxDesiatov Oct 17, 2025
a6d0749
Disable traits in pre-6.1, guard use of `package` on trait
MaxDesiatov Oct 17, 2025
4909d3b
Remove use of `package` from CMake-built code
MaxDesiatov Oct 20, 2025
cce2105
Fix non-CMake build breakage
MaxDesiatov Oct 20, 2025
811589f
Fix formatting
MaxDesiatov Oct 20, 2025
bc2230d
Enable iseq -> wasm instruction mapping
MaxDesiatov Oct 20, 2025
db1ec2d
Fix formatting
MaxDesiatov Oct 20, 2025
62592f1
Add missing `mutating` to `Debugger.swift`
MaxDesiatov Oct 20, 2025
bbfcb45
Make `init` throw effect untyped in `Debugger.swift`
MaxDesiatov Oct 20, 2025
c6213eb
Make throwing method effects untyped in `Debugger.swift`
MaxDesiatov Oct 20, 2025
a993b50
Make `debugger: Debugger` property mutable
MaxDesiatov Oct 20, 2025
2d065e0
Clean up `WasmGen` code
MaxDesiatov Oct 21, 2025
fd0d1ee
Add reverse wasm->iseq mapping, breakpoints toggling PoC
MaxDesiatov Oct 21, 2025
a35b73e
Remove unused `functionAddresses` property from `Debugger`
MaxDesiatov Oct 21, 2025
16ac0cf
Remove changes unrelated to the protocol
MaxDesiatov Oct 22, 2025
410c470
Clarify licensing in `README.md`
MaxDesiatov Oct 22, 2025
977b939
Add license files for separate modules
MaxDesiatov Oct 22, 2025
2acd4f3
Basic doc comments for `GDBHostCommand`
MaxDesiatov Oct 22, 2025
3b2e30f
Add doc comments for `GDBHostCommandDecoder`
MaxDesiatov Oct 22, 2025
fc740e5
Add remaining doc comments
MaxDesiatov Oct 22, 2025
a297f2d
Fix formatting
MaxDesiatov Oct 22, 2025
ff2e940
Fix var naming typo
MaxDesiatov Oct 22, 2025
5f7fbb5
Clarify licensing in `README.md`
MaxDesiatov Oct 22, 2025
d100d1e
Add license files for separate modules
MaxDesiatov Oct 22, 2025
2407284
Basic doc comments for `GDBHostCommand`
MaxDesiatov Oct 22, 2025
f628219
Add doc comments for `GDBHostCommandDecoder`
MaxDesiatov Oct 22, 2025
ab295db
Add remaining doc comments
MaxDesiatov Oct 22, 2025
e3505bc
Fix formatting
MaxDesiatov Oct 22, 2025
c4f9b3f
Fix var naming typo
MaxDesiatov Oct 22, 2025
f6bab20
Remove unused `throws` in `GDBTargetResponseEncoder.swift`
MaxDesiatov Oct 22, 2025
f33dc82
Remove unused `throws` in `GDBTargetResponseEncoder.swift`
MaxDesiatov Oct 22, 2025
a1d5183
Merge branch 'maxd/lldb-remote-protocol' of github.com:swiftwasm/Wasm…
MaxDesiatov Oct 22, 2025
dccc6af
Revert "Remove changes unrelated to the protocol"
MaxDesiatov Oct 22, 2025
a25399d
Restore base branch state
MaxDesiatov Oct 22, 2025
6bb5df8
Merge branch 'main' into maxd/debugging-breakpoints
MaxDesiatov Oct 22, 2025
ae91e24
Add `DebuggerTests` test suite
MaxDesiatov Oct 22, 2025
169d406
Merge remote-tracking branch 'origin/maxd/debugging-breakpoints' into…
MaxDesiatov Oct 22, 2025
d5d1600
Fix build error, add debug logging
MaxDesiatov Oct 23, 2025
9d79c83
Fix `DebuggerTests`
MaxDesiatov Oct 23, 2025
f64bf23
Remove `print` debugging
MaxDesiatov Oct 23, 2025
8bf6849
Allocate and modify `Pc` directly as `Debugger` property
MaxDesiatov Oct 23, 2025
ea04cc3
Rewind Pc back by 1 word after catching `Breakpoint`
MaxDesiatov Oct 23, 2025
c4d3ac9
Revert "Allocate and modify `Pc` directly as `Debugger` property"
MaxDesiatov Oct 24, 2025
6246506
Fully implement `qWasmCallStack`
MaxDesiatov Oct 24, 2025
27dbbc7
Pass `Sp` in `Breakpoint`, add `executeWasm` instance method
MaxDesiatov Oct 24, 2025
036fcb8
Fix license header diff
MaxDesiatov Oct 24, 2025
a57ec75
Fix trailing comma compatibility with Swift 6.0
MaxDesiatov Oct 24, 2025
935f877
Fix breakpoint resumption test expectation
MaxDesiatov Oct 24, 2025
a7fac8e
Mark `Sp.currentFunction` as `internal`
MaxDesiatov Oct 24, 2025
4e8b062
Mark `Debugger.Error` as `@unchecked Sendable`
MaxDesiatov Oct 24, 2025
969b992
Handle `qThreadStopInfo`, run up to breakpoint in handler
MaxDesiatov Oct 24, 2025
2486ec8
Add missing `logger` argument in `Entrypoint.swift`
MaxDesiatov Oct 24, 2025
d594b49
Remove CLI harness for smaller diff
MaxDesiatov Oct 27, 2025
76b2317
Revert "Remove CLI harness for smaller diff"
MaxDesiatov Oct 27, 2025
beff9a7
Remove only `wasmkit-gdb-tool`
MaxDesiatov Oct 27, 2025
eb9001b
Make some functions `fileprivate`
MaxDesiatov Oct 27, 2025
687b223
Add doc comments for the debugger type
MaxDesiatov Oct 27, 2025
d25166b
Merge branch 'main' into maxd/debugging-breakpoints
MaxDesiatov Oct 27, 2025
8d78ab6
Fix formatting
MaxDesiatov Oct 27, 2025
c39f9e2
Refine doc comment Sources/WasmKit/Execution/Debugger.swift
MaxDesiatov Oct 27, 2025
55bfb6b
Refine doc comment in `Debugger.swift`
MaxDesiatov Oct 27, 2025
e7a5287
Refine doc comments wording
MaxDesiatov Oct 27, 2025
a2c701e
Fix build error
MaxDesiatov Oct 27, 2025
1b271d5
Fix formatting
MaxDesiatov Oct 27, 2025
dec6850
Apply formatting to `[email protected]`
MaxDesiatov Oct 27, 2025
b3953a5
Disable nightly toolchain in CI configuration
MaxDesiatov Oct 27, 2025
e81f68e
Pin `build-android` job to v2.6.4 of `swift-android-action`
MaxDesiatov Oct 27, 2025
ab8f080
Refine doc comments wording
MaxDesiatov Oct 27, 2025
0eda671
Revert "Pin `build-android` job to v2.6.4 of `swift-android-action`"
MaxDesiatov Oct 27, 2025
7f0e212
Merge branch 'main' of github.com:swiftwasm/WasmKit into maxd/debuggi…
MaxDesiatov Oct 28, 2025
da87018
Merge branch 'main' into maxd/debugging-breakpoints
MaxDesiatov Oct 28, 2025
ce6124c
Move mapping dictionaries to `DebuggerInstructionMapping`
MaxDesiatov Oct 28, 2025
dd36c4c
Fix formatting and CMake
MaxDesiatov Oct 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,21 @@ jobs:
wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9"
test-args: "--traits WasmDebuggingSupport --enable-code-coverage"
build-dev-dashboard: true
- swift: "swiftlang/swift:nightly-main-noble"
development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz"
wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz"
wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm
wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9"
test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY"
- swift: "swiftlang/swift:nightly-main-noble"
development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz"
wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz"
wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm
wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9"
test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY --build-system swiftbuild"
label: " --build-system swiftbuild"
# Disabled until a toolchain containing https://github.com/swiftlang/swift/commit/b219d4089c922ceb8b700424236ca97f6087a9a1
# is tagged.
# - swift: "swiftlang/swift:nightly-main-noble"
# development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz"
# wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz"
# wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm
# wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9"
# test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY"
# - swift: "swiftlang/swift:nightly-main-noble"
# development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz"
# wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz"
# wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm
# wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9"
# test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY --build-system swiftbuild"
# label: " --build-system swiftbuild"

runs-on: ubuntu-24.04
name: "build-linux (${{ matrix.swift }}${{ matrix.label }})"
Expand Down
5 changes: 3 additions & 2 deletions [email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ let package = Package(
],
traits: [
.default(enabledTraits: []),
"WasmDebuggingSupport"
"WasmDebuggingSupport",
],
targets: [
.executableTarget(
Expand Down Expand Up @@ -123,7 +123,8 @@ let package = Package(
.target(name: "WITExtractor"),
.testTarget(name: "WITExtractorTests", dependencies: ["WITExtractor", "WIT"]),

.target(name: "GDBRemoteProtocol",
.target(
name: "GDBRemoteProtocol",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "NIOCore", package: "swift-nio"),
Expand Down
10 changes: 10 additions & 0 deletions Sources/GDBRemoteProtocol/GDBHostCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ package struct GDBHostCommand: Equatable {
case readMemoryBinaryData
case readMemory
case wasmCallStack
case threadStopInfo

case generalRegisters

Expand Down Expand Up @@ -97,6 +98,7 @@ package struct GDBHostCommand: Equatable {
/// - arguments: raw arguments that immediately follow kind of the command.
package init(kindString: String, arguments: String) throws(GDBHostCommandDecoder.Error) {
let registerInfoPrefix = "qRegisterInfo"
let threadStopInfoPrefix = "qThreadStopInfo"

if kindString.starts(with: "x") {
self.kind = .readMemoryBinaryData
Expand All @@ -109,6 +111,14 @@ package struct GDBHostCommand: Equatable {
} else if kindString.starts(with: registerInfoPrefix) {
self.kind = .registerInfo

guard arguments.isEmpty else {
throw GDBHostCommandDecoder.Error.unexpectedArgumentsValue
}
self.arguments = String(kindString.dropFirst(registerInfoPrefix.count))
return
} else if kindString.starts(with: threadStopInfoPrefix) {
self.kind = .threadStopInfo

guard arguments.isEmpty else {
throw GDBHostCommandDecoder.Error.unexpectedArgumentsValue
}
Expand Down
13 changes: 10 additions & 3 deletions Sources/GDBRemoteProtocol/GDBTargetResponseEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

import Foundation
import Logging
import NIOCore

extension String {
Expand All @@ -27,7 +28,12 @@ extension String {
package class GDBTargetResponseEncoder: MessageToByteEncoder {
private var isNoAckModeActive = false

package init() {}
private let logger: Logger

package init(logger: Logger) {
self.logger = logger
}

package func encode(data: GDBTargetResponse, out: inout ByteBuffer) {
if !isNoAckModeActive {
out.writeInteger(UInt8(ascii: "+"))
Expand All @@ -51,8 +57,9 @@ package class GDBTargetResponseEncoder: MessageToByteEncoder {
out.writeString(str.appendedChecksum)

case .hexEncodedBinary(let binary):
let hexDump = ByteBuffer(bytes: binary).hexDump(format: .compact)
out.writeString(hexDump.appendedChecksum)
let hexDumpResponse = ByteBuffer(bytes: binary).hexDump(format: .compact).appendedChecksum
self.logger.trace("GDBTargetResponseEncoder encoded a response", metadata: ["RawResponse": .string(hexDumpResponse)])
out.writeString(hexDumpResponse)

case .empty:
out.writeString("".appendedChecksum)
Expand Down
2 changes: 2 additions & 0 deletions Sources/WAT/Encoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ extension TableType: WasmEncodable {
struct ElementExprCollector: AnyInstructionVisitor {
typealias Output = Void

var binaryOffset: Int = 0
var isAllRefFunc: Bool = true
var instructions: [Instruction] = []

Expand Down Expand Up @@ -443,6 +444,7 @@ extension WatParser.DataSegmentDecl {
}

struct ExpressionEncoder: BinaryInstructionEncoder {
var binaryOffset: Int = 0
var encoder = Encoder()
var hasDataSegmentInstruction: Bool = false

Expand Down
1 change: 1 addition & 0 deletions Sources/WAT/Parser/WastParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ struct WastParser {
}

struct ConstExpressionCollector: WastConstInstructionVisitor {
var binaryOffset: Int = 0
let addValue: (Value) -> Void

mutating func visitI32Const(value: Int32) throws { addValue(.i32(UInt32(bitPattern: value))) }
Expand Down
1 change: 1 addition & 0 deletions Sources/WasmKit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ add_wasmkit_library(WasmKit
Component/CanonicalCall.swift
Component/CanonicalOptions.swift
Component/ComponentTypes.swift
Execution/DebuggerInstructionMapping.swift
Execution/Instructions/Control.swift
Execution/Instructions/Instruction.swift
Execution/Instructions/Table.swift
Expand Down
201 changes: 201 additions & 0 deletions Sources/WasmKit/Execution/Debugger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
#if WasmDebuggingSupport
/// User-facing debugger state driven by a debugger host. This implementation has no knowledge of the exact
/// debugger protocol, which allows any protocol implementation or direct API users to be layered on top if needed.
package struct Debugger: ~Copyable {
package enum Error: Swift.Error, @unchecked Sendable {
case entrypointFunctionNotFound
case unknownCurrentFunctionForResumedBreakpoint(UnsafeMutablePointer<UInt64>)
case noInstructionMappingAvailable(Int)
case noReverseInstructionMappingAvailable(UnsafeMutablePointer<UInt64>)
}

private let valueStack: Sp
private var execution: Execution
private let store: Store

/// Parsed in-memory representation of a Wasm module instantiated for debugging.
private let module: Module

/// Instance of parsed Wasm ``module``.
private let instance: Instance

/// Reference to the entrypoint function of the currently debugged module, for use in ``stopAtEntrypoint``.
/// Currently assumed to be the WASI command `_start` entrypoint.
private let entrypointFunction: Function

/// Threading model of the Wasm engine configuration, cached for a potentially hot path.
private let threadingModel: EngineConfiguration.ThreadingModel

private(set) var breakpoints = [Int: CodeSlot]()

private var currentBreakpoint: (iseq: Execution.Breakpoint, wasmPc: Int)?

private var pc = Pc.allocate(capacity: 1)

/// Initializes a new debugger state instance.
/// - Parameters:
/// - module: Wasm module to instantiate.
/// - store: Store that instantiates the module.
/// - imports: Imports required by `module` for instantiation.
package init(module: Module, store: Store, imports: Imports) throws {
let limit = store.engine.configuration.stackSize / MemoryLayout<StackSlot>.stride
let instance = try module.instantiate(store: store, imports: imports, isDebuggable: true)

guard case .function(let entrypointFunction) = instance.exports["_start"] else {
throw Error.entrypointFunctionNotFound
}

self.instance = instance
self.module = module
self.entrypointFunction = entrypointFunction
self.valueStack = UnsafeMutablePointer<StackSlot>.allocate(capacity: limit)
self.store = store
self.execution = Execution(store: StoreRef(store), stackEnd: valueStack.advanced(by: limit))
self.threadingModel = store.engine.configuration.threadingModel
self.pc.pointee = Instruction.endOfExecution.headSlot(threadingModel: threadingModel)
}

/// Sets a breakpoint at the first instruction in the entrypoint function of the module instantiated by
/// this debugger.
package mutating func stopAtEntrypoint() throws {
try self.enableBreakpoint(address: self.originalAddress(function: entrypointFunction))
}

/// Finds a Wasm address for the first instruction in a given function.
/// - Parameter function: the Wasm function to find the first Wasm instruction address for.
/// - Returns: byte offset of the first Wasm instruction of given function in the module it was parsed from.
private func originalAddress(function: Function) throws -> Int {
precondition(function.handle.isWasm)

switch function.handle.wasm.code {
case .debuggable(let wasm, _):
return wasm.originalAddress
case .uncompiled:
try function.handle.wasm.ensureCompiled(store: StoreRef(self.store))
return try self.originalAddress(function: function)
case .compiled:
fatalError()
}
}

/// Enables a breakpoint at a given Wasm address.
/// - Parameter address: byte offset of the Wasm instruction that will be replaced with a breakpoint. If no
/// direct internal bytecode matching instruction is found, the next closest internal bytecode instruction
/// is replaced with a breakpoint. The original instruction to be restored is preserved in debugger state
/// represented by `self`.
/// See also ``Debugger/disableBreakpoint(address:)``.
package mutating func enableBreakpoint(address: Int) throws(Error) {
guard self.breakpoints[address] == nil else {
return
}

guard let (iseq, wasm) = try self.instance.handle.instructionMapping.findIseq(forWasmAddress: address) else {
throw Error.noInstructionMappingAvailable(address)
}

self.breakpoints[wasm] = iseq.pointee
iseq.pointee = Instruction.breakpoint.headSlot(threadingModel: self.threadingModel)
}

/// Disables a breakpoint at a given Wasm address. If no breakpoint at a given address was previously set with
/// `self.enableBreakpoint(address:), this function immediately returns.
/// - Parameter address: byte offset of the Wasm instruction that was replaced with a breakpoint. The original
/// instruction is restored from debugger state and replaces the breakpoint instruction.
/// See also ``Debugger/enableBreakpoint(address:)``.
package mutating func disableBreakpoint(address: Int) throws(Error) {
guard let oldCodeSlot = self.breakpoints[address] else {
return
}

guard let (iseq, wasm) = try self.instance.handle.instructionMapping.findIseq(forWasmAddress: address) else {
throw Error.noInstructionMappingAvailable(address)
}

self.breakpoints[wasm] = nil
iseq.pointee = oldCodeSlot
}

/// Resumes the module instantiated by the debugger stopped at a breakpoint. The breakpoint is disabled
/// and execution is resumed until the next breakpoint is triggered or all remaining instructions are
/// executed. If the module is not stopped at a breakpoint, this function returns immediately.
/// - Returns: `[Value]` result of `entrypointFunction` if current instance ran to completion,
/// `nil` if it stopped at a breakpoint.
package mutating func run() throws -> [Value]? {
do {
if let currentBreakpoint {
// Remove the breakpoint before resuming
try self.disableBreakpoint(address: currentBreakpoint.wasmPc)
self.execution.resetError()

var sp = currentBreakpoint.iseq.sp
var pc = currentBreakpoint.iseq.pc
var md: Md = nil
var ms: Ms = 0

guard let currentFunction = sp.currentFunction else {
throw Error.unknownCurrentFunctionForResumedBreakpoint(sp)
}

Execution.CurrentMemory.mayUpdateCurrentInstance(
instance: currentFunction.instance,
from: self.instance.handle,
md: &md,
ms: &ms
)

do {
switch self.threadingModel {
case .direct:
try self.execution.runDirectThreaded(sp: sp, pc: pc, md: md, ms: ms)
case .token:
try self.execution.runTokenThreaded(sp: &sp, pc: &pc, md: &md, ms: &ms)
}
} catch is Execution.EndOfExecution {
}

let type = self.store.engine.funcTypeInterner.resolve(currentFunction.type)
return type.results.enumerated().map { (i, type) in
sp[VReg(i)].cast(to: type)
}
} else {
return try self.execution.executeWasm(
threadingModel: self.threadingModel,
function: self.entrypointFunction.handle,
type: self.entrypointFunction.type,
arguments: [],
sp: self.valueStack,
pc: self.pc
)
}
} catch let breakpoint as Execution.Breakpoint {
let pc = breakpoint.pc
guard let wasmPc = self.instance.handle.instructionMapping.findWasm(forIseqAddress: pc) else {
throw Error.noReverseInstructionMappingAvailable(pc)
}

self.currentBreakpoint = (breakpoint, wasmPc)
return nil
}
}

/// Array of addresses in the Wasm binary of executed instructions on the call stack.
package var currentCallStack: [Int] {
guard let currentBreakpoint else {
return []
}

var result = Execution.captureBacktrace(sp: currentBreakpoint.iseq.sp, store: self.store).symbols.compactMap {
return self.instance.handle.instructionMapping.findWasm(forIseqAddress: $0.address)
}
result.append(currentBreakpoint.wasmPc)

return result
}

deinit {
self.valueStack.deallocate()
self.pc.deallocate()
}
}

#endif
Loading