1 /* Copyright (C) 1986-2024 Free Software Foundation, Inc.
2 
3    This file is part of GDB.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17 
18 #include "extract-store-integer.h"
19 #include "gdbtypes.h"
20 #include "gdbarch.h"
21 #include "gdbsupport/selftest.h"
22 
23 template<typename T, typename>
24 T
extract_integer(gdb::array_view<const gdb_byte> buf,enum bfd_endian byte_order)25 extract_integer (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order)
26 {
27   typename std::make_unsigned<T>::type retval = 0;
28 
29   if (buf.size () > (int) sizeof (T))
30     error (_("\
31 That operation is not available on integers of more than %d bytes."),
32              (int) sizeof (T));
33 
34   /* Start at the most significant end of the integer, and work towards
35      the least significant.  */
36   if (byte_order == BFD_ENDIAN_BIG)
37     {
38       size_t i = 0;
39 
40       if (std::is_signed<T>::value)
41           {
42             /* Do the sign extension once at the start.  */
43             retval = ((LONGEST) buf[i] ^ 0x80) - 0x80;
44             ++i;
45           }
46       for (; i < buf.size (); ++i)
47           retval = (retval << 8) | buf[i];
48     }
49   else
50     {
51       ssize_t i = buf.size () - 1;
52 
53       if (std::is_signed<T>::value)
54           {
55             /* Do the sign extension once at the start.  */
56             retval = ((LONGEST) buf[i] ^ 0x80) - 0x80;
57             --i;
58           }
59       for (; i >= 0; --i)
60           retval = (retval << 8) | buf[i];
61     }
62   return retval;
63 }
64 
65 /* Explicit instantiations.  */
66 template LONGEST extract_integer<LONGEST> (gdb::array_view<const gdb_byte> buf,
67                                                      enum bfd_endian byte_order);
68 template ULONGEST extract_integer<ULONGEST>
69   (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order);
70 
71 /* Sometimes a long long unsigned integer can be extracted as a
72    LONGEST value.  This is done so that we can print these values
73    better.  If this integer can be converted to a LONGEST, this
74    function returns 1 and sets *PVAL.  Otherwise it returns 0.  */
75 
76 int
extract_long_unsigned_integer(const gdb_byte * addr,int orig_len,enum bfd_endian byte_order,LONGEST * pval)77 extract_long_unsigned_integer (const gdb_byte *addr, int orig_len,
78                                      enum bfd_endian byte_order, LONGEST *pval)
79 {
80   const gdb_byte *p;
81   const gdb_byte *first_addr;
82   int len;
83 
84   len = orig_len;
85   if (byte_order == BFD_ENDIAN_BIG)
86     {
87       for (p = addr;
88              len > (int) sizeof (LONGEST) && p < addr + orig_len;
89              p++)
90           {
91             if (*p == 0)
92               len--;
93             else
94               break;
95           }
96       first_addr = p;
97     }
98   else
99     {
100       first_addr = addr;
101       for (p = addr + orig_len - 1;
102              len > (int) sizeof (LONGEST) && p >= addr;
103              p--)
104           {
105             if (*p == 0)
106               len--;
107             else
108               break;
109           }
110     }
111 
112   if (len <= (int) sizeof (LONGEST))
113     {
114       *pval = (LONGEST) extract_unsigned_integer (first_addr,
115                                                               sizeof (LONGEST),
116                                                               byte_order);
117       return 1;
118     }
119 
120   return 0;
121 }
122 
123 
124 /* Treat the bytes at BUF as a pointer of type TYPE, and return the
125    address it represents.  */
126 CORE_ADDR
extract_typed_address(const gdb_byte * buf,struct type * type)127 extract_typed_address (const gdb_byte *buf, struct type *type)
128 {
129   gdb_assert (type->is_pointer_or_reference ());
130   return gdbarch_pointer_to_address (type->arch (), type, buf);
131 }
132 
133 /* All 'store' functions accept a host-format integer and store a
134    target-format integer at ADDR which is LEN bytes long.  */
135 template<typename T, typename>
136 void
store_integer(gdb::array_view<gdb_byte> dst,enum bfd_endian byte_order,T val)137 store_integer (gdb::array_view<gdb_byte> dst, enum bfd_endian byte_order,
138                  T val)
139 {
140   gdb_byte *p;
141   gdb_byte *startaddr = dst.data ();
142   gdb_byte *endaddr = startaddr + dst.size ();
143 
144   /* Start at the least significant end of the integer, and work towards
145      the most significant.  */
146   if (byte_order == BFD_ENDIAN_BIG)
147     {
148       for (p = endaddr - 1; p >= startaddr; --p)
149           {
150             *p = val & 0xff;
151             val >>= 8;
152           }
153     }
154   else
155     {
156       for (p = startaddr; p < endaddr; ++p)
157           {
158             *p = val & 0xff;
159             val >>= 8;
160           }
161     }
162 }
163 
164 /* Explicit instantiations.  */
165 template void store_integer (gdb::array_view<gdb_byte> dst,
166                                    bfd_endian byte_order, LONGEST val);
167 
168 template void store_integer (gdb::array_view<gdb_byte> dst,
169                                    bfd_endian byte_order, ULONGEST val);
170 
171 /* Store the address ADDR as a pointer of type TYPE at BUF, in target
172    form.  */
173 void
store_typed_address(gdb_byte * buf,struct type * type,CORE_ADDR addr)174 store_typed_address (gdb_byte *buf, struct type *type, CORE_ADDR addr)
175 {
176   gdb_assert (type->is_pointer_or_reference ());
177   gdbarch_address_to_pointer (type->arch (), type, buf, addr);
178 }
179 
180 /* Copy a value from SOURCE of size SOURCE_SIZE bytes to DEST of size DEST_SIZE
181    bytes.  If SOURCE_SIZE is greater than DEST_SIZE, then truncate the most
182    significant bytes.  If SOURCE_SIZE is less than DEST_SIZE then either sign
183    or zero extended according to IS_SIGNED.  Values are stored in memory with
184    endianness BYTE_ORDER.  */
185 
186 void
copy_integer_to_size(gdb_byte * dest,int dest_size,const gdb_byte * source,int source_size,bool is_signed,enum bfd_endian byte_order)187 copy_integer_to_size (gdb_byte *dest, int dest_size, const gdb_byte *source,
188                           int source_size, bool is_signed,
189                           enum bfd_endian byte_order)
190 {
191   signed int size_diff = dest_size - source_size;
192 
193   /* Copy across everything from SOURCE that can fit into DEST.  */
194 
195   if (byte_order == BFD_ENDIAN_BIG && size_diff > 0)
196     memcpy (dest + size_diff, source, source_size);
197   else if (byte_order == BFD_ENDIAN_BIG && size_diff < 0)
198     memcpy (dest, source - size_diff, dest_size);
199   else
200     memcpy (dest, source, std::min (source_size, dest_size));
201 
202   /* Fill the remaining space in DEST by either zero extending or sign
203      extending.  */
204 
205   if (size_diff > 0)
206     {
207       gdb_byte extension = 0;
208       if (is_signed
209             && ((byte_order != BFD_ENDIAN_BIG && source[source_size - 1] & 0x80)
210                 || (byte_order == BFD_ENDIAN_BIG && source[0] & 0x80)))
211           extension = 0xff;
212 
213       /* Extend into MSBs of SOURCE.  */
214       if (byte_order == BFD_ENDIAN_BIG)
215           memset (dest, extension, size_diff);
216       else
217           memset (dest + source_size, extension, size_diff);
218     }
219 }
220 
221 #if GDB_SELF_TEST
222 namespace selftests {
223 
224 /* Function to test copy_integer_to_size.  Store SOURCE_VAL with size
225    SOURCE_SIZE to a buffer, making sure no sign extending happens at this
226    stage.  Copy buffer to a new buffer using copy_integer_to_size.  Extract
227    copied value and compare to DEST_VALU.  Copy again with a signed
228    copy_integer_to_size and compare to DEST_VALS.  Do everything for both
229    LITTLE and BIG target endians.  Use unsigned values throughout to make
230    sure there are no implicit sign extensions.  */
231 
232 static void
do_cint_test(ULONGEST dest_valu,ULONGEST dest_vals,int dest_size,ULONGEST src_val,int src_size)233 do_cint_test (ULONGEST dest_valu, ULONGEST dest_vals, int dest_size,
234                 ULONGEST src_val, int src_size)
235 {
236   for (int i = 0; i < 2 ; i++)
237     {
238       gdb_byte srcbuf[sizeof (ULONGEST)] = {};
239       gdb_byte destbuf[sizeof (ULONGEST)] = {};
240       enum bfd_endian byte_order = i ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
241 
242       /* Fill the src buffer (and later the dest buffer) with non-zero junk,
243            to ensure zero extensions aren't hidden.  */
244       memset (srcbuf, 0xaa, sizeof (srcbuf));
245 
246       /* Store (and later extract) using unsigned to ensure there are no sign
247            extensions.  */
248       store_unsigned_integer (srcbuf, src_size, byte_order, src_val);
249 
250       /* Test unsigned.  */
251       memset (destbuf, 0xaa, sizeof (destbuf));
252       copy_integer_to_size (destbuf, dest_size, srcbuf, src_size, false,
253                                   byte_order);
254       SELF_CHECK (dest_valu == extract_unsigned_integer (destbuf, dest_size,
255                                                                        byte_order));
256 
257       /* Test signed.  */
258       memset (destbuf, 0xaa, sizeof (destbuf));
259       copy_integer_to_size (destbuf, dest_size, srcbuf, src_size, true,
260                                   byte_order);
261       SELF_CHECK (dest_vals == extract_unsigned_integer (destbuf, dest_size,
262                                                                        byte_order));
263     }
264 }
265 
266 static void
copy_integer_to_size_test()267 copy_integer_to_size_test ()
268 {
269   /* Destination is bigger than the source, which has the signed bit unset.  */
270   do_cint_test (0x12345678, 0x12345678, 8, 0x12345678, 4);
271   do_cint_test (0x345678, 0x345678, 8, 0x12345678, 3);
272 
273   /* Destination is bigger than the source, which has the signed bit set.  */
274   do_cint_test (0xdeadbeef, 0xffffffffdeadbeef, 8, 0xdeadbeef, 4);
275   do_cint_test (0xadbeef, 0xffffffffffadbeef, 8, 0xdeadbeef, 3);
276 
277   /* Destination is smaller than the source.  */
278   do_cint_test (0x5678, 0x5678, 2, 0x12345678, 3);
279   do_cint_test (0xbeef, 0xbeef, 2, 0xdeadbeef, 3);
280 
281   /* Destination and source are the same size.  */
282   do_cint_test (0x8765432112345678, 0x8765432112345678, 8, 0x8765432112345678,
283                     8);
284   do_cint_test (0x432112345678, 0x432112345678, 6, 0x8765432112345678, 6);
285   do_cint_test (0xfeedbeaddeadbeef, 0xfeedbeaddeadbeef, 8, 0xfeedbeaddeadbeef,
286                     8);
287   do_cint_test (0xbeaddeadbeef, 0xbeaddeadbeef, 6, 0xfeedbeaddeadbeef, 6);
288 
289   /* Destination is bigger than the source.  Source is bigger than 32bits.  */
290   do_cint_test (0x3412345678, 0x3412345678, 8, 0x3412345678, 6);
291   do_cint_test (0xff12345678, 0xff12345678, 8, 0xff12345678, 6);
292   do_cint_test (0x432112345678, 0x432112345678, 8, 0x8765432112345678, 6);
293   do_cint_test (0xff2112345678, 0xffffff2112345678, 8, 0xffffff2112345678, 6);
294 }
295 
296 } // namespace selftests
297 
298 #endif
299 
300 void _initialize_extract_store_integer ();
301 void
_initialize_extract_store_integer()302 _initialize_extract_store_integer ()
303 {
304 #if GDB_SELF_TEST
305   selftests::register_test ("copy_integer_to_size",
306                                   selftests::copy_integer_to_size_test);
307 #endif
308 }
309