diff options
Diffstat (limited to 'gdbsupport/rsp-low.cc')
-rw-r--r-- | gdbsupport/rsp-low.cc | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/gdbsupport/rsp-low.cc b/gdbsupport/rsp-low.cc new file mode 100644 index 0000000..9bb1660 --- /dev/null +++ b/gdbsupport/rsp-low.cc @@ -0,0 +1,307 @@ +/* Low-level RSP routines for GDB, the GNU debugger. + + Copyright (C) 1988-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "common-defs.h" +#include "rsp-low.h" + +/* See rsp-low.h. */ + +int +fromhex (int a) +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else if (a >= 'A' && a <= 'F') + return a - 'A' + 10; + else + error (_("Reply contains invalid hex digit %d"), a); +} + +/* See rsp-low.h. */ + +int +tohex (int nib) +{ + if (nib < 10) + return '0' + nib; + else + return 'a' + nib - 10; +} + +/* Encode 64 bits in 16 chars of hex. */ + +static const char hexchars[] = "0123456789abcdef"; + +static int +ishex (int ch, int *val) +{ + if ((ch >= 'a') && (ch <= 'f')) + { + *val = ch - 'a' + 10; + return 1; + } + if ((ch >= 'A') && (ch <= 'F')) + { + *val = ch - 'A' + 10; + return 1; + } + if ((ch >= '0') && (ch <= '9')) + { + *val = ch - '0'; + return 1; + } + return 0; +} + +/* See rsp-low.h. */ + +char * +pack_nibble (char *buf, int nibble) +{ + *buf++ = hexchars[(nibble & 0x0f)]; + return buf; +} + +/* See rsp-low.h. */ + +char * +pack_hex_byte (char *pkt, int byte) +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +/* See rsp-low.h. */ + +const char * +unpack_varlen_hex (const char *buff, /* packet to parse */ + ULONGEST *result) +{ + int nibble; + ULONGEST retval = 0; + + while (ishex (*buff, &nibble)) + { + buff++; + retval = retval << 4; + retval |= nibble & 0x0f; + } + *result = retval; + return buff; +} + +/* See rsp-low.h. */ + +int +hex2bin (const char *hex, gdb_byte *bin, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + if (hex[0] == 0 || hex[1] == 0) + { + /* Hex string is short, or of uneven length. + Return the count that has been converted so far. */ + return i; + } + *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); + hex += 2; + } + return i; +} + +/* See rsp-low.h. */ + +gdb::byte_vector +hex2bin (const char *hex) +{ + size_t bin_len = strlen (hex) / 2; + gdb::byte_vector bin (bin_len); + + hex2bin (hex, bin.data (), bin_len); + + return bin; +} + +/* See rsp-low.h. */ + +std::string +hex2str (const char *hex) +{ + return hex2str (hex, strlen (hex)); +} + +/* See rsp-low.h. */ + +std::string +hex2str (const char *hex, int count) +{ + std::string ret; + + ret.reserve (count); + for (size_t i = 0; i < count; ++i) + { + if (hex[0] == '\0' || hex[1] == '\0') + { + /* Hex string is short, or of uneven length. Return what we + have so far. */ + return ret; + } + ret += fromhex (hex[0]) * 16 + fromhex (hex[1]); + hex += 2; + } + + return ret; +} + +/* See rsp-low.h. */ + +int +bin2hex (const gdb_byte *bin, char *hex, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + *hex++ = tohex ((*bin >> 4) & 0xf); + *hex++ = tohex (*bin++ & 0xf); + } + *hex = 0; + return i; +} + +/* See rsp-low.h. */ + +std::string +bin2hex (const gdb_byte *bin, int count) +{ + std::string ret; + + ret.reserve (count * 2); + for (int i = 0; i < count; ++i) + { + ret += tohex ((*bin >> 4) & 0xf); + ret += tohex (*bin++ & 0xf); + } + + return ret; +} + +/* Return whether byte B needs escaping when sent as part of binary data. */ + +static int +needs_escaping (gdb_byte b) +{ + return b == '$' || b == '#' || b == '}' || b == '*'; +} + +/* See rsp-low.h. */ + +int +remote_escape_output (const gdb_byte *buffer, int len_units, int unit_size, + gdb_byte *out_buf, int *out_len_units, + int out_maxlen_bytes) +{ + int input_unit_index, output_byte_index = 0, byte_index_in_unit; + int number_escape_bytes_needed; + + /* Try to copy integral addressable memory units until + (1) we run out of space or + (2) we copied all of them. */ + for (input_unit_index = 0; + input_unit_index < len_units; + input_unit_index++) + { + /* Find out how many escape bytes we need for this unit. */ + number_escape_bytes_needed = 0; + for (byte_index_in_unit = 0; + byte_index_in_unit < unit_size; + byte_index_in_unit++) + { + int idx = input_unit_index * unit_size + byte_index_in_unit; + gdb_byte b = buffer[idx]; + if (needs_escaping (b)) + number_escape_bytes_needed++; + } + + /* Check if we have room to fit this escaped unit. */ + if (output_byte_index + unit_size + number_escape_bytes_needed > + out_maxlen_bytes) + break; + + /* Copy the unit byte per byte, adding escapes. */ + for (byte_index_in_unit = 0; + byte_index_in_unit < unit_size; + byte_index_in_unit++) + { + int idx = input_unit_index * unit_size + byte_index_in_unit; + gdb_byte b = buffer[idx]; + if (needs_escaping (b)) + { + out_buf[output_byte_index++] = '}'; + out_buf[output_byte_index++] = b ^ 0x20; + } + else + out_buf[output_byte_index++] = b; + } + } + + *out_len_units = input_unit_index; + return output_byte_index; +} + +/* See rsp-low.h. */ + +int +remote_unescape_input (const gdb_byte *buffer, int len, + gdb_byte *out_buf, int out_maxlen) +{ + int input_index, output_index; + int escaped; + + output_index = 0; + escaped = 0; + for (input_index = 0; input_index < len; input_index++) + { + gdb_byte b = buffer[input_index]; + + if (output_index + 1 > out_maxlen) + error (_("Received too much data from the target.")); + + if (escaped) + { + out_buf[output_index++] = b ^ 0x20; + escaped = 0; + } + else if (b == '}') + escaped = 1; + else + out_buf[output_index++] = b; + } + + if (escaped) + error (_("Unmatched escape character in target response.")); + + return output_index; +} + |