| /* Low-level RSP routines for GDB, the GNU debugger. | 
 |  | 
 |    Copyright (C) 1988-2022 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 | 
 | 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.  */ | 
 |  | 
 | 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; | 
 | } | 
 |  |