OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 #include "debugger/rsp/rsp_packetizer.h" | |
5 | |
6 // Description of GDB RSP protocol: | |
7 // http://sources.redhat.com/gdb/current/onlinedocs/gdb.html#Remote-Protocol | |
8 | |
9 namespace { | |
10 const int kMaxCharValue = 126; | |
11 const int kEscapeXor = 0x20; | |
12 } // namespace | |
13 | |
14 namespace rsp { | |
15 | |
16 Packetizer::Packetizer() | |
17 : state_(IDLE), | |
18 consumer_(NULL), | |
19 calculated_checksum_(0), | |
20 recv_checksum_(0) { | |
21 Reset(); | |
22 } | |
23 | |
24 Packetizer::~Packetizer() { | |
25 } | |
26 | |
27 void Packetizer::SetPacketConsumer(PacketConsumerInterface* consumer) { | |
28 consumer_ = consumer; | |
29 } | |
30 | |
31 void Packetizer::Reset() { | |
32 state_ = IDLE; | |
33 body_.Clear(); | |
34 calculated_checksum_ = 0; | |
35 recv_checksum_ = 0; | |
36 } | |
37 | |
38 void Packetizer::OnData(const debug::Blob& data) { | |
39 for (size_t i = 0; i < data.size(); i++) | |
40 OnByte(data[i]); | |
41 } | |
42 | |
43 void Packetizer::OnData(const void* data, size_t data_length) { | |
44 const uint8_t* cdata = static_cast<const uint8_t*>(data); | |
45 if (NULL == data) | |
46 return; | |
47 for (size_t i = 0; i < data_length; i++) { | |
48 uint8_t c = *cdata++; | |
49 OnByte(c); | |
50 } | |
51 } | |
52 | |
53 void Packetizer::OnByte(uint8_t c) { | |
54 if (NULL == consumer_) | |
55 return; | |
56 | |
57 if (((BODY == state_) && ('#' != c)) || | |
58 (ESCAPE == state_) || (RUNLEN == state_)) | |
59 AddByteToChecksum(c); | |
60 | |
61 switch (state_) { | |
62 case IDLE: { | |
63 if (('+' == c) || ('-' == c)) | |
64 return; | |
65 if ('$' == c) | |
66 state_ = BODY; | |
67 else if (3 == c) // RSP is using Ctrl-C as a break message. | |
68 consumer_->OnBreak(); | |
69 else | |
70 consumer_->OnUnexpectedByte(c); | |
71 break; | |
72 } | |
73 case BODY: { | |
74 if ('}' == c) | |
75 state_ = ESCAPE; | |
76 else if ('#' == c) | |
77 state_ = END; | |
78 else if ('*' == c) | |
79 state_ = RUNLEN; | |
80 else if (c > kMaxCharValue) | |
81 consumer_->OnUnexpectedByte(c); | |
82 else | |
83 AddByteToBody(c); | |
84 break; | |
85 } | |
86 case ESCAPE: { | |
87 c = c ^ kEscapeXor; | |
88 AddByteToBody(c); | |
89 state_ = BODY; | |
90 break; | |
91 } | |
92 case RUNLEN: { | |
93 int n = c - 29; | |
94 AddRepeatedBytes(n); | |
95 state_ = BODY; | |
96 break; | |
97 } | |
98 case END: { | |
99 if (debug::Blob::HexCharToInt(c, &recv_checksum_)) { | |
100 recv_checksum_ <<= 4; | |
101 state_ = CHECKSUM; | |
102 } else { | |
103 consumer_->OnUnexpectedByte(c); | |
104 } | |
105 break; | |
106 } | |
107 case CHECKSUM: { | |
108 unsigned int digit = 0; | |
109 if (debug::Blob::HexCharToInt(c, &digit)) { | |
110 recv_checksum_ += digit; | |
111 bool checksum_valid = (recv_checksum_ == calculated_checksum_); | |
112 consumer_->OnPacket(body_, checksum_valid); | |
113 Reset(); | |
114 } else { | |
115 consumer_->OnUnexpectedByte(c); | |
116 } | |
117 break; | |
118 } | |
119 } | |
120 } | |
121 | |
122 void Packetizer::AddByteToChecksum(uint8_t c) { | |
123 calculated_checksum_ += c; | |
124 calculated_checksum_ %= 256; | |
125 } | |
126 | |
127 void Packetizer::AddByteToBody(uint8_t c) { | |
128 body_.PushBack(c); | |
129 } | |
130 | |
131 void Packetizer::AddRepeatedBytes(size_t n) { | |
132 size_t len = body_.size(); | |
133 if (0 != len) { | |
134 uint8_t c = body_[len - 1]; | |
135 for (size_t i = 0; i < n; i++) | |
136 AddByteToBody(c); | |
137 } | |
138 } | |
139 } // namespace rsp | |
140 | |
OLD | NEW |