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