1 : /*
2 : * Copyright 2010 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can
4 : * be found in the LICENSE file.
5 : */
6 :
7 :
8 : #include <assert.h>
9 : #include <string.h>
10 : #include <stdlib.h>
11 :
12 : #include <string>
13 :
14 : #include "native_client/src/trusted/gdb_rsp/packet.h"
15 : #include "native_client/src/trusted/gdb_rsp/util.h"
16 : #include "native_client/src/trusted/port/platform.h"
17 :
18 : using std::string;
19 : using port::IPlatform;
20 :
21 :
22 : namespace gdb_rsp {
23 :
24 : #define MIN_PAD 1
25 : #define GROW_SIZE 64
26 :
27 32 : Packet::Packet() {
28 32 : seq_ = -1;
29 32 : Clear();
30 32 : }
31 :
32 72 : void Packet::Clear() {
33 72 : data_.clear();
34 72 : data_.resize(GROW_SIZE);
35 72 : data_[0] = 0;
36 :
37 72 : read_index_ = 0;
38 72 : write_index_ = 0;
39 72 : }
40 :
41 1 : void Packet::Rewind() {
42 1 : read_index_ = 0;
43 1 : }
44 :
45 15 : bool Packet::EndOfPacket() const {
46 15 : return (read_index_ >= write_index_);
47 : }
48 :
49 1071 : void Packet::AddRawChar(char ch) {
50 : // Grow by a fixed amount whenever we are within the pad boundry.
51 : // The pad boundry allows for the addition of NUL termination.
52 1071 : if (data_.size() <= (write_index_ + MIN_PAD)) {
53 8 : data_.resize(data_.size() + GROW_SIZE);
54 : }
55 :
56 : // Add character and always null terminate.
57 1071 : data_[write_index_++] = ch;
58 1071 : data_[write_index_] = 0;
59 1071 : }
60 :
61 72 : void Packet::AddWord8(uint8_t ch) {
62 : char seq1, seq2;
63 :
64 72 : IntToNibble(ch >> 4, &seq1);
65 72 : IntToNibble(ch & 0xF, &seq2);
66 :
67 72 : AddRawChar(seq1);
68 72 : AddRawChar(seq2);
69 72 : }
70 :
71 3 : void Packet::AddBlock(const void *ptr, uint32_t len) {
72 3 : assert(ptr);
73 :
74 3 : const char *p = (const char *) ptr;
75 :
76 73 : for (uint32_t offs = 0; offs < len; offs++) {
77 70 : AddWord8(p[offs]);
78 : }
79 3 : }
80 :
81 1 : void Packet::AddWord16(uint16_t val) {
82 1 : AddBlock(&val, sizeof(val));
83 1 : }
84 :
85 1 : void Packet::AddWord32(uint32_t val) {
86 1 : AddBlock(&val, sizeof(val));
87 1 : }
88 :
89 0 : void Packet::AddWord64(uint64_t val) {
90 0 : AddBlock(&val, sizeof(val));
91 0 : }
92 :
93 39 : void Packet::AddString(const char *str) {
94 39 : assert(str);
95 :
96 914 : while (*str) {
97 836 : AddRawChar(*str);
98 836 : str++;
99 : }
100 39 : }
101 :
102 0 : void Packet::AddHexString(const char *str) {
103 0 : assert(str);
104 :
105 0 : while (*str) {
106 0 : AddWord8(*str);
107 0 : str++;
108 : }
109 0 : }
110 :
111 6 : void Packet::AddNumberSep(uint64_t val, char sep) {
112 : char out[sizeof(val) * 2];
113 6 : int nibbles = 0;
114 : size_t a;
115 :
116 : // Check for -1 optimization
117 6 : if (val == static_cast<uint64_t>(-1)) {
118 1 : AddRawChar('-');
119 1 : AddRawChar('1');
120 : } else {
121 : // Assume we have the valuse 0x00001234
122 14 : for (a = 0; a < sizeof(val); a++) {
123 14 : uint8_t byte = static_cast<uint8_t>(val & 0xFF);
124 :
125 : // Stream in with bytes reverse, starting at least significant
126 : // So we store 4, then 3, 2, 1
127 14 : IntToNibble(byte & 0xF, &out[nibbles++]);
128 14 : IntToNibble(byte >> 4, &out[nibbles++]);
129 :
130 : // Get the next 8 bits;
131 14 : val >>= 8;
132 :
133 : // Supress leading zeros, so we are done when val hits zero
134 14 : if (val == 0) break;
135 : }
136 :
137 : // Strip the high zero for this byte if needed
138 5 : if ((nibbles > 1) && (out[nibbles-1] == '0')) nibbles--;
139 :
140 : // Now write it out reverse to correct the order
141 35 : while (nibbles) {
142 25 : nibbles--;
143 25 : AddRawChar(out[nibbles]);
144 : }
145 : }
146 :
147 : // If we asked for a sperator, insert it
148 6 : if (sep) AddRawChar(sep);
149 6 : }
150 :
151 1 : bool Packet::GetNumberSep(uint64_t *val, char *sep) {
152 1 : uint64_t out = 0;
153 : char ch;
154 :
155 1 : if (!GetRawChar(&ch)) return false;
156 :
157 : // Check for -1
158 1 : if (ch == '-') {
159 0 : if (!GetRawChar(&ch)) return false;
160 :
161 0 : if (ch == '1') {
162 0 : *val = -1;
163 :
164 0 : ch = 0;
165 0 : GetRawChar(&ch);
166 0 : if (sep) *sep = ch;
167 0 : return true;
168 : }
169 0 : return false;
170 : }
171 :
172 3 : do {
173 : int nib;
174 :
175 : // Check for separator
176 4 : if (!NibbleToInt(ch, &nib)) break;
177 :
178 : // Add this nibble.
179 4 : out = (out << 4) + nib;
180 :
181 : // Get the next character (if availible)
182 4 : ch = 0;
183 4 : if (!GetRawChar(&ch)) break;
184 : } while (1);
185 :
186 : // Set the value;
187 1 : *val = out;
188 :
189 : // Add the separator if the user wants it...
190 1 : if (sep != NULL) *sep = ch;
191 :
192 1 : return true;
193 : }
194 :
195 413 : bool Packet::GetRawChar(char *ch) {
196 413 : assert(ch != NULL);
197 :
198 413 : if (read_index_ >= write_index_)
199 2 : return false;
200 :
201 411 : *ch = data_[read_index_++];
202 :
203 : // Check for RLE X*N, where X is the value, N is the reps.
204 411 : if (*ch == '*') {
205 9 : if (read_index_ < 2) {
206 0 : IPlatform::LogError("Unexpected RLE at start of packet.\n");
207 0 : return false;
208 : }
209 :
210 9 : if (read_index_ >= write_index_) {
211 0 : IPlatform::LogError("Unexpected EoP during RLE.\n");
212 0 : return false;
213 : }
214 :
215 : // GDB does not use "CTRL" characters in the stream, so the
216 : // number of reps is encoded as the ASCII value beyond 28
217 : // (which when you add a min rep size of 4, forces the rep
218 : // character to be ' ' (32) or greater).
219 9 : int32_t cnt = (data_[read_index_] - 28);
220 9 : if (cnt < 3) {
221 0 : IPlatform::LogError("Unexpected RLE length.\n");
222 0 : return false;
223 : }
224 :
225 : // We have just read '*' and incremented the read pointer,
226 : // so here is the old state, and expected new state.
227 : //
228 : // Assume N = 5, we grow by N - size of encoding (3).
229 : //
230 : // OldP: R W
231 : // OldD: 012X*N89 = 8 chars
232 : // Size: 012X*N89__ = 10 chars
233 : // Move: 012X*__N89 = 10 chars
234 : // Fill: 012XXXXX89 = 10 chars
235 : // NewP: R W (shifted 5 - 3)
236 : //
237 : // To accomplish this we must first, resize the vector then move
238 : // all remaining characters to the right, by the delta between
239 : // the run length, and encoding size. This moves one more char
240 : // than needed (the 'N'), but is easier to understand.
241 : // NOTE: We add one to the resize to allow for zero termination.
242 9 : data_.resize(write_index_ + cnt - 3 + 1);
243 : memmove(&data_[read_index_ + cnt - 3], &data_[read_index_],
244 9 : write_index_ - read_index_);
245 :
246 : // Now me must go back and fill over the previous '*' with the
247 : // repeated character for the length of the run minus the original
248 : // character which is already correct
249 9 : *ch = data_[read_index_ - 2];
250 9 : memset(&data_[read_index_ - 1], *ch, cnt - 1);
251 :
252 : // Now we update the write_index_, and reterminate the string.
253 9 : write_index_ = data_.size() - 1;
254 9 : data_[write_index_] = 0;
255 : }
256 411 : return true;
257 : }
258 :
259 199 : bool Packet::GetWord8(uint8_t *ch) {
260 199 : assert(ch);
261 :
262 : char seq1, seq2;
263 : int val1, val2;
264 :
265 : // Get two ASCII hex values
266 199 : if (!GetRawChar(&seq1)) return false;
267 199 : if (!GetRawChar(&seq2)) return false;
268 :
269 : // Convert them to ints
270 199 : if (!NibbleToInt(seq1, &val1)) return false;
271 199 : if (!NibbleToInt(seq2, &val2)) return false;
272 :
273 199 : *ch = (val1 << 4) + val2;
274 199 : return true;
275 : }
276 :
277 5 : bool Packet::GetBlock(void *ptr, uint32_t len) {
278 5 : assert(ptr);
279 :
280 5 : uint8_t *p = reinterpret_cast<uint8_t *>(ptr);
281 5 : bool res = true;
282 :
283 203 : for (uint32_t offs = 0; offs < len; offs++) {
284 198 : res = GetWord8(&p[offs]);
285 198 : if (false == res) break;
286 : }
287 :
288 5 : return res;
289 : }
290 :
291 1 : bool Packet::GetWord16(uint16_t *ptr) {
292 1 : assert(ptr);
293 1 : return GetBlock(ptr, sizeof(*ptr));
294 : }
295 :
296 1 : bool Packet::GetWord32(uint32_t *ptr) {
297 1 : assert(ptr);
298 1 : return GetBlock(ptr, sizeof(*ptr));
299 : }
300 :
301 0 : bool Packet::GetWord64(uint64_t *ptr) {
302 0 : assert(ptr);
303 0 : return GetBlock(ptr, sizeof(*ptr));
304 : }
305 :
306 :
307 15 : bool Packet::GetString(string* str) {
308 15 : if (EndOfPacket()) return false;
309 :
310 15 : *str = &data_[read_index_];
311 15 : read_index_ = write_index_;
312 15 : return true;
313 : }
314 :
315 0 : bool Packet::GetHexString(string* str) {
316 : char ch;
317 0 : if (EndOfPacket()) return false;
318 :
319 : // Pull values until we hit a seperator
320 0 : str->clear();
321 0 : while (GetRawChar(&ch)) {
322 0 : if (NibbleToInt(ch, NULL)) {
323 0 : *str += ch;
324 : } else {
325 0 : read_index_--;
326 0 : break;
327 : }
328 : }
329 0 : return true;
330 : }
331 :
332 0 : bool Packet::GetStringCB(void *ctx, StrFunc_t cb) {
333 0 : assert(NULL != ctx);
334 :
335 0 : if (EndOfPacket()) {
336 0 : cb(ctx, NULL);
337 0 : return false;
338 : }
339 :
340 0 : cb(ctx, &data_[read_index_]);
341 0 : read_index_ = write_index_;
342 0 : return true;
343 : }
344 :
345 0 : bool Packet::GetHexStringCB(void *ctx, StrFunc_t cb) {
346 0 : assert(NULL != ctx);
347 :
348 0 : std::string out;
349 : char ch;
350 :
351 0 : if (EndOfPacket()) {
352 0 : cb(ctx, NULL);
353 0 : return false;
354 : }
355 :
356 : // Pull values until we hit a seperator
357 0 : while (GetRawChar(&ch)) {
358 0 : if (NibbleToInt(ch, NULL)) {
359 0 : out += ch;
360 : } else {
361 0 : read_index_--;
362 0 : break;
363 : }
364 : }
365 :
366 : // Call the CB with the availible string
367 0 : cb(ctx, out.data());
368 0 : return true;
369 : }
370 :
371 :
372 26 : const char *Packet::GetPayload() const {
373 26 : return &data_[0];
374 : }
375 :
376 13 : bool Packet::GetSequence(int32_t *ch) const {
377 13 : assert(ch);
378 :
379 13 : if (seq_ != -1) {
380 0 : *ch = seq_;
381 0 : return true;
382 : }
383 :
384 13 : return false;
385 : }
386 :
387 0 : void Packet::SetSequence(int32_t val) {
388 0 : seq_ = val;
389 0 : }
390 :
391 : } // namespace gdb_rsp
392 :
|