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
, ...);
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<<= (unsigned long nbits
)
256 mpz_mul_2exp (m_val
, m_val
, nbits
);
260 gdb_mpz
operator<< (unsigned long nbits
) const
263 mpz_mul_2exp (result
.m_val
, m_val
, nbits
);
267 gdb_mpz
operator>> (unsigned long nbits
) const
270 mpz_tdiv_q_2exp (result
.m_val
, m_val
, nbits
);
274 gdb_mpz
&operator>>= (unsigned long nbits
)
276 mpz_tdiv_q_2exp (m_val
, m_val
, nbits
);
280 gdb_mpz
operator& (const gdb_mpz
&other
) const
283 mpz_and (result
.m_val
, m_val
, other
.m_val
);
287 gdb_mpz
operator| (const gdb_mpz
&other
) const
290 mpz_ior (result
.m_val
, m_val
, other
.m_val
);
294 gdb_mpz
operator^ (const gdb_mpz
&other
) const
297 mpz_xor (result
.m_val
, m_val
, other
.m_val
);
301 bool operator> (const gdb_mpz
&other
) const
303 return mpz_cmp (m_val
, other
.m_val
) > 0;
306 bool operator>= (const gdb_mpz
&other
) const
308 return mpz_cmp (m_val
, other
.m_val
) >= 0;
311 bool operator< (const gdb_mpz
&other
) const
313 return mpz_cmp (m_val
, other
.m_val
) < 0;
316 bool operator<= (const gdb_mpz
&other
) const
318 return mpz_cmp (m_val
, other
.m_val
) <= 0;
321 bool operator< (long other
) const
323 return mpz_cmp_si (m_val
, other
) < 0;
326 /* We want an operator== that can handle all integer types. For
327 types that are 'long' or narrower, we can use a GMP function and
328 avoid boxing the RHS. But, because overloading based on integer
329 type is a pain in C++, we accept all such types here and check
330 the size in the body. */
331 template<typename T
, typename
= gdb::Requires
<std::is_integral
<T
>>>
332 bool operator== (T other
) const
334 if (std::is_signed
<T
>::value
)
336 if (sizeof (T
) <= sizeof (long))
337 return mpz_cmp_si (m_val
, other
) == 0;
341 if (sizeof (T
) <= sizeof (unsigned long))
342 return mpz_cmp_ui (m_val
, other
) == 0;
344 return *this == gdb_mpz (other
);
347 bool operator== (const gdb_mpz
&other
) const
349 return mpz_cmp (m_val
, other
.m_val
) == 0;
352 bool operator!= (const gdb_mpz
&other
) const
354 return mpz_cmp (m_val
, other
.m_val
) != 0;
359 /* Helper template for constructor and operator=. */
360 template<typename T
> void set (T src
);
362 /* Low-level function to export VAL into BUF as a number whose byte size
365 If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
366 Otherwise, export it as a signed value.
368 The API is inspired from GMP's mpz_export, hence the naming and types
369 of the following parameter:
371 . 1 for most significant byte first; or
372 . -1 for least significant byte first; or
373 . 0 for native endianness.
375 If SAFE is true, an error is raised if BUF is not large enough to
376 contain the value being exported. If SAFE is false, the value is
377 truncated to fit in BUF. */
378 void export_bits (gdb::array_view
<gdb_byte
> buf
, int endian
, bool unsigned_p
,
381 friend struct gdb_mpq
;
382 friend struct gdb_mpf
;
387 /* A class to make it easier to use GMP's mpq_t values within GDB. */
392 gdb_mpq () { mpq_init (m_val
); }
394 explicit gdb_mpq (const mpq_t
&from_val
)
397 mpq_set (m_val
, from_val
);
400 gdb_mpq (const gdb_mpq
&from
)
403 mpq_set (m_val
, from
.m_val
);
406 explicit gdb_mpq (gdb_mpq
&&from
)
409 mpq_swap (m_val
, from
.m_val
);
412 gdb_mpq (const gdb_mpz
&num
, const gdb_mpz
&denom
)
415 mpz_set (mpq_numref (m_val
), num
.m_val
);
416 mpz_set (mpq_denref (m_val
), denom
.m_val
);
417 mpq_canonicalize (m_val
);
420 gdb_mpq (long num
, long denom
)
423 mpq_set_si (m_val
, num
, denom
);
424 mpq_canonicalize (m_val
);
427 /* Copy assignment operator. */
428 gdb_mpq
&operator= (const gdb_mpq
&from
)
430 mpq_set (m_val
, from
.m_val
);
434 gdb_mpq
&operator= (gdb_mpq
&&from
)
436 mpq_swap (m_val
, from
.m_val
);
440 gdb_mpq
&operator= (const gdb_mpz
&from
)
442 mpq_set_z (m_val
, from
.m_val
);
446 gdb_mpq
&operator= (double d
)
448 mpq_set_d (m_val
, d
);
452 /* Return the sign of this value. This returns -1 for a negative
453 value, 0 if the value is 0, and 1 for a positive value. */
455 { return mpq_sgn (m_val
); }
457 gdb_mpq
operator+ (const gdb_mpq
&other
) const
460 mpq_add (result
.m_val
, m_val
, other
.m_val
);
464 gdb_mpq
operator- (const gdb_mpq
&other
) const
467 mpq_sub (result
.m_val
, m_val
, other
.m_val
);
471 gdb_mpq
operator* (const gdb_mpq
&other
) const
474 mpq_mul (result
.m_val
, m_val
, other
.m_val
);
478 gdb_mpq
operator/ (const gdb_mpq
&other
) const
481 mpq_div (result
.m_val
, m_val
, other
.m_val
);
485 gdb_mpq
&operator*= (const gdb_mpq
&other
)
487 mpq_mul (m_val
, m_val
, other
.m_val
);
491 gdb_mpq
&operator/= (const gdb_mpq
&other
)
493 mpq_div (m_val
, m_val
, other
.m_val
);
497 bool operator== (const gdb_mpq
&other
) const
499 return mpq_cmp (m_val
, other
.m_val
) == 0;
502 bool operator< (const gdb_mpq
&other
) const
504 return mpq_cmp (m_val
, other
.m_val
) < 0;
507 /* Return a string representing VAL as "<numerator> / <denominator>". */
508 std::string
str () const { return gmp_string_printf ("%Qd", m_val
); }
510 /* Return VAL rounded to the nearest integer. */
511 gdb_mpz
get_rounded () const;
513 /* Return this value as an integer, rounded toward zero. */
514 gdb_mpz
as_integer () const
517 mpz_tdiv_q (result
.m_val
, mpq_numref (m_val
), mpq_denref (m_val
));
521 /* Return this value converted to a host double. */
522 double as_double () const
523 { return mpq_get_d (m_val
); }
525 /* Set VAL from the contents of the given byte array (BUF), which
526 contains the unscaled value of a fixed point type object.
527 The byte size of the data is the size of BUF.
529 BYTE_ORDER provides the byte_order to use when reading the data.
531 UNSIGNED_P indicates whether the number has an unsigned type.
532 SCALING_FACTOR is the scaling factor to apply after having
533 read the unscaled value from our buffer. */
534 void read_fixed_point (gdb::array_view
<const gdb_byte
> buf
,
535 enum bfd_endian byte_order
, bool unsigned_p
,
536 const gdb_mpq
&scaling_factor
);
538 /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
539 The size of BUF is used as the length to write the value into.
541 UNSIGNED_P indicates whether the number has an unsigned type.
542 SCALING_FACTOR is the scaling factor to apply before writing
543 the unscaled value to our buffer. */
544 void write_fixed_point (gdb::array_view
<gdb_byte
> buf
,
545 enum bfd_endian byte_order
, bool unsigned_p
,
546 const gdb_mpq
&scaling_factor
) const;
548 /* The destructor. */
549 ~gdb_mpq () { mpq_clear (m_val
); }
553 friend struct gdb_mpf
;
558 /* A class to make it easier to use GMP's mpf_t values within GDB.
560 Should MPFR become a required dependency, we should probably
561 drop this class in favor of using MPFR. */
566 gdb_mpf () { mpf_init (m_val
); }
568 DISABLE_COPY_AND_ASSIGN (gdb_mpf
);
570 /* Set VAL from the contents of the given buffer (BUF), which
571 contains the unscaled value of a fixed point type object
572 with the given size (LEN) and byte order (BYTE_ORDER).
574 UNSIGNED_P indicates whether the number has an unsigned type.
575 SCALING_FACTOR is the scaling factor to apply after having
576 read the unscaled value from our buffer. */
577 void read_fixed_point (gdb::array_view
<const gdb_byte
> buf
,
578 enum bfd_endian byte_order
, bool unsigned_p
,
579 const gdb_mpq
&scaling_factor
)
583 tmp_q
.read_fixed_point (buf
, byte_order
, unsigned_p
, scaling_factor
);
584 mpf_set_q (m_val
, tmp_q
.m_val
);
587 /* Convert this value to a string. FMT is the format to use, and
588 should have a single '%' substitution. */
589 std::string
str (const char *fmt
) const
590 { return gmp_string_printf (fmt
, m_val
); }
592 /* The destructor. */
593 ~gdb_mpf () { mpf_clear (m_val
); }
600 /* See declaration above. */
606 mpz_import (m_val
, 1 /* count */, -1 /* order */,
607 sizeof (T
) /* size */, 0 /* endian (0 = native) */,
608 0 /* nails */, &src
/* op */);
609 if (std::is_signed
<T
>::value
&& src
< 0)
611 /* mpz_import does not handle the sign, so our value was imported
612 as an unsigned. Adjust that imported value so as to make it
613 the correct negative value. */
616 mpz_ui_pow_ui (neg_offset
.m_val
, 2, sizeof (T
) * HOST_CHAR_BIT
);
617 mpz_sub (m_val
, m_val
, neg_offset
.m_val
);
621 /* See declaration above. */
625 gdb_mpz::as_integer () const
629 this->export_bits ({(gdb_byte
*) &result
, sizeof (result
)},
630 0 /* endian (0 = native) */,
631 !std::is_signed
<T
>::value
/* unsigned_p */,
637 /* See declaration above. */
641 gdb_mpz::as_integer_truncate () const
645 this->export_bits ({(gdb_byte
*) &result
, sizeof (result
)},
646 0 /* endian (0 = native) */,
647 !std::is_signed
<T
>::value
/* unsigned_p */,