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