Implemented disabling of GDB packet acknowledgement, and disabled it by default. The new packetAcknowledgement debug server config param can be used to keep it enabled.
This commit is contained in:
@@ -155,11 +155,18 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::pair<Feature, std::optional<std::string>>> AvrGdbRsp::getSupportedFeatures() {
|
std::set<std::pair<Feature, std::optional<std::string>>> AvrGdbRsp::getSupportedFeatures() {
|
||||||
return {
|
auto output = std::set<std::pair<Feature, std::optional<std::string>>>{
|
||||||
|
{Feature::HARDWARE_BREAKPOINTS, std::nullopt},
|
||||||
{Feature::SOFTWARE_BREAKPOINTS, std::nullopt},
|
{Feature::SOFTWARE_BREAKPOINTS, std::nullopt},
|
||||||
{Feature::MEMORY_MAP_READ, std::nullopt},
|
{Feature::MEMORY_MAP_READ, std::nullopt},
|
||||||
{Feature::VCONT_ACTIONS_QUERY, std::nullopt},
|
{Feature::VCONT_ACTIONS_QUERY, std::nullopt},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!this->debugServerConfig.packetAcknowledgement) {
|
||||||
|
output.emplace(Feature::NO_ACK_MODE, std::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvrGdbRsp::handleTargetStoppedGdbResponse(Targets::TargetMemoryAddress programAddress) {
|
void AvrGdbRsp::handleTargetStoppedGdbResponse(Targets::TargetMemoryAddress programAddress) {
|
||||||
|
|||||||
@@ -61,6 +61,17 @@ namespace DebugServer::Gdb::CommandPackets
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!debugSession.serverConfig.packetAcknowledgement && packetString.find("QStartNoAckMode") == 0) {
|
||||||
|
Logger::info("Handling QStartNoAckMode");
|
||||||
|
/*
|
||||||
|
* We respond to the command before actually disabling packet acknowledgement, because GDB will send one
|
||||||
|
* final acknowledgement byte to acknowledge the response.
|
||||||
|
*/
|
||||||
|
debugSession.connection.writePacket(OkResponsePacket{});
|
||||||
|
debugSession.connection.packetAcknowledgement = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Logger::debug("Unknown GDB RSP packet: " + packetString + " - returning empty response");
|
Logger::debug("Unknown GDB RSP packet: " + packetString + " - returning empty response");
|
||||||
|
|
||||||
// GDB expects an empty response for all unsupported commands
|
// GDB expects an empty response for all unsupported commands
|
||||||
|
|||||||
@@ -135,8 +135,10 @@ namespace DebugServer::Gdb
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Acknowledge receipt
|
if (this->packetAcknowledgement) {
|
||||||
this->write({'+'});
|
// Acknowledge receipt
|
||||||
|
this->write({'+'});
|
||||||
|
}
|
||||||
|
|
||||||
output.emplace_back(std::move(rawPacket));
|
output.emplace_back(std::move(rawPacket));
|
||||||
byteIndex = packetIndex;
|
byteIndex = packetIndex;
|
||||||
@@ -149,22 +151,32 @@ namespace DebugServer::Gdb
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Connection::writePacket(const ResponsePacket& packet) {
|
void Connection::writePacket(const ResponsePacket& packet) {
|
||||||
// Write the packet repeatedly until the GDB client acknowledges it.
|
|
||||||
int attempts = 0;
|
|
||||||
const auto rawPacket = packet.toRawPacket();
|
const auto rawPacket = packet.toRawPacket();
|
||||||
|
|
||||||
Logger::debug("Writing GDB packet: " + std::string{rawPacket.begin(), rawPacket.end()});
|
Logger::debug("Writing GDB packet: " + std::string{rawPacket.begin(), rawPacket.end()});
|
||||||
|
|
||||||
do {
|
this->write(rawPacket);
|
||||||
if (attempts > 10) {
|
|
||||||
throw ClientCommunicationError{
|
|
||||||
"Failed to write GDB response packet - client failed to acknowledge receipt - retry limit reached"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
this->write(rawPacket);
|
if (this->packetAcknowledgement) {
|
||||||
attempts++;
|
auto attempts = std::size_t{0};
|
||||||
} while (this->readSingleByte(false).value_or(0) != '+');
|
auto ackByte = this->readSingleByte(false);
|
||||||
|
while (ackByte != '+') {
|
||||||
|
if (attempts > 10) {
|
||||||
|
throw ClientCommunicationError{
|
||||||
|
"Failed to write GDB response packet - client failed to acknowledge receipt - retry limit reached"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ackByte == '-') {
|
||||||
|
// GDB has requested retransmission
|
||||||
|
Logger::debug("Sending packet again, upon GDB's request");
|
||||||
|
this->write(rawPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
ackByte = this->readSingleByte(false);
|
||||||
|
++attempts;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::accept(int serverSocketFileDescriptor) {
|
void Connection::accept(int serverSocketFileDescriptor) {
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ namespace DebugServer::Gdb
|
|||||||
*/
|
*/
|
||||||
static constexpr auto ABSOLUTE_MAXIMUM_PACKET_READ_SIZE = 2097000; // 2MiB
|
static constexpr auto ABSOLUTE_MAXIMUM_PACKET_READ_SIZE = 2097000; // 2MiB
|
||||||
|
|
||||||
|
bool packetAcknowledgement = true;
|
||||||
|
|
||||||
Connection(int serverSocketFileDescriptor, EventFdNotifier& interruptEventNotifier);
|
Connection(int serverSocketFileDescriptor, EventFdNotifier& interruptEventNotifier);
|
||||||
|
|
||||||
Connection() = delete;
|
Connection() = delete;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace DebugServer::Gdb
|
|||||||
PACKET_SIZE,
|
PACKET_SIZE,
|
||||||
MEMORY_MAP_READ,
|
MEMORY_MAP_READ,
|
||||||
VCONT_ACTIONS_QUERY,
|
VCONT_ACTIONS_QUERY,
|
||||||
|
NO_ACK_MODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline BiMap<Feature, std::string> getGdbFeatureToNameMapping() {
|
static inline BiMap<Feature, std::string> getGdbFeatureToNameMapping() {
|
||||||
@@ -20,6 +21,7 @@ namespace DebugServer::Gdb
|
|||||||
{Feature::PACKET_SIZE, "PacketSize"},
|
{Feature::PACKET_SIZE, "PacketSize"},
|
||||||
{Feature::MEMORY_MAP_READ, "qXfer:memory-map:read"},
|
{Feature::MEMORY_MAP_READ, "qXfer:memory-map:read"},
|
||||||
{Feature::VCONT_ACTIONS_QUERY, "vContSupported"},
|
{Feature::VCONT_ACTIONS_QUERY, "vContSupported"},
|
||||||
|
{Feature::NO_ACK_MODE, "QStartNoAckMode"},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,5 +42,17 @@ namespace DebugServer::Gdb
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (debugServerConfig.debugServerNode["packetAcknowledgement"]) {
|
||||||
|
if (YamlUtilities::isCastable<bool>(debugServerConfig.debugServerNode["packetAcknowledgement"])) {
|
||||||
|
this->packetAcknowledgement = debugServerConfig.debugServerNode["packetAcknowledgement"].as<bool>();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Logger::error(
|
||||||
|
"Invalid GDB debug server config parameter ('packetAcknowledgement') provided - value must be"
|
||||||
|
" castable to a boolean. The parameter will be ignored."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,19 @@ namespace DebugServer::Gdb
|
|||||||
*/
|
*/
|
||||||
bool rangeStepping = true;
|
bool rangeStepping = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether Bloom will seek to disable packet acknowledgement with GDB, at the start of the debug
|
||||||
|
* session.
|
||||||
|
*
|
||||||
|
* If this is set to false, Bloom will communicate its ability to disable package acknowledgment to GDB.
|
||||||
|
* GDB may then send the appropriate packet to disable packet acknowledgment. However, this isn't
|
||||||
|
* guaranteed - GDB may be configured to keep packet acknowledgment enabled (via the
|
||||||
|
* `set remote noack-packet off` command).
|
||||||
|
*
|
||||||
|
* This parameter is optional. If not specified, the default value set here will be used.
|
||||||
|
*/
|
||||||
|
bool packetAcknowledgement = false;
|
||||||
|
|
||||||
explicit GdbDebugServerConfig(const DebugServerConfig& debugServerConfig);
|
explicit GdbDebugServerConfig(const DebugServerConfig& debugServerConfig);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user