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
Packet()28 Packet::Packet() {
29 seq_ = -1;
30 Clear();
31 }
32
Clear()33 void Packet::Clear() {
34 data_.clear();
35 data_.resize(GROW_SIZE);
36 data_[0] = 0;
37
38 read_index_ = 0;
39 write_index_ = 0;
40 }
41
Rewind()42 void Packet::Rewind() {
43 read_index_ = 0;
44 }
45
EndOfPacket() const46 bool Packet::EndOfPacket() const {
47 return (read_index_ >= write_index_);
48 }
49
AddRawChar(char ch)50 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 if (data_.size() <= (write_index_ + MIN_PAD)) {
54 data_.resize(data_.size() + GROW_SIZE);
55 }
56
57 // Add character and always null terminate.
58 data_[write_index_++] = ch;
59 data_[write_index_] = 0;
60 }
61
AddWord8(uint8_t ch)62 void Packet::AddWord8(uint8_t ch) {
63 char seq1, seq2;
64
65 IntToNibble(ch >> 4, &seq1);
66 IntToNibble(ch & 0xF, &seq2);
67
68 AddRawChar(seq1);
69 AddRawChar(seq2);
70 }
71
AddBlock(const void * ptr,uint32_t len)72 void Packet::AddBlock(const void *ptr, uint32_t len) {
73 assert(ptr);
74
75 const char *p = (const char *) ptr;
76
77 for (uint32_t offs = 0; offs < len; offs++) {
78 AddWord8(p[offs]);
79 }
80 }
81
AddWord16(uint16_t val)82 void Packet::AddWord16(uint16_t val) {
83 AddBlock(&val, sizeof(val));
84 }
85
AddWord32(uint32_t val)86 void Packet::AddWord32(uint32_t val) {
87 AddBlock(&val, sizeof(val));
88 }
89
AddWord64(uint64_t val)90 void Packet::AddWord64(uint64_t val) {
91 AddBlock(&val, sizeof(val));
92 }
93
AddString(const char * str)94 void Packet::AddString(const char *str) {
95 assert(str);
96
97 while (*str) {
98 AddRawChar(*str);
99 str++;
100 }
101 }
102
AddEscapedData(const char * data,size_t length)103 void Packet::AddEscapedData(const char *data, size_t length) {
104 while (length > 0) {
105 char ch = *data;
106 // Escape certain characters by sending 0x7d ('}') followed by the original
107 // character xor-ed with 0x20.
108 if (ch == '}' || ch == '#' || ch == '$' || ch == '*') {
109 AddRawChar('}');
110 AddRawChar(ch ^ 0x20);
111 } else {
112 AddRawChar(ch);
113 }
114 ++data;
115 --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 size_t count = 0;
120 while (count < 97 && length > count && data[count] == ch) {
121 count++;
122 }
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 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 if (count == 6 || count == 7) {
132 count = 5;
133 }
134 AddRawChar('*');
135 AddRawChar(static_cast<char>(count + 29));
136 data += count;
137 length -= count;
138 }
139 }
140 }
141
AddHexString(const char * str)142 void Packet::AddHexString(const char *str) {
143 assert(str);
144
145 while (*str) {
146 AddWord8(*str);
147 str++;
148 }
149 }
150
AddNumberSep(uint64_t val,char sep)151 void Packet::AddNumberSep(uint64_t val, char sep) {
152 char out[sizeof(val) * 2];
153 int nibbles = 0;
154 size_t a;
155
156 // Check for -1 optimization
157 if (val == static_cast<uint64_t>(-1)) {
158 AddRawChar('-');
159 AddRawChar('1');
160 } else {
161 // Assume we have the valuse 0x00001234
162 for (a = 0; a < sizeof(val); a++) {
163 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 IntToNibble(byte & 0xF, &out[nibbles++]);
168 IntToNibble(byte >> 4, &out[nibbles++]);
169
170 // Get the next 8 bits;
171 val >>= 8;
172
173 // Supress leading zeros, so we are done when val hits zero
174 if (val == 0) {
175 break;
176 }
177 }
178
179 // Strip the high zero for this byte if needed
180 if ((nibbles > 1) && (out[nibbles-1] == '0')) nibbles--;
181
182 // Now write it out reverse to correct the order
183 while (nibbles) {
184 nibbles--;
185 AddRawChar(out[nibbles]);
186 }
187 }
188
189 // If we asked for a sperator, insert it
190 if (sep) AddRawChar(sep);
191 }
192
GetNumberSep(uint64_t * val,char * sep)193 bool Packet::GetNumberSep(uint64_t *val, char *sep) {
194 uint64_t out = 0;
195 char ch;
196
197 if (!GetRawChar(&ch)) {
198 return false;
199 }
200
201 // Check for -1
202 if (ch == '-') {
203 if (!GetRawChar(&ch)) {
204 return false;
205 }
206
207 if (ch == '1') {
208 *val = (uint64_t) -1;
209
210 ch = 0;
211 GetRawChar(&ch);
212 if (sep) {
213 *sep = ch;
214 }
215 return true;
216 }
217 return false;
218 }
219
220 do {
221 int nib;
222
223 // Check for separator
224 if (!NibbleToInt(ch, &nib)) {
225 break;
226 }
227
228 // Add this nibble.
229 out = (out << 4) + nib;
230
231 // Get the next character (if availible)
232 ch = 0;
233 if (!GetRawChar(&ch)) {
234 break;
235 }
236 } while (1);
237
238 // Set the value;
239 *val = out;
240
241 // Add the separator if the user wants it...
242 if (sep != NULL) *sep = ch;
243
244 return true;
245 }
246
GetRawChar(char * ch)247 bool Packet::GetRawChar(char *ch) {
248 assert(ch != NULL);
249
250 if (read_index_ >= write_index_)
251 return false;
252
253 *ch = data_[read_index_++];
254
255 // Check for RLE X*N, where X is the value, N is the reps.
256 if (*ch == '*') {
257 if (read_index_ < 2) {
258 NaClLog(LOG_ERROR, "Unexpected RLE at start of packet.\n");
259 return false;
260 }
261
262 if (read_index_ >= write_index_) {
263 NaClLog(LOG_ERROR, "Unexpected EoP during RLE.\n");
264 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 int32_t cnt = (data_[read_index_] - 28);
272 if (cnt < 3) {
273 NaClLog(LOG_ERROR, "Unexpected RLE length.\n");
274 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 data_.resize(write_index_ + cnt - 3 + 1);
295 memmove(&data_[read_index_ + cnt - 3], &data_[read_index_],
296 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 *ch = data_[read_index_ - 2];
302 memset(&data_[read_index_ - 1], *ch, cnt - 1);
303
304 // Now we update the write_index_, and reterminate the string.
305 write_index_ = data_.size() - 1;
306 data_[write_index_] = 0;
307 }
308 return true;
309 }
310
GetWord8(uint8_t * ch)311 bool Packet::GetWord8(uint8_t *ch) {
312 assert(ch);
313
314 char seq1, seq2;
315 int val1, val2;
316
317 // Get two ASCII hex values
318 if (!GetRawChar(&seq1)) {
319 return false;
320 }
321 if (!GetRawChar(&seq2)) {
322 return false;
323 }
324
325 // Convert them to ints
326 if (!NibbleToInt(seq1, &val1)) {
327 return false;
328 }
329 if (!NibbleToInt(seq2, &val2)) {
330 return false;
331 }
332
333 *ch = (val1 << 4) + val2;
334 return true;
335 }
336
GetBlock(void * ptr,uint32_t len)337 bool Packet::GetBlock(void *ptr, uint32_t len) {
338 assert(ptr);
339
340 uint8_t *p = reinterpret_cast<uint8_t *>(ptr);
341 bool res = true;
342
343 for (uint32_t offs = 0; offs < len; offs++) {
344 res = GetWord8(&p[offs]);
345 if (false == res) {
346 break;
347 }
348 }
349
350 return res;
351 }
352
GetWord16(uint16_t * ptr)353 bool Packet::GetWord16(uint16_t *ptr) {
354 assert(ptr);
355 return GetBlock(ptr, sizeof(*ptr));
356 }
357
GetWord32(uint32_t * ptr)358 bool Packet::GetWord32(uint32_t *ptr) {
359 assert(ptr);
360 return GetBlock(ptr, sizeof(*ptr));
361 }
362
GetWord64(uint64_t * ptr)363 bool Packet::GetWord64(uint64_t *ptr) {
364 assert(ptr);
365 return GetBlock(ptr, sizeof(*ptr));
366 }
367
368
GetString(string * str)369 bool Packet::GetString(string *str) {
370 if (EndOfPacket()) {
371 return false;
372 }
373
374 *str = &data_[read_index_];
375 read_index_ = write_index_;
376 return true;
377 }
378
GetHexString(string * str)379 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 if (EndOfPacket()) {
388 return false;
389 }
390
391 // Pull values until we hit a separator
392 str->clear();
393 while (GetRawChar(&ch1)) {
394 if (!NibbleToInt(ch1, &nib1)) {
395 read_index_--;
396 break;
397 }
398 if (!GetRawChar(&ch2) ||
399 !NibbleToInt(ch2, &nib2)) {
400 return false;
401 }
402 *str += static_cast<char>((nib1 << 4) + nib2);
403 }
404 return true;
405 }
406
GetStringSep(std::string * str,char sep)407 bool Packet::GetStringSep(std::string *str, char sep) {
408 char ch;
409
410 if (EndOfPacket()) {
411 return false;
412 }
413
414 // Pull values until we hit a separator
415 str->clear();
416 while (GetRawChar(&ch)) {
417 if (ch == sep) {
418 return true;
419 } else {
420 *str += ch;
421 }
422 }
423 return false;
424 }
425
GetPayload() const426 const char *Packet::GetPayload() const {
427 return &data_[0];
428 }
429
GetPayloadSize() const430 size_t Packet::GetPayloadSize() const {
431 return write_index_;
432 }
433
GetSequence(int32_t * ch) const434 bool Packet::GetSequence(int32_t *ch) const {
435 assert(ch);
436
437 if (seq_ != -1) {
438 *ch = seq_;
439 return true;
440 }
441
442 return false;
443 }
444
ParseSequence()445 void Packet::ParseSequence() {
446 size_t saved_read_index = read_index_;
447 unsigned char seq;
448 char ch;
449 if (GetWord8(&seq) &&
450 GetRawChar(&ch)) {
451 if (ch == ':') {
452 SetSequence(seq);
453 return;
454 }
455 }
456 // No sequence number present, so reset to original position.
457 read_index_ = saved_read_index;
458 }
459
SetSequence(int32_t val)460 void Packet::SetSequence(int32_t val) {
461 seq_ = val;
462 }
463
464 } // namespace gdb_rsp
465