xref: /netbsd-src/external/gpl3/gdb/dist/gdbsupport/rsp-low.cc (revision 5ba1f45f2a09259cc846f20c7c5501604d633c90)
1 /* Low-level RSP routines for GDB, the GNU debugger.
2 
3    Copyright (C) 1988-2024 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "rsp-low.h"
21 
22 /* See rsp-low.h.  */
23 
24 int
25 tohex (int nib)
26 {
27   if (nib < 10)
28     return '0' + nib;
29   else
30     return 'a' + nib - 10;
31 }
32 
33 /* Encode 64 bits in 16 chars of hex.  */
34 
35 static const char hexchars[] = "0123456789abcdef";
36 
37 static int
38 ishex (int ch, int *val)
39 {
40   if ((ch >= 'a') && (ch <= 'f'))
41     {
42       *val = ch - 'a' + 10;
43       return 1;
44     }
45   if ((ch >= 'A') && (ch <= 'F'))
46     {
47       *val = ch - 'A' + 10;
48       return 1;
49     }
50   if ((ch >= '0') && (ch <= '9'))
51     {
52       *val = ch - '0';
53       return 1;
54     }
55   return 0;
56 }
57 
58 /* See rsp-low.h.  */
59 
60 char *
61 pack_nibble (char *buf, int nibble)
62 {
63   *buf++ = hexchars[(nibble & 0x0f)];
64   return buf;
65 }
66 
67 /* See rsp-low.h.  */
68 
69 char *
70 pack_hex_byte (char *pkt, int byte)
71 {
72   *pkt++ = hexchars[(byte >> 4) & 0xf];
73   *pkt++ = hexchars[(byte & 0xf)];
74   return pkt;
75 }
76 
77 /* See rsp-low.h.  */
78 
79 const char *
80 unpack_varlen_hex (const char *buff,	/* packet to parse */
81 		   ULONGEST *result)
82 {
83   int nibble;
84   ULONGEST retval = 0;
85 
86   while (ishex (*buff, &nibble))
87     {
88       buff++;
89       retval = retval << 4;
90       retval |= nibble & 0x0f;
91     }
92   *result = retval;
93   return buff;
94 }
95 
96 /* See rsp-low.h.  */
97 
98 std::string
99 hex2str (const char *hex)
100 {
101   return hex2str (hex, strlen (hex));
102 }
103 
104 /* See rsp-low.h.  */
105 
106 std::string
107 hex2str (const char *hex, int count)
108 {
109   std::string ret;
110 
111   ret.reserve (count);
112   for (size_t i = 0; i < count; ++i)
113     {
114       if (hex[0] == '\0' || hex[1] == '\0')
115 	{
116 	  /* Hex string is short, or of uneven length.  Return what we
117 	     have so far.  */
118 	  return ret;
119 	}
120       ret += fromhex (hex[0]) * 16 + fromhex (hex[1]);
121       hex += 2;
122     }
123 
124   return ret;
125 }
126 
127 /* See rsp-low.h.  */
128 
129 int
130 bin2hex (const gdb_byte *bin, char *hex, int count)
131 {
132   int i;
133 
134   for (i = 0; i < count; i++)
135     {
136       *hex++ = tohex ((*bin >> 4) & 0xf);
137       *hex++ = tohex (*bin++ & 0xf);
138     }
139   *hex = 0;
140   return i;
141 }
142 
143 /* See rsp-low.h.  */
144 
145 int
146 bin2hex (gdb::array_view<gdb_byte> bin, char *hex)
147 {
148   return bin2hex (bin.data (), hex, bin.size ());
149 }
150 
151 /* See rsp-low.h.  */
152 
153 std::string
154 bin2hex (const gdb_byte *bin, int count)
155 {
156   std::string ret;
157 
158   ret.reserve (count * 2);
159   for (int i = 0; i < count; ++i)
160     {
161       ret += tohex ((*bin >> 4) & 0xf);
162       ret += tohex (*bin++ & 0xf);
163     }
164 
165   return ret;
166 }
167 
168 /* Return whether byte B needs escaping when sent as part of binary data.  */
169 
170 static int
171 needs_escaping (gdb_byte b)
172 {
173   return b == '$' || b == '#' || b == '}' || b == '*';
174 }
175 
176 /* See rsp-low.h.  */
177 
178 int
179 remote_escape_output (const gdb_byte *buffer, int len_units, int unit_size,
180 		      gdb_byte *out_buf, int *out_len_units,
181 		      int out_maxlen_bytes)
182 {
183   int input_unit_index, output_byte_index = 0, byte_index_in_unit;
184   int number_escape_bytes_needed;
185 
186   /* Try to copy integral addressable memory units until
187      (1) we run out of space or
188      (2) we copied all of them.  */
189   for (input_unit_index = 0;
190        input_unit_index < len_units;
191        input_unit_index++)
192     {
193       /* Find out how many escape bytes we need for this unit.  */
194       number_escape_bytes_needed = 0;
195       for (byte_index_in_unit = 0;
196 	   byte_index_in_unit < unit_size;
197 	   byte_index_in_unit++)
198 	{
199 	  int idx = input_unit_index * unit_size + byte_index_in_unit;
200 	  gdb_byte b = buffer[idx];
201 	  if (needs_escaping (b))
202 	    number_escape_bytes_needed++;
203 	}
204 
205       /* Check if we have room to fit this escaped unit.  */
206       if (output_byte_index + unit_size + number_escape_bytes_needed >
207 	    out_maxlen_bytes)
208 	  break;
209 
210       /* Copy the unit byte per byte, adding escapes.  */
211       for (byte_index_in_unit = 0;
212 	   byte_index_in_unit < unit_size;
213 	   byte_index_in_unit++)
214 	{
215 	  int idx = input_unit_index * unit_size + byte_index_in_unit;
216 	  gdb_byte b = buffer[idx];
217 	  if (needs_escaping (b))
218 	    {
219 	      out_buf[output_byte_index++] = '}';
220 	      out_buf[output_byte_index++] = b ^ 0x20;
221 	    }
222 	  else
223 	    out_buf[output_byte_index++] = b;
224 	}
225     }
226 
227   *out_len_units = input_unit_index;
228   return output_byte_index;
229 }
230 
231 /* See rsp-low.h.  */
232 
233 int
234 remote_unescape_input (const gdb_byte *buffer, int len,
235 		       gdb_byte *out_buf, int out_maxlen)
236 {
237   int input_index, output_index;
238   int escaped;
239 
240   output_index = 0;
241   escaped = 0;
242   for (input_index = 0; input_index < len; input_index++)
243     {
244       gdb_byte b = buffer[input_index];
245 
246       if (output_index + 1 > out_maxlen)
247 	error (_("Received too much data from the target."));
248 
249       if (escaped)
250 	{
251 	  out_buf[output_index++] = b ^ 0x20;
252 	  escaped = 0;
253 	}
254       else if (b == '}')
255 	escaped = 1;
256       else
257 	out_buf[output_index++] = b;
258     }
259 
260   if (escaped)
261     error (_("Unmatched escape character in target response."));
262 
263   return output_index;
264 }
265 
266