Updated Bulgarian translation for the binutils/ directory
[binutils-gdb.git] / gdb / extract-store-integer.c
blob644273c96392c926b3f8f42f5a112bc0efb85368
1 /* Copyright (C) 1986-2024 Free Software Foundation, Inc.
3 This file is part of GDB.
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.
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.
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/>. */
18 #include "extract-store-integer.h"
19 #include "gdbtypes.h"
20 #include "gdbarch.h"
21 #include "gdbsupport/selftest.h"
23 template<typename T, typename>
25 extract_integer (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order)
27 typename std::make_unsigned<T>::type retval = 0;
29 /* It is ok if BUF is wider than T, but only if the value is
30 representable. */
31 bool bad_repr = false;
32 if (buf.size () > (int) sizeof (T))
34 const size_t end = buf.size () - sizeof (T);
35 if (byte_order == BFD_ENDIAN_BIG)
37 for (size_t i = 0; i < end; ++i)
39 /* High bytes == 0 are always ok, and high bytes == 0xff
40 are ok when the type is signed. */
41 if ((buf[i] == 0
42 || (std::is_signed<T>::value && buf[i] == 0xff))
43 /* All the high bytes must be the same, no
44 alternating 0 and 0xff. */
45 && (i == 0 || buf[i - 1] == buf[i]))
47 /* Ok. */
49 else
51 bad_repr = true;
52 break;
55 buf = buf.slice (end);
57 else
59 size_t bufsz = buf.size () - 1;
60 for (size_t i = bufsz; i >= end; --i)
62 /* High bytes == 0 are always ok, and high bytes == 0xff
63 are ok when the type is signed. */
64 if ((buf[i] == 0
65 || (std::is_signed<T>::value && buf[i] == 0xff))
66 /* All the high bytes must be the same, no
67 alternating 0 and 0xff. */
68 && (i == bufsz || buf[i] == buf[i + 1]))
70 /* Ok. */
72 else
74 bad_repr = true;
75 break;
78 buf = buf.slice (0, end);
82 if (bad_repr)
83 error (_("Value cannot be represented as integer of %d bytes."),
84 (int) sizeof (T));
86 /* Start at the most significant end of the integer, and work towards
87 the least significant. */
88 if (byte_order == BFD_ENDIAN_BIG)
90 size_t i = 0;
92 if (std::is_signed<T>::value)
94 /* Do the sign extension once at the start. */
95 retval = ((LONGEST) buf[i] ^ 0x80) - 0x80;
96 ++i;
98 for (; i < buf.size (); ++i)
99 retval = (retval << 8) | buf[i];
101 else
103 ssize_t i = buf.size () - 1;
105 if (std::is_signed<T>::value)
107 /* Do the sign extension once at the start. */
108 retval = ((LONGEST) buf[i] ^ 0x80) - 0x80;
109 --i;
111 for (; i >= 0; --i)
112 retval = (retval << 8) | buf[i];
114 return retval;
117 /* Explicit instantiations. */
118 template LONGEST extract_integer<LONGEST> (gdb::array_view<const gdb_byte> buf,
119 enum bfd_endian byte_order);
120 template ULONGEST extract_integer<ULONGEST>
121 (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order);
123 /* Treat the bytes at BUF as a pointer of type TYPE, and return the
124 address it represents. */
125 CORE_ADDR
126 extract_typed_address (const gdb_byte *buf, struct type *type)
128 gdb_assert (type->is_pointer_or_reference ());
129 return gdbarch_pointer_to_address (type->arch (), type, buf);
132 /* All 'store' functions accept a host-format integer and store a
133 target-format integer at ADDR which is LEN bytes long. */
134 template<typename T, typename>
135 void
136 store_integer (gdb::array_view<gdb_byte> dst, enum bfd_endian byte_order,
137 T val)
139 gdb_byte *p;
140 gdb_byte *startaddr = dst.data ();
141 gdb_byte *endaddr = startaddr + dst.size ();
143 /* Start at the least significant end of the integer, and work towards
144 the most significant. */
145 if (byte_order == BFD_ENDIAN_BIG)
147 for (p = endaddr - 1; p >= startaddr; --p)
149 *p = val & 0xff;
150 val >>= 8;
153 else
155 for (p = startaddr; p < endaddr; ++p)
157 *p = val & 0xff;
158 val >>= 8;
163 /* Explicit instantiations. */
164 template void store_integer (gdb::array_view<gdb_byte> dst,
165 bfd_endian byte_order, LONGEST val);
167 template void store_integer (gdb::array_view<gdb_byte> dst,
168 bfd_endian byte_order, ULONGEST val);
170 /* Store the address ADDR as a pointer of type TYPE at BUF, in target
171 form. */
172 void
173 store_typed_address (gdb_byte *buf, struct type *type, CORE_ADDR addr)
175 gdb_assert (type->is_pointer_or_reference ());
176 gdbarch_address_to_pointer (type->arch (), type, buf, addr);
179 /* Copy a value from SOURCE of size SOURCE_SIZE bytes to DEST of size DEST_SIZE
180 bytes. If SOURCE_SIZE is greater than DEST_SIZE, then truncate the most
181 significant bytes. If SOURCE_SIZE is less than DEST_SIZE then either sign
182 or zero extended according to IS_SIGNED. Values are stored in memory with
183 endianness BYTE_ORDER. */
185 void
186 copy_integer_to_size (gdb_byte *dest, int dest_size, const gdb_byte *source,
187 int source_size, bool is_signed,
188 enum bfd_endian byte_order)
190 signed int size_diff = dest_size - source_size;
192 /* Copy across everything from SOURCE that can fit into DEST. */
194 if (byte_order == BFD_ENDIAN_BIG && size_diff > 0)
195 memcpy (dest + size_diff, source, source_size);
196 else if (byte_order == BFD_ENDIAN_BIG && size_diff < 0)
197 memcpy (dest, source - size_diff, dest_size);
198 else
199 memcpy (dest, source, std::min (source_size, dest_size));
201 /* Fill the remaining space in DEST by either zero extending or sign
202 extending. */
204 if (size_diff > 0)
206 gdb_byte extension = 0;
207 if (is_signed
208 && ((byte_order != BFD_ENDIAN_BIG && source[source_size - 1] & 0x80)
209 || (byte_order == BFD_ENDIAN_BIG && source[0] & 0x80)))
210 extension = 0xff;
212 /* Extend into MSBs of SOURCE. */
213 if (byte_order == BFD_ENDIAN_BIG)
214 memset (dest, extension, size_diff);
215 else
216 memset (dest + source_size, extension, size_diff);
220 #if GDB_SELF_TEST
221 namespace selftests {
223 /* Function to test copy_integer_to_size. Store SOURCE_VAL with size
224 SOURCE_SIZE to a buffer, making sure no sign extending happens at this
225 stage. Copy buffer to a new buffer using copy_integer_to_size. Extract
226 copied value and compare to DEST_VALU. Copy again with a signed
227 copy_integer_to_size and compare to DEST_VALS. Do everything for both
228 LITTLE and BIG target endians. Use unsigned values throughout to make
229 sure there are no implicit sign extensions. */
231 static void
232 do_cint_test (ULONGEST dest_valu, ULONGEST dest_vals, int dest_size,
233 ULONGEST src_val, int src_size)
235 for (int i = 0; i < 2 ; i++)
237 gdb_byte srcbuf[sizeof (ULONGEST)] = {};
238 gdb_byte destbuf[sizeof (ULONGEST)] = {};
239 enum bfd_endian byte_order = i ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
241 /* Fill the src buffer (and later the dest buffer) with non-zero junk,
242 to ensure zero extensions aren't hidden. */
243 memset (srcbuf, 0xaa, sizeof (srcbuf));
245 /* Store (and later extract) using unsigned to ensure there are no sign
246 extensions. */
247 store_unsigned_integer (srcbuf, src_size, byte_order, src_val);
249 /* Test unsigned. */
250 memset (destbuf, 0xaa, sizeof (destbuf));
251 copy_integer_to_size (destbuf, dest_size, srcbuf, src_size, false,
252 byte_order);
253 SELF_CHECK (dest_valu == extract_unsigned_integer (destbuf, dest_size,
254 byte_order));
256 /* Test signed. */
257 memset (destbuf, 0xaa, sizeof (destbuf));
258 copy_integer_to_size (destbuf, dest_size, srcbuf, src_size, true,
259 byte_order);
260 SELF_CHECK (dest_vals == extract_unsigned_integer (destbuf, dest_size,
261 byte_order));
265 static void
266 copy_integer_to_size_test ()
268 /* Destination is bigger than the source, which has the signed bit unset. */
269 do_cint_test (0x12345678, 0x12345678, 8, 0x12345678, 4);
270 do_cint_test (0x345678, 0x345678, 8, 0x12345678, 3);
272 /* Destination is bigger than the source, which has the signed bit set. */
273 do_cint_test (0xdeadbeef, 0xffffffffdeadbeef, 8, 0xdeadbeef, 4);
274 do_cint_test (0xadbeef, 0xffffffffffadbeef, 8, 0xdeadbeef, 3);
276 /* Destination is smaller than the source. */
277 do_cint_test (0x5678, 0x5678, 2, 0x12345678, 3);
278 do_cint_test (0xbeef, 0xbeef, 2, 0xdeadbeef, 3);
280 /* Destination and source are the same size. */
281 do_cint_test (0x8765432112345678, 0x8765432112345678, 8, 0x8765432112345678,
283 do_cint_test (0x432112345678, 0x432112345678, 6, 0x8765432112345678, 6);
284 do_cint_test (0xfeedbeaddeadbeef, 0xfeedbeaddeadbeef, 8, 0xfeedbeaddeadbeef,
286 do_cint_test (0xbeaddeadbeef, 0xbeaddeadbeef, 6, 0xfeedbeaddeadbeef, 6);
288 /* Destination is bigger than the source. Source is bigger than 32bits. */
289 do_cint_test (0x3412345678, 0x3412345678, 8, 0x3412345678, 6);
290 do_cint_test (0xff12345678, 0xff12345678, 8, 0xff12345678, 6);
291 do_cint_test (0x432112345678, 0x432112345678, 8, 0x8765432112345678, 6);
292 do_cint_test (0xff2112345678, 0xffffff2112345678, 8, 0xffffff2112345678, 6);
295 template<typename T>
296 void
297 do_extract_test (gdb_byte byte1, gdb_byte byte2, enum bfd_endian endian,
298 std::optional<T> expected)
300 std::optional<T> result;
304 const gdb_byte val[2] = { byte1, byte2 };
305 result = extract_integer<T> (gdb::make_array_view (val, 2), endian);
307 catch (const gdb_exception_error &)
311 SELF_CHECK (result == expected);
314 template<typename T>
315 void
316 do_extract_tests (gdb_byte low, gdb_byte high, std::optional<T> expected)
318 do_extract_test (low, high, BFD_ENDIAN_LITTLE, expected);
319 do_extract_test (high, low, BFD_ENDIAN_BIG, expected);
322 static void
323 extract_integer_test ()
325 do_extract_tests<uint8_t> (0x00, 0xff, {});
326 do_extract_tests<uint8_t> (0x7f, 0x23, {});
327 do_extract_tests<uint8_t> (0x80, 0xff, {});
328 do_extract_tests<uint8_t> (0x00, 0x00, 0x00);
330 do_extract_tests<int8_t> (0xff, 0x00, 0xff);
331 do_extract_tests<int8_t> (0x7f, 0x23, {});
332 do_extract_tests<int8_t> (0x80, 0xff, 0x80);
333 do_extract_tests<int8_t> (0x00, 0x00, 0x00);
336 } // namespace selftests
338 #endif
340 void _initialize_extract_store_integer ();
341 void
342 _initialize_extract_store_integer ()
344 #if GDB_SELF_TEST
345 selftests::register_test ("copy_integer_to_size",
346 selftests::copy_integer_to_size_test);
347 selftests::register_test ("extract_integer",
348 selftests::extract_integer_test);
349 #endif