Index: build_tools/debug_server/debug_server/common/rsp_packetizer.cc |
=================================================================== |
--- build_tools/debug_server/debug_server/common/rsp_packetizer.cc (revision 0) |
+++ build_tools/debug_server/debug_server/common/rsp_packetizer.cc (revision 0) |
@@ -0,0 +1,154 @@ |
+#include "rsp_packetizer.h" |
+ |
+// Description of GDB RSP protocol: |
+// http://sources.redhat.com/gdb/current/onlinedocs/gdb.html#Remote-Protocol |
+ |
+namespace rsp { |
+ |
+Packetizer::Packetizer() |
+ : state_(IDLE), |
+ consumer_(NULL), |
+ calculated_checksum_(0), |
+ recv_checksum_(0) { |
+ Reset(); |
+} |
+ |
+Packetizer::~Packetizer() { |
+} |
+ |
+void Packetizer::SetPacketConsumer(PacketConsumer* consumer) { |
+ consumer_ = consumer; |
+} |
+ |
+void Packetizer::Reset() { |
+ state_ = IDLE; |
+ body_.Clear(); |
+ calculated_checksum_ = 0; |
+ recv_checksum_ = 0; |
+} |
+ |
+bool Packetizer::IsIdle() const { |
+ return (state_ == IDLE); |
+} |
+ |
+void Packetizer::OnData(const debug::Blob& data) { |
+ for (size_t i = 0; i < data.Size(); i++) |
+ OnChar(data[i]); |
+} |
+ |
+void Packetizer::OnData(const void* data, size_t data_length) { |
+ const unsigned char* cdata = static_cast<const unsigned char*>(data); |
+ if (NULL == data) |
+ return; |
+ if (-1 == data_length) |
+ data_length = static_cast<int>(strlen(static_cast<const char*>(data))); |
+ if (data_length < 0) |
+ return; |
+ for (size_t i = 0; i < data_length; i++) { |
+ unsigned char c = *cdata++; |
+ OnChar(c); |
+ } |
+} |
+ |
+void Packetizer::OnChar(unsigned char c) { |
+ if (NULL == consumer_) |
+ return; |
+ |
+ if (((BODY == state_) && ('#' != c)) || |
+ (ESCAPE == state_) || |
+ (RUNLEN == state_)) |
+ AddToChecksum(c); |
+ |
+ switch (state_) { |
+ case IDLE: { |
+ if (('+' == c) || ('-' == c)) |
+ return; |
+ if ('$' == c) |
+ state_ = BODY; |
+ else if (3 == c) |
+ consumer_->OnBreak(); |
+ else |
+ consumer_->OnUnexpectedChar(c); |
+ break; |
+ } |
+ case BODY: { |
+ if ('}' == c) |
+ state_ = ESCAPE; |
+ else if ('#' == c) |
+ state_ = END; |
+ else if ('*' == c) |
+ state_ = RUNLEN; |
+ else if (c > 126) |
+ consumer_->OnUnexpectedChar(c); |
+ else |
+ AddCharToBody(c); |
+ break; |
+ } |
+ case ESCAPE: { |
+ c = c ^ 0x20; |
+ AddCharToBody(c); |
+ state_ = BODY; |
+ break; |
+ } |
+ case RUNLEN: { |
+ int n = c - 29; |
+ AddRepeatedChars(n); |
+ state_ = BODY; |
+ break; |
+ } |
+ case END: { |
+ if (HexCharToint(c, &recv_checksum_)) { |
+ recv_checksum_ <<= 4; |
+ state_ = CHECKSUM; |
+ } |
+ break; |
+ } |
+ case CHECKSUM: { |
+ unsigned int digit = 0; |
+ if (HexCharToint(c, &digit)) { |
+ recv_checksum_ += digit; |
+ bool checksum_valid = (recv_checksum_ == calculated_checksum_); |
+ consumer_->OnPacket(body_, checksum_valid); |
+ Reset(); |
+ } |
+ break; |
+ } |
+ } |
+} |
+ |
+void Packetizer::AddToChecksum(unsigned char c) { |
+ calculated_checksum_ += c; |
+ calculated_checksum_ %= 256; |
+} |
+ |
+void Packetizer::AddCharToBody(unsigned char c) { |
+ body_.PushBack(c); |
+} |
+ |
+void Packetizer::AddRepeatedChars(size_t n) { |
+ size_t len = body_.Size(); |
+ if (0 != len) { |
+ char c = body_[len - 1]; |
+ for (size_t i = 0; i < n; i++) |
+ AddCharToBody(c); |
+ } |
+} |
+ |
+bool Packetizer::HexCharToint(unsigned char c, unsigned int* result) { |
+ if (('0' <= c) && ('9' >= c)) { |
+ *result = c - '0'; |
+ } |
+ else if (('A' <= c) && ('F' >= c)) { |
+ *result = c - 'A' + 10; |
+ } |
+ else if (('a' <= c) && ('f' >= c)) { |
+ *result = c - 'a' + 10; |
+ } |
+ else { |
+ consumer_->OnUnexpectedChar(c); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+} // namespace rsp |