[gdb/testsuite] Fix gdb.threads/threadcrash.exp with glibc debuginfo
[binutils-gdb.git] / gdb / extract-store-integer.c
blob621af253e25519cd5edce1961e10377d4fd5fa6b
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 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));
34 /* Start at the most significant end of the integer, and work towards
35 the least significant. */
36 if (byte_order == BFD_ENDIAN_BIG)
38 size_t i = 0;
40 if (std::is_signed<T>::value)
42 /* Do the sign extension once at the start. */
43 retval = ((LONGEST) buf[i] ^ 0x80) - 0x80;
44 ++i;
46 for (; i < buf.size (); ++i)
47 retval = (retval << 8) | buf[i];
49 else
51 ssize_t i = buf.size () - 1;
53 if (std::is_signed<T>::value)
55 /* Do the sign extension once at the start. */
56 retval = ((LONGEST) buf[i] ^ 0x80) - 0x80;
57 --i;
59 for (; i >= 0; --i)
60 retval = (retval << 8) | buf[i];
62 return retval;
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);
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. */
76 int
77 extract_long_unsigned_integer (const gdb_byte *addr, int orig_len,
78 enum bfd_endian byte_order, LONGEST *pval)
80 const gdb_byte *p;
81 const gdb_byte *first_addr;
82 int len;
84 len = orig_len;
85 if (byte_order == BFD_ENDIAN_BIG)
87 for (p = addr;
88 len > (int) sizeof (LONGEST) && p < addr + orig_len;
89 p++)
91 if (*p == 0)
92 len--;
93 else
94 break;
96 first_addr = p;
98 else
100 first_addr = addr;
101 for (p = addr + orig_len - 1;
102 len > (int) sizeof (LONGEST) && p >= addr;
103 p--)
105 if (*p == 0)
106 len--;
107 else
108 break;
112 if (len <= (int) sizeof (LONGEST))
114 *pval = (LONGEST) extract_unsigned_integer (first_addr,
115 sizeof (LONGEST),
116 byte_order);
117 return 1;
120 return 0;
124 /* Treat the bytes at BUF as a pointer of type TYPE, and return the
125 address it represents. */
126 CORE_ADDR
127 extract_typed_address (const gdb_byte *buf, struct type *type)
129 gdb_assert (type->is_pointer_or_reference ());
130 return gdbarch_pointer_to_address (type->arch (), type, buf);
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
137 store_integer (gdb::array_view<gdb_byte> dst, enum bfd_endian byte_order,
138 T val)
140 gdb_byte *p;
141 gdb_byte *startaddr = dst.data ();
142 gdb_byte *endaddr = startaddr + dst.size ();
144 /* Start at the least significant end of the integer, and work towards
145 the most significant. */
146 if (byte_order == BFD_ENDIAN_BIG)
148 for (p = endaddr - 1; p >= startaddr; --p)
150 *p = val & 0xff;
151 val >>= 8;
154 else
156 for (p = startaddr; p < endaddr; ++p)
158 *p = val & 0xff;
159 val >>= 8;
164 /* Explicit instantiations. */
165 template void store_integer (gdb::array_view<gdb_byte> dst,
166 bfd_endian byte_order, LONGEST val);
168 template void store_integer (gdb::array_view<gdb_byte> dst,
169 bfd_endian byte_order, ULONGEST val);
171 /* Store the address ADDR as a pointer of type TYPE at BUF, in target
172 form. */
173 void
174 store_typed_address (gdb_byte *buf, struct type *type, CORE_ADDR addr)
176 gdb_assert (type->is_pointer_or_reference ());
177 gdbarch_address_to_pointer (type->arch (), type, buf, addr);
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. */
186 void
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)
191 signed int size_diff = dest_size - source_size;
193 /* Copy across everything from SOURCE that can fit into DEST. */
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));
202 /* Fill the remaining space in DEST by either zero extending or sign
203 extending. */
205 if (size_diff > 0)
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;
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);
221 #if GDB_SELF_TEST
222 namespace selftests {
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. */
232 static void
233 do_cint_test (ULONGEST dest_valu, ULONGEST dest_vals, int dest_size,
234 ULONGEST src_val, int src_size)
236 for (int i = 0; i < 2 ; i++)
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;
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));
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);
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));
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));
266 static void
267 copy_integer_to_size_test ()
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);
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);
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);
281 /* Destination and source are the same size. */
282 do_cint_test (0x8765432112345678, 0x8765432112345678, 8, 0x8765432112345678,
284 do_cint_test (0x432112345678, 0x432112345678, 6, 0x8765432112345678, 6);
285 do_cint_test (0xfeedbeaddeadbeef, 0xfeedbeaddeadbeef, 8, 0xfeedbeaddeadbeef,
287 do_cint_test (0xbeaddeadbeef, 0xbeaddeadbeef, 6, 0xfeedbeaddeadbeef, 6);
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);
296 } // namespace selftests
298 #endif
300 void _initialize_extract_store_integer ();
301 void
302 _initialize_extract_store_integer ()
304 #if GDB_SELF_TEST
305 selftests::register_test ("copy_integer_to_size",
306 selftests::copy_integer_to_size_test);
307 #endif