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