Skip to content

Commit 3b2e30f

Browse files
committed
Add doc comments for GDBHostCommandDecoder
1 parent 2acd4f3 commit 3b2e30f

File tree

3 files changed

+59
-20
lines changed

3 files changed

+59
-20
lines changed

Sources/GDBRemoteProtocol/GDBHostCommand.swift

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616
/// * https://sourceware.org/gdb/current/onlinedocs/gdb.html/General-Query-Packets.html
1717
/// * https://lldb.llvm.org/resources/lldbgdbremote.html
1818
package struct GDBHostCommand: Equatable {
19-
enum Error: Swift.Error {
20-
case unexpectedArgumentsValue
21-
case unknownCommand(kind: String, arguments: String)
22-
}
23-
2419
package enum Kind: String, Equatable {
2520
// Currently listed in the order that LLDB sends them in.
2621
case startNoAckMode
@@ -94,8 +89,12 @@ package struct GDBHostCommand: Equatable {
9489

9590
/// Arguments supplied with a host command.
9691
package let arguments: String
97-
98-
package init(kindString: String, arguments: String) throws {
92+
93+
/// Initialize a host command from raw strings sent from a host.
94+
/// - Parameters:
95+
/// - kindString: raw ``String`` that denotes kind of the command.
96+
/// - arguments: raw arguments that immediately follow kind of the command.
97+
package init(kindString: String, arguments: String) throws(GDBHostCommandDecoder.Error) {
9998
let registerInfoPrefix = "qRegisterInfo"
10099

101100
if kindString.starts(with: "x") {
@@ -110,20 +109,20 @@ package struct GDBHostCommand: Equatable {
110109
self.kind = .registerInfo
111110

112111
guard arguments.isEmpty else {
113-
throw Error.unexpectedArgumentsValue
112+
throw GDBHostCommandDecoder.Error.unexpectedArgumentsValue
114113
}
115114
self.arguments = String(kindString.dropFirst(registerInfoPrefix.count))
116115
return
117116
} else if let kind = Kind(rawValue: kindString) {
118117
self.kind = kind
119118
} else {
120-
throw Error.unknownCommand(kind: kindString, arguments: arguments)
119+
throw GDBHostCommandDecoder.Error.unknownCommand(kind: kindString, arguments: arguments)
121120
}
122121

123122
self.arguments = arguments
124123
}
125124

126-
/// Memberwise initializer of `GDBHostCommand` type.
125+
/// Member-wise initializer of `GDBHostCommand` type.
127126
package init(kind: Kind, arguments: String) {
128127
self.kind = kind
129128
self.arguments = arguments

Sources/GDBRemoteProtocol/GDBHostCommandDecoder.swift

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,58 +14,93 @@ import Logging
1414
import NIOCore
1515

1616
extension ByteBuffer {
17+
/// Returns `true` if byte to be read immediately is a GDB RP checksum
18+
/// delimiter. Returns `false` otherwise.
1719
var isChecksumDelimiterAtReader: Bool {
1820
self.peekInteger(as: UInt8.self) == UInt8(ascii: "#")
1921
}
2022

23+
/// Returns `true` if byte to be read immediately is a GDB RP command arguments
24+
/// delimiter. Returns `false` otherwise.
2125
var isArgumentsDelimiterAtReader: Bool {
2226
self.peekInteger(as: UInt8.self) == UInt8(ascii: ":")
2327
}
2428
}
2529

30+
/// Decoder of GDB RP host commands, that takes raw `ByteBuffer` as an input encoded
31+
/// per https://sourceware.org/gdb/current/onlinedocs/gdb.html/Overview.html#Overview
32+
/// and produces a `GDBPacket<GDBHostCommand>` value as output. This decoder is
33+
/// compatible with NIO channel pipelines, making it easy to integrate with different
34+
/// I/O configurations.
2635
package struct GDBHostCommandDecoder: ByteToMessageDecoder {
27-
enum Error: Swift.Error {
36+
/// Errors that can be thrown during host command decoding.
37+
package enum Error: Swift.Error {
38+
/// Expected `+` acknowledgement character to be included in the packet, when
39+
/// ``GDBHostCommandDecoder/isNoAckModeActive`` is set to `false`.
2840
case expectedAck
41+
42+
/// Expected command to start with `$` character`.
2943
case expectedCommandStart
30-
case unknownCommandKind(String)
44+
45+
/// Expected checksum to be included with the packet was not found.
3146
case expectedChecksum
47+
48+
/// Expected checksum included with the packet did not match the expected value.
3249
case checksumIncorrect(expectedChecksum: Int, receivedChecksum: UInt8)
50+
51+
/// Unexpected arguments value supplied for a given command.
52+
case unexpectedArgumentsValue
53+
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)
3357
}
3458

59+
/// Type of the output value produced by this decoder.
3560
package typealias InboundOut = GDBPacket<GDBHostCommand>
3661

3762
private var accumulatedDelimiter: UInt8?
3863

3964
private var accummulatedKind = [UInt8]()
4065
private var accummulatedArguments = [UInt8]()
41-
66+
67+
/// Logger instance used by this decoder.
4268
private let logger: Logger
43-
69+
70+
/// Initializes a new decoder.
71+
/// - Parameter logger: logger instance that consumes messages from the newly
72+
/// initialized decoder.
4473
package init(logger: Logger) { self.logger = logger }
45-
74+
75+
/// Sum of the raw character values consumed in the current command so far,
76+
/// used in checksum computation.
4677
private var accummulatedSum = 0
78+
79+
/// Computed checksum for the values consumed in the current command so far.
4780
package var accummulatedChecksum: UInt8 {
4881
UInt8(self.accummulatedSum % 256)
4982
}
5083

5184
private var isNoAckModeRequested = false
5285
private var isNoAckModeActive = false
5386

54-
mutating package func decode(buffer: inout ByteBuffer) throws -> GDBPacket<GDBHostCommand>? {
87+
package mutating func decode(
88+
buffer: inout ByteBuffer
89+
) throws(Error) -> GDBPacket<GDBHostCommand>? {
5590
guard var startDelimiter = self.accumulatedDelimiter ?? buffer.readInteger(as: UInt8.self) else {
5691
// Not enough data to parse.
5792
return nil
5893
}
5994

60-
if !isNoAckModeActive {
95+
if !self.isNoAckModeActive {
6196
let firstStartDelimiter = startDelimiter
6297

6398
guard firstStartDelimiter == UInt8(ascii: "+") else {
6499
logger.error("unexpected ack character: \(Character(UnicodeScalar(startDelimiter)))")
65100
throw Error.expectedAck
66101
}
67102

68-
if isNoAckModeRequested {
103+
if self.isNoAckModeRequested {
69104
self.isNoAckModeActive = true
70105
}
71106

@@ -82,7 +117,7 @@ package struct GDBHostCommandDecoder: ByteToMessageDecoder {
82117

83118
// Command start delimiters.
84119
guard startDelimiter == UInt8(ascii: "$") else {
85-
logger.error("unexpected delimiter: \(Character(UnicodeScalar(startDelimiter)))")
120+
self.logger.error("unexpected delimiter: \(Character(UnicodeScalar(startDelimiter)))")
86121
throw Error.expectedCommandStart
87122
}
88123

@@ -151,7 +186,7 @@ package struct GDBHostCommandDecoder: ByteToMessageDecoder {
151186
mutating package func decode(
152187
context: ChannelHandlerContext,
153188
buffer: inout ByteBuffer
154-
) throws -> DecodingState {
189+
) throws(Error) -> DecodingState {
155190
logger.trace(.init(stringLiteral: buffer.peekString(length: buffer.readableBytes)!))
156191

157192
guard let command = try self.decode(buffer: &buffer) else {

Sources/GDBRemoteProtocol/GDBPacket.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
/// GDB host commands and target responses are wrapped with delimiters followed
14+
/// by a single byte checksum value. This type denotes such a packet by attaching
15+
/// a checksum value to the contained payload.
16+
/// See GDB remote protocol overview for more details:
17+
/// https://sourceware.org/gdb/current/onlinedocs/gdb.html/Overview.html#Overview
1318
package struct GDBPacket<Payload: Sendable>: Sendable {
1419
package let payload: Payload
1520
package let checksum: UInt8

0 commit comments

Comments
 (0)