1 /* Miscellaneous routines making it easier to use GMP within GDB's framework.
3 Copyright (C) 2019-2020 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/>. */
25 /* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
26 access to GMP's various formatting functions. */
30 #include "gdbsupport/traits.h"
32 /* Same as gmp_asprintf, but returning an std::string. */
34 std::string
gmp_string_printf (const char *fmt
, ...);
36 /* A class to make it easier to use GMP's mpz_t values within GDB. */
43 gdb_mpz () { mpz_init (val
); }
45 explicit gdb_mpz (const mpz_t
&from_val
)
48 mpz_set (val
, from_val
);
51 gdb_mpz (const gdb_mpz
&from
)
54 mpz_set (val
, from
.val
);
57 /* Initialize using the given integral value.
59 The main advantage of this method is that it handles both signed
60 and unsigned types, with no size restriction. */
61 template<typename T
, typename
= gdb::Requires
<std::is_integral
<T
>>>
62 explicit gdb_mpz (T src
)
68 explicit gdb_mpz (gdb_mpz
&&from
)
71 mpz_swap (val
, from
.val
);
75 gdb_mpz
&operator= (const gdb_mpz
&from
)
77 mpz_set (val
, from
.val
);
81 gdb_mpz
&operator= (gdb_mpz
&&other
)
83 mpz_swap (val
, other
.val
);
87 template<typename T
, typename
= gdb::Requires
<std::is_integral
<T
>>>
88 gdb_mpz
&operator= (T src
)
94 /* Convert VAL to an integer of the given type.
96 The return type can signed or unsigned, with no size restriction. */
97 template<typename T
> T
as_integer () const;
99 /* Set VAL by importing the number stored in the byte array (BUF),
100 using the given BYTE_ORDER. The size of the data to read is
101 the byte array's size.
103 UNSIGNED_P indicates whether the number has an unsigned type. */
104 void read (gdb::array_view
<const gdb_byte
> buf
, enum bfd_endian byte_order
,
107 /* Write VAL into BUF as a number whose byte size is the size of BUF,
108 using the given BYTE_ORDER.
110 UNSIGNED_P indicates whether the number has an unsigned type. */
111 void write (gdb::array_view
<gdb_byte
> buf
, enum bfd_endian byte_order
,
112 bool unsigned_p
) const;
114 /* Return a string containing VAL. */
115 std::string
str () const { return gmp_string_printf ("%Zd", val
); }
117 /* The destructor. */
118 ~gdb_mpz () { mpz_clear (val
); }
122 /* Helper template for constructor and operator=. */
123 template<typename T
> void set (T src
);
126 /* A class to make it easier to use GMP's mpq_t values within GDB. */
133 gdb_mpq () { mpq_init (val
); }
135 explicit gdb_mpq (const mpq_t
&from_val
)
138 mpq_set (val
, from_val
);
141 gdb_mpq (const gdb_mpq
&from
)
144 mpq_set (val
, from
.val
);
147 explicit gdb_mpq (gdb_mpq
&&from
)
150 mpq_swap (val
, from
.val
);
153 /* Copy assignment operator. */
154 gdb_mpq
&operator= (const gdb_mpq
&from
)
156 mpq_set (val
, from
.val
);
160 gdb_mpq
&operator= (gdb_mpq
&&from
)
162 mpq_swap (val
, from
.val
);
166 /* Return a string representing VAL as "<numerator> / <denominator>". */
167 std::string
str () const { return gmp_string_printf ("%Qd", val
); }
169 /* Return VAL rounded to the nearest integer. */
170 gdb_mpz
get_rounded () const;
172 /* Set VAL from the contents of the given byte array (BUF), which
173 contains the unscaled value of a fixed point type object.
174 The byte size of the data is the size of BUF.
176 BYTE_ORDER provides the byte_order to use when reading the data.
178 UNSIGNED_P indicates whether the number has an unsigned type.
179 SCALING_FACTOR is the scaling factor to apply after having
180 read the unscaled value from our buffer. */
181 void read_fixed_point (gdb::array_view
<const gdb_byte
> buf
,
182 enum bfd_endian byte_order
, bool unsigned_p
,
183 const gdb_mpq
&scaling_factor
);
185 /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
186 The size of BUF is used as the length to write the value into.
188 UNSIGNED_P indicates whether the number has an unsigned type.
189 SCALING_FACTOR is the scaling factor to apply before writing
190 the unscaled value to our buffer. */
191 void write_fixed_point (gdb::array_view
<gdb_byte
> buf
,
192 enum bfd_endian byte_order
, bool unsigned_p
,
193 const gdb_mpq
&scaling_factor
) const;
195 /* The destructor. */
196 ~gdb_mpq () { mpq_clear (val
); }
199 /* A class to make it easier to use GMP's mpf_t values within GDB.
201 Should MPFR become a required dependency, we should probably
202 drop this class in favor of using MPFR. */
209 gdb_mpf () { mpf_init (val
); }
211 DISABLE_COPY_AND_ASSIGN (gdb_mpf
);
213 /* Set VAL from the contents of the given buffer (BUF), which
214 contains the unscaled value of a fixed point type object
215 with the given size (LEN) and byte order (BYTE_ORDER).
217 UNSIGNED_P indicates whether the number has an unsigned type.
218 SCALING_FACTOR is the scaling factor to apply after having
219 read the unscaled value from our buffer. */
220 void read_fixed_point (gdb::array_view
<const gdb_byte
> buf
,
221 enum bfd_endian byte_order
, bool unsigned_p
,
222 const gdb_mpq
&scaling_factor
)
226 tmp_q
.read_fixed_point (buf
, byte_order
, unsigned_p
, scaling_factor
);
227 mpf_set_q (val
, tmp_q
.val
);
230 /* The destructor. */
231 ~gdb_mpf () { mpf_clear (val
); }
234 /* See declaration above. */
240 mpz_import (val
, 1 /* count */, -1 /* order */,
241 sizeof (T
) /* size */, 0 /* endian (0 = native) */,
242 0 /* nails */, &src
/* op */);
243 if (std::is_signed
<T
>::value
&& src
< 0)
245 /* mpz_import does not handle the sign, so our value was imported
246 as an unsigned. Adjust that imported value so as to make it
247 the correct negative value. */
250 mpz_ui_pow_ui (neg_offset
.val
, 2, sizeof (T
) * HOST_CHAR_BIT
);
251 mpz_sub (val
, val
, neg_offset
.val
);
255 /* See declaration above. */
259 gdb_mpz::as_integer () const
261 /* Initialize RESULT, because mpz_export only write the minimum
262 number of bytes, including none if our value is zero! */
265 gdb_mpz
exported_val (val
);
266 if (std::is_signed
<T
>::value
&& mpz_cmp_ui (val
, 0) < 0)
268 /* We want to use mpz_export to set the return value, but
269 this function does not handle the sign. So give exported_val
270 a value which is at the same time positive, and has the same
271 bit representation as our negative value. */
274 mpz_ui_pow_ui (neg_offset
.val
, 2, sizeof (T
) * HOST_CHAR_BIT
);
275 mpz_add (exported_val
.val
, exported_val
.val
, neg_offset
.val
);
278 mpz_export (&result
, NULL
/* count */, -1 /* order */,
279 sizeof (T
) /* size */, 0 /* endian (0 = native) */,
280 0 /* nails */, exported_val
.val
);