]>
git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/gmp-utils.h
1 /* Miscellaneous routines making it easier to use GMP within GDB's framework.
3 Copyright (C) 2019-2023 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
23 /* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
24 access to GMP's various formatting functions. */
28 #include "gdbsupport/traits.h"
30 /* Same as gmp_asprintf, but returning an std::string. */
32 std::string
gmp_string_printf (const char *fmt
, ...);
34 /* A class to make it easier to use GMP's mpz_t values within GDB. */
41 gdb_mpz () { mpz_init (val
); }
43 explicit gdb_mpz (const mpz_t
&from_val
)
46 mpz_set (val
, from_val
);
49 gdb_mpz (const gdb_mpz
&from
)
52 mpz_set (val
, from
.val
);
55 /* Initialize using the given integral value.
57 The main advantage of this method is that it handles both signed
58 and unsigned types, with no size restriction. */
59 template<typename T
, typename
= gdb::Requires
<std::is_integral
<T
>>>
60 explicit gdb_mpz (T src
)
66 explicit gdb_mpz (gdb_mpz
&&from
)
69 mpz_swap (val
, from
.val
);
73 gdb_mpz
&operator= (const gdb_mpz
&from
)
75 mpz_set (val
, from
.val
);
79 gdb_mpz
&operator= (gdb_mpz
&&other
)
81 mpz_swap (val
, other
.val
);
85 template<typename T
, typename
= gdb::Requires
<std::is_integral
<T
>>>
86 gdb_mpz
&operator= (T src
)
92 /* Initialize this value from a string and a base. Returns true if
93 the string was parsed successfully, false otherwise. */
94 bool set (const char *str
, int base
)
96 return mpz_set_str (val
, str
, base
) != -1;
99 /* Return a new value that is BASE**EXP. */
100 static gdb_mpz
pow (unsigned long base
, unsigned long exp
)
103 mpz_ui_pow_ui (result
.val
, base
, exp
);
107 /* Convert VAL to an integer of the given type.
109 The return type can signed or unsigned, with no size restriction. */
110 template<typename T
> T
as_integer () const;
112 /* Set VAL by importing the number stored in the byte array (BUF),
113 using the given BYTE_ORDER. The size of the data to read is
114 the byte array's size.
116 UNSIGNED_P indicates whether the number has an unsigned type. */
117 void read (gdb::array_view
<const gdb_byte
> buf
, enum bfd_endian byte_order
,
120 /* Write VAL into BUF as a number whose byte size is the size of BUF,
121 using the given BYTE_ORDER.
123 UNSIGNED_P indicates whether the number has an unsigned type. */
124 void write (gdb::array_view
<gdb_byte
> buf
, enum bfd_endian byte_order
,
125 bool unsigned_p
) const;
127 /* Return a string containing VAL. */
128 std::string
str () const { return gmp_string_printf ("%Zd", val
); }
130 /* The destructor. */
131 ~gdb_mpz () { mpz_clear (val
); }
133 /* Negate this value in place. */
139 gdb_mpz
&operator*= (long other
)
141 mpz_mul_si (val
, val
, other
);
145 gdb_mpz
&operator+= (unsigned long other
)
147 mpz_add_ui (val
, val
, other
);
151 gdb_mpz
&operator-= (unsigned long other
)
153 mpz_sub_ui (val
, val
, other
);
157 gdb_mpz
&operator<<= (unsigned long nbits
)
159 mpz_mul_2exp (val
, val
, nbits
);
163 bool operator> (const gdb_mpz
&other
) const
165 return mpz_cmp (val
, other
.val
) > 0;
168 bool operator< (int other
) const
170 return mpz_cmp_si (val
, other
) < 0;
173 bool operator== (int other
) const
175 return mpz_cmp_si (val
, other
) == 0;
178 bool operator== (const gdb_mpz
&other
) const
180 return mpz_cmp (val
, other
.val
) == 0;
185 /* Helper template for constructor and operator=. */
186 template<typename T
> void set (T src
);
188 /* Low-level function to export VAL into BUF as a number whose byte size
191 If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
192 Otherwise, export it as a signed value.
194 The API is inspired from GMP's mpz_export, hence the naming and types
195 of the following parameter:
197 . 1 for most significant byte first; or
198 . -1 for least significant byte first; or
199 . 0 for native endianness.
201 An error is raised if BUF is not large enough to contain the value
203 void safe_export (gdb::array_view
<gdb_byte
> buf
,
204 int endian
, bool unsigned_p
) const;
207 /* A class to make it easier to use GMP's mpq_t values within GDB. */
214 gdb_mpq () { mpq_init (val
); }
216 explicit gdb_mpq (const mpq_t
&from_val
)
219 mpq_set (val
, from_val
);
222 gdb_mpq (const gdb_mpq
&from
)
225 mpq_set (val
, from
.val
);
228 explicit gdb_mpq (gdb_mpq
&&from
)
231 mpq_swap (val
, from
.val
);
234 gdb_mpq (const gdb_mpz
&num
, const gdb_mpz
&denom
)
237 mpz_set (mpq_numref (val
), num
.val
);
238 mpz_set (mpq_denref (val
), denom
.val
);
239 mpq_canonicalize (val
);
242 /* Copy assignment operator. */
243 gdb_mpq
&operator= (const gdb_mpq
&from
)
245 mpq_set (val
, from
.val
);
249 gdb_mpq
&operator= (gdb_mpq
&&from
)
251 mpq_swap (val
, from
.val
);
255 gdb_mpq
&operator= (const gdb_mpz
&from
)
257 mpq_set_z (val
, from
.val
);
261 /* Return a string representing VAL as "<numerator> / <denominator>". */
262 std::string
str () const { return gmp_string_printf ("%Qd", val
); }
264 /* Return VAL rounded to the nearest integer. */
265 gdb_mpz
get_rounded () const;
267 /* Return this value as an integer, rounded toward zero. */
268 gdb_mpz
as_integer () const
271 mpz_tdiv_q (result
.val
, mpq_numref (val
), mpq_denref (val
));
275 /* Set VAL from the contents of the given byte array (BUF), which
276 contains the unscaled value of a fixed point type object.
277 The byte size of the data is the size of BUF.
279 BYTE_ORDER provides the byte_order to use when reading the data.
281 UNSIGNED_P indicates whether the number has an unsigned type.
282 SCALING_FACTOR is the scaling factor to apply after having
283 read the unscaled value from our buffer. */
284 void read_fixed_point (gdb::array_view
<const gdb_byte
> buf
,
285 enum bfd_endian byte_order
, bool unsigned_p
,
286 const gdb_mpq
&scaling_factor
);
288 /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
289 The size of BUF is used as the length to write the value into.
291 UNSIGNED_P indicates whether the number has an unsigned type.
292 SCALING_FACTOR is the scaling factor to apply before writing
293 the unscaled value to our buffer. */
294 void write_fixed_point (gdb::array_view
<gdb_byte
> buf
,
295 enum bfd_endian byte_order
, bool unsigned_p
,
296 const gdb_mpq
&scaling_factor
) const;
298 /* The destructor. */
299 ~gdb_mpq () { mpq_clear (val
); }
302 /* A class to make it easier to use GMP's mpf_t values within GDB.
304 Should MPFR become a required dependency, we should probably
305 drop this class in favor of using MPFR. */
312 gdb_mpf () { mpf_init (val
); }
314 DISABLE_COPY_AND_ASSIGN (gdb_mpf
);
316 /* Set VAL from the contents of the given buffer (BUF), which
317 contains the unscaled value of a fixed point type object
318 with the given size (LEN) and byte order (BYTE_ORDER).
320 UNSIGNED_P indicates whether the number has an unsigned type.
321 SCALING_FACTOR is the scaling factor to apply after having
322 read the unscaled value from our buffer. */
323 void read_fixed_point (gdb::array_view
<const gdb_byte
> buf
,
324 enum bfd_endian byte_order
, bool unsigned_p
,
325 const gdb_mpq
&scaling_factor
)
329 tmp_q
.read_fixed_point (buf
, byte_order
, unsigned_p
, scaling_factor
);
330 mpf_set_q (val
, tmp_q
.val
);
333 /* The destructor. */
334 ~gdb_mpf () { mpf_clear (val
); }
337 /* See declaration above. */
343 mpz_import (val
, 1 /* count */, -1 /* order */,
344 sizeof (T
) /* size */, 0 /* endian (0 = native) */,
345 0 /* nails */, &src
/* op */);
346 if (std::is_signed
<T
>::value
&& src
< 0)
348 /* mpz_import does not handle the sign, so our value was imported
349 as an unsigned. Adjust that imported value so as to make it
350 the correct negative value. */
353 mpz_ui_pow_ui (neg_offset
.val
, 2, sizeof (T
) * HOST_CHAR_BIT
);
354 mpz_sub (val
, val
, neg_offset
.val
);
358 /* See declaration above. */
362 gdb_mpz::as_integer () const
366 this->safe_export ({(gdb_byte
*) &result
, sizeof (result
)},
367 0 /* endian (0 = native) */,
368 !std::is_signed
<T
>::value
/* unsigned_p */);