Commit | Line | Data |
---|---|---|
b34c74ab JB |
1 | /* Miscellaneous routines making it easier to use GMP within GDB's framework. |
2 | ||
3666a048 | 3 | Copyright (C) 2019-2021 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 | 34 | std::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 | ||
38 | struct 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 | ||
120 | private: | |
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 | ||
146 | struct 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 | ||
222 | struct 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 | ||
254 | template<typename T> | |
255 | void | |
256 | gdb_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 | ||
275 | template<typename T> | |
276 | T | |
277 | gdb_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 |