gmp-utils.h revision 1.1.1.1.4.2 1 1.1.1.1.4.2 perseant /* Miscellaneous routines making it easier to use GMP within GDB's framework.
2 1.1.1.1.4.2 perseant
3 1.1.1.1.4.2 perseant Copyright (C) 2019-2023 Free Software Foundation, Inc.
4 1.1.1.1.4.2 perseant
5 1.1.1.1.4.2 perseant This file is part of GDB.
6 1.1.1.1.4.2 perseant
7 1.1.1.1.4.2 perseant This program is free software; you can redistribute it and/or modify
8 1.1.1.1.4.2 perseant it under the terms of the GNU General Public License as published by
9 1.1.1.1.4.2 perseant the Free Software Foundation; either version 3 of the License, or
10 1.1.1.1.4.2 perseant (at your option) any later version.
11 1.1.1.1.4.2 perseant
12 1.1.1.1.4.2 perseant This program is distributed in the hope that it will be useful,
13 1.1.1.1.4.2 perseant but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1.1.1.4.2 perseant MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1.1.1.4.2 perseant GNU General Public License for more details.
16 1.1.1.1.4.2 perseant
17 1.1.1.1.4.2 perseant You should have received a copy of the GNU General Public License
18 1.1.1.1.4.2 perseant along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 1.1.1.1.4.2 perseant
20 1.1.1.1.4.2 perseant #ifndef GMP_UTILS_H
21 1.1.1.1.4.2 perseant #define GMP_UTILS_H
22 1.1.1.1.4.2 perseant
23 1.1.1.1.4.2 perseant #include "defs.h"
24 1.1.1.1.4.2 perseant
25 1.1.1.1.4.2 perseant /* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
26 1.1.1.1.4.2 perseant access to GMP's various formatting functions. */
27 1.1.1.1.4.2 perseant #include <stdio.h>
28 1.1.1.1.4.2 perseant #include <stdarg.h>
29 1.1.1.1.4.2 perseant #include <gmp.h>
30 1.1.1.1.4.2 perseant #include "gdbsupport/traits.h"
31 1.1.1.1.4.2 perseant
32 1.1.1.1.4.2 perseant /* Same as gmp_asprintf, but returning an std::string. */
33 1.1.1.1.4.2 perseant
34 1.1.1.1.4.2 perseant std::string gmp_string_printf (const char *fmt, ...);
35 1.1.1.1.4.2 perseant
36 1.1.1.1.4.2 perseant /* A class to make it easier to use GMP's mpz_t values within GDB. */
37 1.1.1.1.4.2 perseant
38 1.1.1.1.4.2 perseant struct gdb_mpz
39 1.1.1.1.4.2 perseant {
40 1.1.1.1.4.2 perseant mpz_t val;
41 1.1.1.1.4.2 perseant
42 1.1.1.1.4.2 perseant /* Constructors. */
43 1.1.1.1.4.2 perseant gdb_mpz () { mpz_init (val); }
44 1.1.1.1.4.2 perseant
45 1.1.1.1.4.2 perseant explicit gdb_mpz (const mpz_t &from_val)
46 1.1.1.1.4.2 perseant {
47 1.1.1.1.4.2 perseant mpz_init (val);
48 1.1.1.1.4.2 perseant mpz_set (val, from_val);
49 1.1.1.1.4.2 perseant }
50 1.1.1.1.4.2 perseant
51 1.1.1.1.4.2 perseant gdb_mpz (const gdb_mpz &from)
52 1.1.1.1.4.2 perseant {
53 1.1.1.1.4.2 perseant mpz_init (val);
54 1.1.1.1.4.2 perseant mpz_set (val, from.val);
55 1.1.1.1.4.2 perseant }
56 1.1.1.1.4.2 perseant
57 1.1.1.1.4.2 perseant /* Initialize using the given integral value.
58 1.1.1.1.4.2 perseant
59 1.1.1.1.4.2 perseant The main advantage of this method is that it handles both signed
60 1.1.1.1.4.2 perseant and unsigned types, with no size restriction. */
61 1.1.1.1.4.2 perseant template<typename T, typename = gdb::Requires<std::is_integral<T>>>
62 1.1.1.1.4.2 perseant explicit gdb_mpz (T src)
63 1.1.1.1.4.2 perseant {
64 1.1.1.1.4.2 perseant mpz_init (val);
65 1.1.1.1.4.2 perseant set (src);
66 1.1.1.1.4.2 perseant }
67 1.1.1.1.4.2 perseant
68 1.1.1.1.4.2 perseant explicit gdb_mpz (gdb_mpz &&from)
69 1.1.1.1.4.2 perseant {
70 1.1.1.1.4.2 perseant mpz_init (val);
71 1.1.1.1.4.2 perseant mpz_swap (val, from.val);
72 1.1.1.1.4.2 perseant }
73 1.1.1.1.4.2 perseant
74 1.1.1.1.4.2 perseant
75 1.1.1.1.4.2 perseant gdb_mpz &operator= (const gdb_mpz &from)
76 1.1.1.1.4.2 perseant {
77 1.1.1.1.4.2 perseant mpz_set (val, from.val);
78 1.1.1.1.4.2 perseant return *this;
79 1.1.1.1.4.2 perseant }
80 1.1.1.1.4.2 perseant
81 1.1.1.1.4.2 perseant gdb_mpz &operator= (gdb_mpz &&other)
82 1.1.1.1.4.2 perseant {
83 1.1.1.1.4.2 perseant mpz_swap (val, other.val);
84 1.1.1.1.4.2 perseant return *this;
85 1.1.1.1.4.2 perseant }
86 1.1.1.1.4.2 perseant
87 1.1.1.1.4.2 perseant template<typename T, typename = gdb::Requires<std::is_integral<T>>>
88 1.1.1.1.4.2 perseant gdb_mpz &operator= (T src)
89 1.1.1.1.4.2 perseant {
90 1.1.1.1.4.2 perseant set (src);
91 1.1.1.1.4.2 perseant return *this;
92 1.1.1.1.4.2 perseant }
93 1.1.1.1.4.2 perseant
94 1.1.1.1.4.2 perseant /* Convert VAL to an integer of the given type.
95 1.1.1.1.4.2 perseant
96 1.1.1.1.4.2 perseant The return type can signed or unsigned, with no size restriction. */
97 1.1.1.1.4.2 perseant template<typename T> T as_integer () const;
98 1.1.1.1.4.2 perseant
99 1.1.1.1.4.2 perseant /* Set VAL by importing the number stored in the byte array (BUF),
100 1.1.1.1.4.2 perseant using the given BYTE_ORDER. The size of the data to read is
101 1.1.1.1.4.2 perseant the byte array's size.
102 1.1.1.1.4.2 perseant
103 1.1.1.1.4.2 perseant UNSIGNED_P indicates whether the number has an unsigned type. */
104 1.1.1.1.4.2 perseant void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
105 1.1.1.1.4.2 perseant bool unsigned_p);
106 1.1.1.1.4.2 perseant
107 1.1.1.1.4.2 perseant /* Write VAL into BUF as a number whose byte size is the size of BUF,
108 1.1.1.1.4.2 perseant using the given BYTE_ORDER.
109 1.1.1.1.4.2 perseant
110 1.1.1.1.4.2 perseant UNSIGNED_P indicates whether the number has an unsigned type. */
111 1.1.1.1.4.2 perseant void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
112 1.1.1.1.4.2 perseant bool unsigned_p) const;
113 1.1.1.1.4.2 perseant
114 1.1.1.1.4.2 perseant /* Return a string containing VAL. */
115 1.1.1.1.4.2 perseant std::string str () const { return gmp_string_printf ("%Zd", val); }
116 1.1.1.1.4.2 perseant
117 1.1.1.1.4.2 perseant /* The destructor. */
118 1.1.1.1.4.2 perseant ~gdb_mpz () { mpz_clear (val); }
119 1.1.1.1.4.2 perseant
120 1.1.1.1.4.2 perseant private:
121 1.1.1.1.4.2 perseant
122 1.1.1.1.4.2 perseant /* Helper template for constructor and operator=. */
123 1.1.1.1.4.2 perseant template<typename T> void set (T src);
124 1.1.1.1.4.2 perseant
125 1.1.1.1.4.2 perseant /* Low-level function to export VAL into BUF as a number whose byte size
126 1.1.1.1.4.2 perseant is the size of BUF.
127 1.1.1.1.4.2 perseant
128 1.1.1.1.4.2 perseant If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
129 1.1.1.1.4.2 perseant Otherwise, export it as a signed value.
130 1.1.1.1.4.2 perseant
131 1.1.1.1.4.2 perseant The API is inspired from GMP's mpz_export, hence the naming and types
132 1.1.1.1.4.2 perseant of the following parameter:
133 1.1.1.1.4.2 perseant - ENDIAN should be:
134 1.1.1.1.4.2 perseant . 1 for most significant byte first; or
135 1.1.1.1.4.2 perseant . -1 for least significant byte first; or
136 1.1.1.1.4.2 perseant . 0 for native endianness.
137 1.1.1.1.4.2 perseant
138 1.1.1.1.4.2 perseant An error is raised if BUF is not large enough to contain the value
139 1.1.1.1.4.2 perseant being exported. */
140 1.1.1.1.4.2 perseant void safe_export (gdb::array_view<gdb_byte> buf,
141 1.1.1.1.4.2 perseant int endian, bool unsigned_p) const;
142 1.1.1.1.4.2 perseant };
143 1.1.1.1.4.2 perseant
144 1.1.1.1.4.2 perseant /* A class to make it easier to use GMP's mpq_t values within GDB. */
145 1.1.1.1.4.2 perseant
146 1.1.1.1.4.2 perseant struct gdb_mpq
147 1.1.1.1.4.2 perseant {
148 1.1.1.1.4.2 perseant mpq_t val;
149 1.1.1.1.4.2 perseant
150 1.1.1.1.4.2 perseant /* Constructors. */
151 1.1.1.1.4.2 perseant gdb_mpq () { mpq_init (val); }
152 1.1.1.1.4.2 perseant
153 1.1.1.1.4.2 perseant explicit gdb_mpq (const mpq_t &from_val)
154 1.1.1.1.4.2 perseant {
155 1.1.1.1.4.2 perseant mpq_init (val);
156 1.1.1.1.4.2 perseant mpq_set (val, from_val);
157 1.1.1.1.4.2 perseant }
158 1.1.1.1.4.2 perseant
159 1.1.1.1.4.2 perseant gdb_mpq (const gdb_mpq &from)
160 1.1.1.1.4.2 perseant {
161 1.1.1.1.4.2 perseant mpq_init (val);
162 1.1.1.1.4.2 perseant mpq_set (val, from.val);
163 1.1.1.1.4.2 perseant }
164 1.1.1.1.4.2 perseant
165 1.1.1.1.4.2 perseant explicit gdb_mpq (gdb_mpq &&from)
166 1.1.1.1.4.2 perseant {
167 1.1.1.1.4.2 perseant mpq_init (val);
168 1.1.1.1.4.2 perseant mpq_swap (val, from.val);
169 1.1.1.1.4.2 perseant }
170 1.1.1.1.4.2 perseant
171 1.1.1.1.4.2 perseant /* Copy assignment operator. */
172 1.1.1.1.4.2 perseant gdb_mpq &operator= (const gdb_mpq &from)
173 1.1.1.1.4.2 perseant {
174 1.1.1.1.4.2 perseant mpq_set (val, from.val);
175 1.1.1.1.4.2 perseant return *this;
176 1.1.1.1.4.2 perseant }
177 1.1.1.1.4.2 perseant
178 1.1.1.1.4.2 perseant gdb_mpq &operator= (gdb_mpq &&from)
179 1.1.1.1.4.2 perseant {
180 1.1.1.1.4.2 perseant mpq_swap (val, from.val);
181 1.1.1.1.4.2 perseant return *this;
182 1.1.1.1.4.2 perseant }
183 1.1.1.1.4.2 perseant
184 1.1.1.1.4.2 perseant /* Return a string representing VAL as "<numerator> / <denominator>". */
185 1.1.1.1.4.2 perseant std::string str () const { return gmp_string_printf ("%Qd", val); }
186 1.1.1.1.4.2 perseant
187 1.1.1.1.4.2 perseant /* Return VAL rounded to the nearest integer. */
188 1.1.1.1.4.2 perseant gdb_mpz get_rounded () const;
189 1.1.1.1.4.2 perseant
190 1.1.1.1.4.2 perseant /* Set VAL from the contents of the given byte array (BUF), which
191 1.1.1.1.4.2 perseant contains the unscaled value of a fixed point type object.
192 1.1.1.1.4.2 perseant The byte size of the data is the size of BUF.
193 1.1.1.1.4.2 perseant
194 1.1.1.1.4.2 perseant BYTE_ORDER provides the byte_order to use when reading the data.
195 1.1.1.1.4.2 perseant
196 1.1.1.1.4.2 perseant UNSIGNED_P indicates whether the number has an unsigned type.
197 1.1.1.1.4.2 perseant SCALING_FACTOR is the scaling factor to apply after having
198 1.1.1.1.4.2 perseant read the unscaled value from our buffer. */
199 1.1.1.1.4.2 perseant void read_fixed_point (gdb::array_view<const gdb_byte> buf,
200 1.1.1.1.4.2 perseant enum bfd_endian byte_order, bool unsigned_p,
201 1.1.1.1.4.2 perseant const gdb_mpq &scaling_factor);
202 1.1.1.1.4.2 perseant
203 1.1.1.1.4.2 perseant /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
204 1.1.1.1.4.2 perseant The size of BUF is used as the length to write the value into.
205 1.1.1.1.4.2 perseant
206 1.1.1.1.4.2 perseant UNSIGNED_P indicates whether the number has an unsigned type.
207 1.1.1.1.4.2 perseant SCALING_FACTOR is the scaling factor to apply before writing
208 1.1.1.1.4.2 perseant the unscaled value to our buffer. */
209 1.1.1.1.4.2 perseant void write_fixed_point (gdb::array_view<gdb_byte> buf,
210 1.1.1.1.4.2 perseant enum bfd_endian byte_order, bool unsigned_p,
211 1.1.1.1.4.2 perseant const gdb_mpq &scaling_factor) const;
212 1.1.1.1.4.2 perseant
213 1.1.1.1.4.2 perseant /* The destructor. */
214 1.1.1.1.4.2 perseant ~gdb_mpq () { mpq_clear (val); }
215 1.1.1.1.4.2 perseant };
216 1.1.1.1.4.2 perseant
217 1.1.1.1.4.2 perseant /* A class to make it easier to use GMP's mpf_t values within GDB.
218 1.1.1.1.4.2 perseant
219 1.1.1.1.4.2 perseant Should MPFR become a required dependency, we should probably
220 1.1.1.1.4.2 perseant drop this class in favor of using MPFR. */
221 1.1.1.1.4.2 perseant
222 1.1.1.1.4.2 perseant struct gdb_mpf
223 1.1.1.1.4.2 perseant {
224 1.1.1.1.4.2 perseant mpf_t val;
225 1.1.1.1.4.2 perseant
226 1.1.1.1.4.2 perseant /* Constructors. */
227 1.1.1.1.4.2 perseant gdb_mpf () { mpf_init (val); }
228 1.1.1.1.4.2 perseant
229 1.1.1.1.4.2 perseant DISABLE_COPY_AND_ASSIGN (gdb_mpf);
230 1.1.1.1.4.2 perseant
231 1.1.1.1.4.2 perseant /* Set VAL from the contents of the given buffer (BUF), which
232 1.1.1.1.4.2 perseant contains the unscaled value of a fixed point type object
233 1.1.1.1.4.2 perseant with the given size (LEN) and byte order (BYTE_ORDER).
234 1.1.1.1.4.2 perseant
235 1.1.1.1.4.2 perseant UNSIGNED_P indicates whether the number has an unsigned type.
236 1.1.1.1.4.2 perseant SCALING_FACTOR is the scaling factor to apply after having
237 1.1.1.1.4.2 perseant read the unscaled value from our buffer. */
238 1.1.1.1.4.2 perseant void read_fixed_point (gdb::array_view<const gdb_byte> buf,
239 1.1.1.1.4.2 perseant enum bfd_endian byte_order, bool unsigned_p,
240 1.1.1.1.4.2 perseant const gdb_mpq &scaling_factor)
241 1.1.1.1.4.2 perseant {
242 1.1.1.1.4.2 perseant gdb_mpq tmp_q;
243 1.1.1.1.4.2 perseant
244 1.1.1.1.4.2 perseant tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor);
245 1.1.1.1.4.2 perseant mpf_set_q (val, tmp_q.val);
246 1.1.1.1.4.2 perseant }
247 1.1.1.1.4.2 perseant
248 1.1.1.1.4.2 perseant /* The destructor. */
249 1.1.1.1.4.2 perseant ~gdb_mpf () { mpf_clear (val); }
250 1.1.1.1.4.2 perseant };
251 1.1.1.1.4.2 perseant
252 1.1.1.1.4.2 perseant /* See declaration above. */
253 1.1.1.1.4.2 perseant
254 1.1.1.1.4.2 perseant template<typename T>
255 1.1.1.1.4.2 perseant void
256 1.1.1.1.4.2 perseant gdb_mpz::set (T src)
257 1.1.1.1.4.2 perseant {
258 1.1.1.1.4.2 perseant mpz_import (val, 1 /* count */, -1 /* order */,
259 1.1.1.1.4.2 perseant sizeof (T) /* size */, 0 /* endian (0 = native) */,
260 1.1.1.1.4.2 perseant 0 /* nails */, &src /* op */);
261 1.1.1.1.4.2 perseant if (std::is_signed<T>::value && src < 0)
262 1.1.1.1.4.2 perseant {
263 1.1.1.1.4.2 perseant /* mpz_import does not handle the sign, so our value was imported
264 1.1.1.1.4.2 perseant as an unsigned. Adjust that imported value so as to make it
265 1.1.1.1.4.2 perseant the correct negative value. */
266 1.1.1.1.4.2 perseant gdb_mpz neg_offset;
267 1.1.1.1.4.2 perseant
268 1.1.1.1.4.2 perseant mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
269 1.1.1.1.4.2 perseant mpz_sub (val, val, neg_offset.val);
270 1.1.1.1.4.2 perseant }
271 1.1.1.1.4.2 perseant }
272 1.1.1.1.4.2 perseant
273 1.1.1.1.4.2 perseant /* See declaration above. */
274 1.1.1.1.4.2 perseant
275 1.1.1.1.4.2 perseant template<typename T>
276 1.1.1.1.4.2 perseant T
277 1.1.1.1.4.2 perseant gdb_mpz::as_integer () const
278 1.1.1.1.4.2 perseant {
279 1.1.1.1.4.2 perseant T result;
280 1.1.1.1.4.2 perseant
281 1.1.1.1.4.2 perseant this->safe_export ({(gdb_byte *) &result, sizeof (result)},
282 1.1.1.1.4.2 perseant 0 /* endian (0 = native) */,
283 1.1.1.1.4.2 perseant !std::is_signed<T>::value /* unsigned_p */);
284 1.1.1.1.4.2 perseant
285 1.1.1.1.4.2 perseant return result;
286 1.1.1.1.4.2 perseant }
287 1.1.1.1.4.2 perseant
288 1.1.1.1.4.2 perseant #endif
289