Skip to content

Commit adaec2b

Browse files
authored
Fix lldb-dap connection, add decodingUnknownCommand test (#324)
When `lldb-dap` connects to WasmKit via `process connect -p wasm`, it sends GDB Remote Protocol commands that WasmKit doesn't recognize (e.g., `p` for reading a single register, `H` for setting thread context, `qLaunchSuccess`). The `GDBHostCommandDecoder` throws `unknownCommand`, which propagates through the NIO pipeline and kills the connection. Per the GDB protocol spec, unrecognized commands should receive an empty response (`$#00`) and the connection should continue.
1 parent b55972c commit adaec2b

4 files changed

Lines changed: 31 additions & 10 deletions

File tree

Sources/GDBRemoteProtocol/GDBHostCommand.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ package struct GDBHostCommand: Equatable {
5252
case detach
5353

5454
case generalRegisters
55+
case unsupported
5556

5657
/// Decodes kind of a command from a raw string sent from a host.
5758
package init?(rawValue: String) {
@@ -169,7 +170,7 @@ package struct GDBHostCommand: Equatable {
169170
/// - Parameters:
170171
/// - kindString: raw ``String`` that denotes kind of the command.
171172
/// - arguments: raw arguments that immediately follow kind of the command.
172-
package init(kindString: String, arguments: String) throws(GDBHostCommandDecoder.Error) {
173+
package init(kindString: String, arguments: String) {
173174
for rule in Self.parsingRules {
174175
if kindString.starts(with: rule.prefix) {
175176
self.kind = rule.kind
@@ -186,11 +187,11 @@ package struct GDBHostCommand: Equatable {
186187

187188
if let kind = Kind(rawValue: kindString) {
188189
self.kind = kind
190+
self.arguments = arguments
189191
} else {
190-
throw GDBHostCommandDecoder.Error.unknownCommand(kind: kindString, arguments: arguments)
192+
self.kind = .unsupported
193+
self.arguments = arguments.isEmpty ? kindString : "\(kindString):\(arguments)"
191194
}
192-
193-
self.arguments = arguments
194195
}
195196

196197
/// Member-wise initializer of `GDBHostCommand` type.

Sources/GDBRemoteProtocol/GDBHostCommandDecoder.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@ package struct GDBHostCommandDecoder: ByteToMessageDecoder {
5151
/// Unexpected arguments value supplied for a given command.
5252
case unexpectedArgumentsValue
5353

54-
/// Host command kind could not be parsed. See `GDBHostCommand.Kind` for the
55-
/// list of supported commands.
56-
case unknownCommand(kind: String, arguments: String)
5754
}
5855

5956
/// Type of the output value produced by this decoder.
@@ -180,7 +177,7 @@ package struct GDBHostCommandDecoder: ByteToMessageDecoder {
180177
)
181178
}
182179

183-
let payload = try GDBHostCommand(
180+
let payload = GDBHostCommand(
184181
kindString: String(decoding: self.accummulatedKind, as: UTF8.self),
185182
arguments: String(decoding: self.accummulatedArguments, as: UTF8.self)
186183
)

Sources/WasmKitGDBHandler/WasmKitGDBHandler.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
case stoppingAtEntrypointFailed
4545
case multipleThreadsNotSupported
4646
case unknownThreadAction(String)
47-
case hostCommandNotImplemented(GDBHostCommand.Kind)
47+
4848
case exitCodeUnknown([Value])
4949
case killRequestReceived
5050
case unknownHexEncodedArguments(String)
@@ -333,7 +333,14 @@
333333
responseKind = .empty
334334

335335
case .generalRegisters:
336-
throw Error.hostCommandNotImplemented(command.kind)
336+
responseKind = .empty
337+
338+
case .unsupported:
339+
logger.debug(
340+
"unsupported GDB host command",
341+
metadata: ["rawCommand": .string(command.arguments)]
342+
)
343+
responseKind = .empty
337344
}
338345

339346
logger.trace("handler produced a response", metadata: ["GDBTargetResponse": .string("\(responseKind)")])

Tests/GDBRemoteProtocolTests/GDBRemoteProtocolTests.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@ import Testing
1717

1818
@Suite
1919
struct GDBRemoteProtocolTests {
20+
var decoder: GDBHostCommandDecoder {
21+
var logger = Logger(label: "com.swiftwasm.WasmKit.tests")
22+
logger.logLevel = .critical
23+
return GDBHostCommandDecoder(logger: logger)
24+
}
25+
26+
@Test
27+
func decodingUnknownCommand() throws {
28+
var decoder = self.decoder
29+
// "p0" is "read single register 0" — not supported by WasmKit
30+
var buffer = ByteBuffer(string: "+$p0#a0")
31+
let packet = try decoder.decode(buffer: &buffer)
32+
#expect(packet?.payload.kind == .unsupported)
33+
#expect(packet?.payload.arguments == "p0")
34+
}
35+
2036
@Test
2137
func decoding() throws {
2238
var logger = Logger(label: "com.swiftwasm.WasmKit.tests")

0 commit comments

Comments
 (0)