Skip to content

Commit e1a5524

Browse files
committed
Implement .readMemory command handling
1 parent c3b9ebd commit e1a5524

File tree

5 files changed

+69
-13
lines changed

5 files changed

+69
-13
lines changed

[email protected]

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,11 @@ let package = Package(
134134
.target(
135135
name: "WasmKitGDBHandler",
136136
dependencies: [
137+
.product(name: "_NIOFileSystem", package: "swift-nio"),
137138
.product(name: "NIOCore", package: "swift-nio"),
138139
.product(name: "SystemPackage", package: "swift-system"),
139140
"WasmKit",
141+
"WasmKitWASI",
140142
"GDBRemoteProtocol",
141143
],
142144
),

Sources/GDBRemoteProtocol/GDBTargetResponse.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import NIOCore
2+
13
/// Actions supported in the `vCont` host command.
24
package enum VContActions: String {
35
case `continue` = "c"
@@ -13,7 +15,8 @@ package struct GDBTargetResponse {
1315
case ok
1416
case keyValuePairs(KeyValuePairs<String, String>)
1517
case vContSupportedActions([VContActions])
16-
case raw(String)
18+
case string(String)
19+
case hexEncodedBinary(ByteBufferView)
1720
case empty
1821
}
1922

Sources/GDBRemoteProtocol/GDBTargetResponseEncoder.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@ package class GDBTargetResponseEncoder: MessageToByteEncoder {
3030
case .vContSupportedActions(let actions):
3131
out.writeString("vCont;\(actions.map { "\($0.rawValue);" }.joined())".appendedChecksum)
3232

33-
case .raw(let str):
33+
case .string(let str):
3434
out.writeString(str.appendedChecksum)
3535

36+
case .hexEncodedBinary(let binary):
37+
let hexDump = ByteBuffer(bytes: binary).hexDump(format: .compact)
38+
out.writeString(hexDump.appendedChecksum)
39+
3640
case .empty:
3741
out.writeString("".appendedChecksum)
3842
}

Sources/WasmKitGDBHandler/WasmKitDebugger.swift renamed to Sources/WasmKitGDBHandler/WasmKitGDBHandler.swift

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,61 @@
11
import GDBRemoteProtocol
22
import Logging
3+
import NIOCore
4+
import NIOFileSystem
35
import Synchronization
46
import SystemPackage
57
import WasmKit
8+
import WasmKitWASI
9+
10+
extension BinaryInteger {
11+
init?(hexEncoded: Substring) {
12+
var result = Self.zero
13+
for (offset, element) in hexEncoded.reversed().enumerated() {
14+
guard let digit = element.hexDigitValue else { return nil }
15+
result += Self(digit) << (offset * 4)
16+
}
17+
18+
self = result
19+
}
20+
}
621

722
package actor WasmKitGDBHandler {
823
enum Error: Swift.Error {
924
case unknownTransferArguments
25+
case unknownReadMemoryArguments
26+
case entrypointFunctionNotFound
1027
}
1128

29+
private let wasmBinary: ByteBuffer
1230
private let module: Module
1331
private let moduleFilePath: FilePath
1432
private let logger: Logger
1533
private let debuggerExecution: DebuggerExecution
1634
private let instance: Instance
35+
private let entrypointFunction: Function
36+
private let functionsRLE: [(wasmAddress: Int, iSeqAddress: Int)] = []
1737

18-
package init(logger: Logger, moduleFilePath: FilePath) throws {
38+
package init(logger: Logger, moduleFilePath: FilePath) async throws {
1939
self.logger = logger
20-
self.module = try parseWasm(filePath: moduleFilePath)
40+
41+
self.wasmBinary = try await FileSystem.shared.withFileHandle(forReadingAt: moduleFilePath) {
42+
try await $0.readToEnd(maximumSizeAllowed: .unlimited)
43+
}
44+
45+
self.module = try parseWasm(bytes: .init(buffer: self.wasmBinary))
2146
self.moduleFilePath = moduleFilePath
2247
let store = Store(engine: Engine())
2348
self.debuggerExecution = DebuggerExecution(store: store)
24-
self.instance = try module.instantiate(store: store)
49+
50+
var imports = Imports()
51+
let wasi = try WASIBridgeToHost()
52+
wasi.link(to: &imports, store: store)
53+
self.instance = try module.instantiate(store: store, imports: imports)
54+
55+
guard case .function(let entrypointFunction) = self.instance.exports["_start"] else {
56+
throw Error.entrypointFunctionNotFound
57+
}
58+
self.entrypointFunction = entrypointFunction
2559
}
2660

2761
package func handle(command: GDBHostCommand) throws -> GDBTargetResponse {
@@ -47,7 +81,7 @@ package actor WasmKitGDBHandler {
4781
])
4882

4983
case .supportedFeatures:
50-
responseKind = .raw("qXfer:libraries:read+;PacketSize=1000;")
84+
responseKind = .string("qXfer:libraries:read+;PacketSize=1000;")
5185

5286
case .vContSupportedActions:
5387
responseKind = .vContSupportedActions([.continue, .step])
@@ -65,13 +99,13 @@ package actor WasmKitGDBHandler {
6599
])
66100

67101
case .currentThreadID:
68-
responseKind = .raw("QC1")
102+
responseKind = .string("QC1")
69103

70104
case .firstThreadInfo:
71-
responseKind = .raw("m1")
105+
responseKind = .string("m1")
72106

73107
case .subsequentThreadInfo:
74-
responseKind = .raw("l")
108+
responseKind = .string("l")
75109

76110
case .targetStatus:
77111
responseKind = .keyValuePairs([
@@ -93,12 +127,12 @@ package actor WasmKitGDBHandler {
93127
"generic": "pc",
94128
])
95129
} else {
96-
responseKind = .raw("E45")
130+
responseKind = .string("E45")
97131
}
98132

99133
case .transfer:
100134
if command.arguments.starts(with: "libraries:read:") {
101-
responseKind = .raw(
135+
responseKind = .string(
102136
"""
103137
l<library-list>
104138
<library name="\(self.moduleFilePath.string)"><section address="0x4000000000000000"/></library>
@@ -109,7 +143,20 @@ package actor WasmKitGDBHandler {
109143
}
110144

111145
case .readMemory:
112-
responseKind = .empty
146+
let argumentsArray = command.arguments.split(separator: ",")
147+
guard
148+
argumentsArray.count == 2,
149+
let address = UInt64(hexEncoded: argumentsArray[0]),
150+
var length = Int(hexEncoded: argumentsArray[1])
151+
else { throw Error.unknownReadMemoryArguments }
152+
153+
let binaryOffset = Int(address - 0x4000000000000000)
154+
155+
if binaryOffset + length > wasmBinary.readableBytes {
156+
length = wasmBinary.readableBytes - binaryOffset
157+
}
158+
159+
responseKind = .hexEncodedBinary(wasmBinary.readableBytesView[binaryOffset..<(binaryOffset + length)])
113160

114161
case .wasmCallStack:
115162
print(self.debuggerExecution.captureBacktrace())

Sources/wasmkit-gdb-tool/Entrypoint.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ struct Entrypoint: AsyncParsableCommand {
8181
/* the server will now be accepting connections */
8282
logger.info("listening on port \(port)")
8383

84-
let debugger = try WasmKitGDBHandler(logger: logger, moduleFilePath: self.wasmModulePath)
84+
let debugger = try await WasmKitGDBHandler(logger: logger, moduleFilePath: self.wasmModulePath)
8585

8686
try await withThrowingDiscardingTaskGroup { group in
8787
try await serverChannel.executeThenClose { serverChannelInbound in

0 commit comments

Comments
 (0)