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