1 /* Miscellaneous routines making it easier to use GMP within GDB's framework.
3 Copyright (C) 2019-2024 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
, ...);
37 /* A class to make it easier to use GMP's mpz_t values within GDB. */
42 gdb_mpz () { mpz_init (m_val
); }
44 explicit gdb_mpz (const mpz_t
&from_val
)
47 mpz_set (m_val
, from_val
);
50 gdb_mpz (const gdb_mpz
&from
)
53 mpz_set (m_val
, from
.m_val
);
56 /* Initialize using the given integral value.
58 The main advantage of this method is that it handles both signed
59 and unsigned types, with no size restriction. */
60 template<typename T
, typename
= gdb::Requires
<std::is_integral
<T
>>>
61 explicit gdb_mpz (T src
)
67 explicit gdb_mpz (gdb_mpz
&&from
)
70 mpz_swap (m_val
, from
.m_val
);
74 gdb_mpz
&operator= (const gdb_mpz
&from
)
76 mpz_set (m_val
, from
.m_val
);
80 gdb_mpz
&operator= (gdb_mpz
&&other
)
82 mpz_swap (m_val
, other
.m_val
);
86 template<typename T
, typename
= gdb::Requires
<std::is_integral
<T
>>>
87 gdb_mpz
&operator= (T src
)
93 gdb_mpz
&operator= (bool src
)
95 mpz_set_ui (m_val
, (unsigned long) src
);
99 /* Initialize this value from a string and a base. Returns true if
100 the string was parsed successfully, false otherwise. */
101 bool set (const char *str
, int base
)
103 return mpz_set_str (m_val
, str
, base
) != -1;
106 /* Return a new value that is BASE**EXP. */
107 static gdb_mpz
pow (unsigned long base
, unsigned long exp
)
110 mpz_ui_pow_ui (result
.m_val
, base
, exp
);
114 /* Return a new value that is this value raised to EXP. */
115 gdb_mpz
pow (unsigned long exp
) const
118 mpz_pow_ui (result
.m_val
, m_val
, exp
);
122 /* Convert this value to an integer of the given type.
124 The return type can signed or unsigned, with no size restriction. */
125 template<typename T
> T
as_integer () const;
127 /* Convert this value to an integer of the given type. If this
128 value is too large, it is truncated.
130 The return type can signed or unsigned, with no size restriction. */
131 template<typename T
> T
as_integer_truncate () const;
133 /* Set VAL by importing the number stored in the byte array (BUF),
134 using the given BYTE_ORDER. The size of the data to read is
135 the byte array's size.
137 UNSIGNED_P indicates whether the number has an unsigned type. */
138 void read (gdb::array_view
<const gdb_byte
> buf
, enum bfd_endian byte_order
,
141 /* Write VAL into BUF as a number whose byte size is the size of BUF,
142 using the given BYTE_ORDER.
144 UNSIGNED_P indicates whether the number has an unsigned type. */
145 void write (gdb::array_view
<gdb_byte
> buf
, enum bfd_endian byte_order
,
146 bool unsigned_p
) const
148 export_bits (buf
, byte_order
== BFD_ENDIAN_BIG
? 1 : -1 /* endian */,
149 unsigned_p
, true /* safe */);
152 /* Like write, but truncates the value to the desired number of
154 void truncate (gdb::array_view
<gdb_byte
> buf
, enum bfd_endian byte_order
,
155 bool unsigned_p
) const
157 export_bits (buf
, byte_order
== BFD_ENDIAN_BIG
? 1 : -1 /* endian */,
158 unsigned_p
, false /* safe */);
161 /* Return a string containing VAL. */
162 std::string
str () const { return gmp_string_printf ("%Zd", m_val
); }
164 /* The destructor. */
165 ~gdb_mpz () { mpz_clear (m_val
); }
167 /* Negate this value in place. */
170 mpz_neg (m_val
, m_val
);
173 /* Take the one's complement in place. */
175 { mpz_com (m_val
, m_val
); }
177 /* Mask this value to N bits, in place. */
178 void mask (unsigned n
)
179 { mpz_tdiv_r_2exp (m_val
, m_val
, n
); }
181 /* Return the sign of this value. This returns -1 for a negative
182 value, 0 if the value is 0, and 1 for a positive value. */
184 { return mpz_sgn (m_val
); }
186 explicit operator bool () const
187 { return sgn () != 0; }
189 gdb_mpz
&operator*= (long other
)
191 mpz_mul_si (m_val
, m_val
, other
);
195 gdb_mpz
operator* (const gdb_mpz
&other
) const
198 mpz_mul (result
.m_val
, m_val
, other
.m_val
);
202 gdb_mpz
operator/ (const gdb_mpz
&other
) const
205 mpz_tdiv_q (result
.m_val
, m_val
, other
.m_val
);
209 gdb_mpz
operator% (const gdb_mpz
&other
) const
212 mpz_tdiv_r (result
.m_val
, m_val
, other
.m_val
);
216 gdb_mpz
&operator+= (unsigned long other
)
218 mpz_add_ui (m_val
, m_val
, other
);
222 gdb_mpz
&operator+= (const gdb_mpz
&other
)
224 mpz_add (m_val
, m_val
, other
.m_val
);
228 gdb_mpz
operator+ (const gdb_mpz
&other
) const
231 mpz_add (result
.m_val
, m_val
, other
.m_val
);
235 gdb_mpz
&operator-= (unsigned long other
)
237 mpz_sub_ui (m_val
, m_val
, other
);
241 gdb_mpz
&operator-= (const gdb_mpz
&other
)
243 mpz_sub (m_val
, m_val
, other
.m_val
);
247 gdb_mpz
operator- (const gdb_mpz
&other
) const
250 mpz_sub (result
.m_val
, m_val
, other
.m_val
);
254 gdb_mpz
operator- () const
257 mpz_neg (result
.m_val
, m_val
);
261 gdb_mpz
&operator<<= (unsigned long nbits
)
263 mpz_mul_2exp (m_val
, m_val
, nbits
);
267 gdb_mpz
operator<< (unsigned long nbits
) const &
270 mpz_mul_2exp (result
.m_val
, m_val
, nbits
);
274 gdb_mpz
operator<< (unsigned long nbits
) &&
276 mpz_mul_2exp (m_val
, m_val
, nbits
);
280 gdb_mpz
operator>> (unsigned long nbits
) const
283 mpz_tdiv_q_2exp (result
.m_val
, m_val
, nbits
);
287 gdb_mpz
&operator>>= (unsigned long nbits
)
289 mpz_tdiv_q_2exp (m_val
, m_val
, nbits
);
293 gdb_mpz
operator& (const gdb_mpz
&other
) const
296 mpz_and (result
.m_val
, m_val
, other
.m_val
);
300 gdb_mpz
operator| (const gdb_mpz
&other
) const
303 mpz_ior (result
.m_val
, m_val
, other
.m_val
);
307 gdb_mpz
operator^ (const gdb_mpz
&other
) const
310 mpz_xor (result
.m_val
, m_val
, other
.m_val
);
314 bool operator> (const gdb_mpz
&other
) const
316 return mpz_cmp (m_val
, other
.m_val
) > 0;
319 bool operator>= (const gdb_mpz
&other
) const
321 return mpz_cmp (m_val
, other
.m_val
) >= 0;
324 bool operator< (const gdb_mpz
&other
) const
326 return mpz_cmp (m_val
, other
.m_val
) < 0;
329 bool operator<= (const gdb_mpz
&other
) const
331 return mpz_cmp (m_val
, other
.m_val
) <= 0;
334 bool operator< (long other
) const
336 return mpz_cmp_si (m_val
, other
) < 0;
339 /* We want an operator== that can handle all integer types. For
340 types that are 'long' or narrower, we can use a GMP function and
341 avoid boxing the RHS. But, because overloading based on integer
342 type is a pain in C++, we accept all such types here and check
343 the size in the body. */
344 template<typename T
, typename
= gdb::Requires
<std::is_integral
<T
>>>
345 bool operator== (T other
) const
347 if (std::is_signed
<T
>::value
)
349 if (sizeof (T
) <= sizeof (long))
350 return mpz_cmp_si (m_val
, other
) == 0;
354 if (sizeof (T
) <= sizeof (unsigned long))
355 return mpz_cmp_ui (m_val
, other
) == 0;
357 return *this == gdb_mpz (other
);
360 bool operator== (const gdb_mpz
&other
) const
362 return mpz_cmp (m_val
, other
.m_val
) == 0;
365 bool operator!= (const gdb_mpz
&other
) const
367 return mpz_cmp (m_val
, other
.m_val
) != 0;
372 /* Helper template for constructor and operator=. */
373 template<typename T
> void set (T src
);
375 /* Low-level function to export VAL into BUF as a number whose byte size
378 If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
379 Otherwise, export it as a signed value.
381 The API is inspired from GMP's mpz_export, hence the naming and types
382 of the following parameter:
384 . 1 for most significant byte first; or
385 . -1 for least significant byte first; or
386 . 0 for native endianness.
388 If SAFE is true, an error is raised if BUF is not large enough to
389 contain the value being exported. If SAFE is false, the value is
390 truncated to fit in BUF. */
391 void export_bits (gdb::array_view
<gdb_byte
> buf
, int endian
, bool unsigned_p
,
394 friend struct gdb_mpq
;
395 friend struct gdb_mpf
;
400 /* A class to make it easier to use GMP's mpq_t values within GDB. */
405 gdb_mpq () { mpq_init (m_val
); }
407 explicit gdb_mpq (const mpq_t
&from_val
)
410 mpq_set (m_val
, from_val
);
413 gdb_mpq (const gdb_mpq
&from
)
416 mpq_set (m_val
, from
.m_val
);
419 explicit gdb_mpq (gdb_mpq
&&from
)
422 mpq_swap (m_val
, from
.m_val
);
425 gdb_mpq (const gdb_mpz
&num
, const gdb_mpz
&denom
)
428 mpz_set (mpq_numref (m_val
), num
.m_val
);
429 mpz_set (mpq_denref (m_val
), denom
.m_val
);
430 mpq_canonicalize (m_val
);
433 gdb_mpq (long num
, long denom
)
436 mpq_set_si (m_val
, num
, denom
);
437 mpq_canonicalize (m_val
);
440 /* Copy assignment operator. */
441 gdb_mpq
&operator= (const gdb_mpq
&from
)
443 mpq_set (m_val
, from
.m_val
);
447 gdb_mpq
&operator= (gdb_mpq
&&from
)
449 mpq_swap (m_val
, from
.m_val
);
453 gdb_mpq
&operator= (const gdb_mpz
&from
)
455 mpq_set_z (m_val
, from
.m_val
);
459 gdb_mpq
&operator= (double d
)
461 mpq_set_d (m_val
, d
);
465 /* Return the sign of this value. This returns -1 for a negative
466 value, 0 if the value is 0, and 1 for a positive value. */
468 { return mpq_sgn (m_val
); }
470 gdb_mpq
operator+ (const gdb_mpq
&other
) const
473 mpq_add (result
.m_val
, m_val
, other
.m_val
);
477 gdb_mpq
operator- (const gdb_mpq
&other
) const
480 mpq_sub (result
.m_val
, m_val
, other
.m_val
);
484 gdb_mpq
operator* (const gdb_mpq
&other
) const
487 mpq_mul (result
.m_val
, m_val
, other
.m_val
);
491 gdb_mpq
operator/ (const gdb_mpq
&other
) const
494 mpq_div (result
.m_val
, m_val
, other
.m_val
);
498 gdb_mpq
&operator*= (const gdb_mpq
&other
)
500 mpq_mul (m_val
, m_val
, other
.m_val
);
504 gdb_mpq
&operator/= (const gdb_mpq
&other
)
506 mpq_div (m_val
, m_val
, other
.m_val
);
510 bool operator== (const gdb_mpq
&other
) const
512 return mpq_cmp (m_val
, other
.m_val
) == 0;
515 bool operator< (const gdb_mpq
&other
) const
517 return mpq_cmp (m_val
, other
.m_val
) < 0;
520 /* Return a string representing VAL as "<numerator> / <denominator>". */
521 std::string
str () const { return gmp_string_printf ("%Qd", m_val
); }
523 /* Return VAL rounded to the nearest integer. */
524 gdb_mpz
get_rounded () const;
526 /* Return this value as an integer, rounded toward zero. */
527 gdb_mpz
as_integer () const
530 mpz_tdiv_q (result
.m_val
, mpq_numref (m_val
), mpq_denref (m_val
));
534 /* Return this value converted to a host double. */
535 double as_double () const
536 { return mpq_get_d (m_val
); }
538 /* Set VAL from the contents of the given byte array (BUF), which
539 contains the unscaled value of a fixed point type object.
540 The byte size of the data is the size of BUF.
542 BYTE_ORDER provides the byte_order to use when reading the data.
544 UNSIGNED_P indicates whether the number has an unsigned type.
545 SCALING_FACTOR is the scaling factor to apply after having
546 read the unscaled value from our buffer. */
547 void read_fixed_point (gdb::array_view
<const gdb_byte
> buf
,
548 enum bfd_endian byte_order
, bool unsigned_p
,
549 const gdb_mpq
&scaling_factor
);
551 /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
552 The size of BUF is used as the length to write the value into.
554 UNSIGNED_P indicates whether the number has an unsigned type.
555 SCALING_FACTOR is the scaling factor to apply before writing
556 the unscaled value to our buffer. */
557 void write_fixed_point (gdb::array_view
<gdb_byte
> buf
,
558 enum bfd_endian byte_order
, bool unsigned_p
,
559 const gdb_mpq
&scaling_factor
) const;
561 /* The destructor. */
562 ~gdb_mpq () { mpq_clear (m_val
); }
566 friend struct gdb_mpf
;
571 /* A class to make it easier to use GMP's mpf_t values within GDB.
573 Should MPFR become a required dependency, we should probably
574 drop this class in favor of using MPFR. */
579 gdb_mpf () { mpf_init (m_val
); }
581 DISABLE_COPY_AND_ASSIGN (gdb_mpf
);
583 /* Set VAL from the contents of the given buffer (BUF), which
584 contains the unscaled value of a fixed point type object
585 with the given size (LEN) and byte order (BYTE_ORDER).
587 UNSIGNED_P indicates whether the number has an unsigned type.
588 SCALING_FACTOR is the scaling factor to apply after having
589 read the unscaled value from our buffer. */
590 void read_fixed_point (gdb::array_view
<const gdb_byte
> buf
,
591 enum bfd_endian byte_order
, bool unsigned_p
,
592 const gdb_mpq
&scaling_factor
)
596 tmp_q
.read_fixed_point (buf
, byte_order
, unsigned_p
, scaling_factor
);
597 mpf_set_q (m_val
, tmp_q
.m_val
);
600 /* Convert this value to a string. FMT is the format to use, and
601 should have a single '%' substitution. */
602 std::string
str (const char *fmt
) const
603 { return gmp_string_printf (fmt
, m_val
); }
605 /* The destructor. */
606 ~gdb_mpf () { mpf_clear (m_val
); }
613 /* See declaration above. */
619 mpz_import (m_val
, 1 /* count */, -1 /* order */,
620 sizeof (T
) /* size */, 0 /* endian (0 = native) */,
621 0 /* nails */, &src
/* op */);
622 if (std::is_signed
<T
>::value
&& src
< 0)
624 /* mpz_import does not handle the sign, so our value was imported
625 as an unsigned. Adjust that imported value so as to make it
626 the correct negative value. */
629 mpz_ui_pow_ui (neg_offset
.m_val
, 2, sizeof (T
) * HOST_CHAR_BIT
);
630 mpz_sub (m_val
, m_val
, neg_offset
.m_val
);
634 /* See declaration above. */
638 gdb_mpz::as_integer () const
642 this->export_bits ({(gdb_byte
*) &result
, sizeof (result
)},
643 0 /* endian (0 = native) */,
644 !std::is_signed
<T
>::value
/* unsigned_p */,
650 /* See declaration above. */
654 gdb_mpz::as_integer_truncate () const
658 this->export_bits ({(gdb_byte
*) &result
, sizeof (result
)},
659 0 /* endian (0 = native) */,
660 !std::is_signed
<T
>::value
/* unsigned_p */,