gmp-utils.h revision 1.1.1.2 1 /* Miscellaneous routines making it easier to use GMP within GDB's framework.
2
3 Copyright (C) 2019-2024 Free Software Foundation, Inc.
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 <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
24 access to GMP's various formatting functions. */
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <gmp.h>
28 #include "gdbsupport/traits.h"
29
30 /* Same as gmp_asprintf, but returning an std::string. */
31
32 std::string gmp_string_printf (const char *fmt, ...);
33
34 struct gdb_mpq;
35 struct gdb_mpf;
36
37 /* A class to make it easier to use GMP's mpz_t values within GDB. */
38
39 struct gdb_mpz
40 {
41 /* Constructors. */
42 gdb_mpz () { mpz_init (m_val); }
43
44 explicit gdb_mpz (const mpz_t &from_val)
45 {
46 mpz_init (m_val);
47 mpz_set (m_val, from_val);
48 }
49
50 gdb_mpz (const gdb_mpz &from)
51 {
52 mpz_init (m_val);
53 mpz_set (m_val, from.m_val);
54 }
55
56 /* Initialize using the given integral value.
57
58 The main advantage of this method is that it handles both signed
59 and unsigned types, with no size restriction. */
60 template<typename T, typename = gdb::Requires<std::is_integral<T>>>
61 explicit gdb_mpz (T src)
62 {
63 mpz_init (m_val);
64 set (src);
65 }
66
67 explicit gdb_mpz (gdb_mpz &&from)
68 {
69 mpz_init (m_val);
70 mpz_swap (m_val, from.m_val);
71 }
72
73
74 gdb_mpz &operator= (const gdb_mpz &from)
75 {
76 mpz_set (m_val, from.m_val);
77 return *this;
78 }
79
80 gdb_mpz &operator= (gdb_mpz &&other)
81 {
82 mpz_swap (m_val, other.m_val);
83 return *this;
84 }
85
86 template<typename T, typename = gdb::Requires<std::is_integral<T>>>
87 gdb_mpz &operator= (T src)
88 {
89 set (src);
90 return *this;
91 }
92
93 gdb_mpz &operator= (bool src)
94 {
95 mpz_set_ui (m_val, (unsigned long) src);
96 return *this;
97 }
98
99 /* Initialize this value from a string and a base. Returns true if
100 the string was parsed successfully, false otherwise. */
101 bool set (const char *str, int base)
102 {
103 return mpz_set_str (m_val, str, base) != -1;
104 }
105
106 /* Return a new value that is BASE**EXP. */
107 static gdb_mpz pow (unsigned long base, unsigned long exp)
108 {
109 gdb_mpz result;
110 mpz_ui_pow_ui (result.m_val, base, exp);
111 return result;
112 }
113
114 /* Return a new value that is this value raised to EXP. */
115 gdb_mpz pow (unsigned long exp) const
116 {
117 gdb_mpz result;
118 mpz_pow_ui (result.m_val, m_val, exp);
119 return result;
120 }
121
122 /* Convert this value to an integer of the given type.
123
124 The return type can signed or unsigned, with no size restriction. */
125 template<typename T> T as_integer () const;
126
127 /* Convert this value to an integer of the given type. If this
128 value is too large, it is truncated.
129
130 The return type can signed or unsigned, with no size restriction. */
131 template<typename T> T as_integer_truncate () const;
132
133 /* Set VAL by importing the number stored in the byte array (BUF),
134 using the given BYTE_ORDER. The size of the data to read is
135 the byte array's size.
136
137 UNSIGNED_P indicates whether the number has an unsigned type. */
138 void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
139 bool unsigned_p);
140
141 /* Write VAL into BUF as a number whose byte size is the size of BUF,
142 using the given BYTE_ORDER.
143
144 UNSIGNED_P indicates whether the number has an unsigned type. */
145 void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
146 bool unsigned_p) const
147 {
148 export_bits (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
149 unsigned_p, true /* safe */);
150 }
151
152 /* Like write, but truncates the value to the desired number of
153 bytes. */
154 void truncate (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
155 bool unsigned_p) const
156 {
157 export_bits (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
158 unsigned_p, false /* safe */);
159 }
160
161 /* Return a string containing VAL. */
162 std::string str () const { return gmp_string_printf ("%Zd", m_val); }
163
164 /* The destructor. */
165 ~gdb_mpz () { mpz_clear (m_val); }
166
167 /* Negate this value in place. */
168 void negate ()
169 {
170 mpz_neg (m_val, m_val);
171 }
172
173 /* Take the one's complement in place. */
174 void complement ()
175 { mpz_com (m_val, m_val); }
176
177 /* Mask this value to N bits, in place. */
178 void mask (unsigned n)
179 { mpz_tdiv_r_2exp (m_val, m_val, n); }
180
181 /* Return the sign of this value. This returns -1 for a negative
182 value, 0 if the value is 0, and 1 for a positive value. */
183 int sgn () const
184 { return mpz_sgn (m_val); }
185
186 explicit operator bool () const
187 { return sgn () != 0; }
188
189 gdb_mpz &operator*= (long other)
190 {
191 mpz_mul_si (m_val, m_val, other);
192 return *this;
193 }
194
195 gdb_mpz operator* (const gdb_mpz &other) const
196 {
197 gdb_mpz result;
198 mpz_mul (result.m_val, m_val, other.m_val);
199 return result;
200 }
201
202 gdb_mpz operator/ (const gdb_mpz &other) const
203 {
204 gdb_mpz result;
205 mpz_tdiv_q (result.m_val, m_val, other.m_val);
206 return result;
207 }
208
209 gdb_mpz operator% (const gdb_mpz &other) const
210 {
211 gdb_mpz result;
212 mpz_tdiv_r (result.m_val, m_val, other.m_val);
213 return result;
214 }
215
216 gdb_mpz &operator+= (unsigned long other)
217 {
218 mpz_add_ui (m_val, m_val, other);
219 return *this;
220 }
221
222 gdb_mpz &operator+= (const gdb_mpz &other)
223 {
224 mpz_add (m_val, m_val, other.m_val);
225 return *this;
226 }
227
228 gdb_mpz operator+ (const gdb_mpz &other) const
229 {
230 gdb_mpz result;
231 mpz_add (result.m_val, m_val, other.m_val);
232 return result;
233 }
234
235 gdb_mpz &operator-= (unsigned long other)
236 {
237 mpz_sub_ui (m_val, m_val, other);
238 return *this;
239 }
240
241 gdb_mpz &operator-= (const gdb_mpz &other)
242 {
243 mpz_sub (m_val, m_val, other.m_val);
244 return *this;
245 }
246
247 gdb_mpz operator- (const gdb_mpz &other) const
248 {
249 gdb_mpz result;
250 mpz_sub (result.m_val, m_val, other.m_val);
251 return result;
252 }
253
254 gdb_mpz operator- () const
255 {
256 gdb_mpz result;
257 mpz_neg (result.m_val, m_val);
258 return result;
259 }
260
261 gdb_mpz &operator<<= (unsigned long nbits)
262 {
263 mpz_mul_2exp (m_val, m_val, nbits);
264 return *this;
265 }
266
267 gdb_mpz operator<< (unsigned long nbits) const &
268 {
269 gdb_mpz result;
270 mpz_mul_2exp (result.m_val, m_val, nbits);
271 return result;
272 }
273
274 gdb_mpz operator<< (unsigned long nbits) &&
275 {
276 mpz_mul_2exp (m_val, m_val, nbits);
277 return *this;
278 }
279
280 gdb_mpz operator>> (unsigned long nbits) const
281 {
282 gdb_mpz result;
283 mpz_fdiv_q_2exp (result.m_val, m_val, nbits);
284 return result;
285 }
286
287 gdb_mpz &operator>>= (unsigned long nbits)
288 {
289 mpz_fdiv_q_2exp (m_val, m_val, nbits);
290 return *this;
291 }
292
293 gdb_mpz operator& (const gdb_mpz &other) const
294 {
295 gdb_mpz result;
296 mpz_and (result.m_val, m_val, other.m_val);
297 return result;
298 }
299
300 gdb_mpz operator| (const gdb_mpz &other) const
301 {
302 gdb_mpz result;
303 mpz_ior (result.m_val, m_val, other.m_val);
304 return result;
305 }
306
307 gdb_mpz operator^ (const gdb_mpz &other) const
308 {
309 gdb_mpz result;
310 mpz_xor (result.m_val, m_val, other.m_val);
311 return result;
312 }
313
314 bool operator> (const gdb_mpz &other) const
315 {
316 return mpz_cmp (m_val, other.m_val) > 0;
317 }
318
319 bool operator>= (const gdb_mpz &other) const
320 {
321 return mpz_cmp (m_val, other.m_val) >= 0;
322 }
323
324 bool operator< (const gdb_mpz &other) const
325 {
326 return mpz_cmp (m_val, other.m_val) < 0;
327 }
328
329 bool operator<= (const gdb_mpz &other) const
330 {
331 return mpz_cmp (m_val, other.m_val) <= 0;
332 }
333
334 bool operator< (long other) const
335 {
336 return mpz_cmp_si (m_val, other) < 0;
337 }
338
339 /* We want an operator== that can handle all integer types. For
340 types that are 'long' or narrower, we can use a GMP function and
341 avoid boxing the RHS. But, because overloading based on integer
342 type is a pain in C++, we accept all such types here and check
343 the size in the body. */
344 template<typename T, typename = gdb::Requires<std::is_integral<T>>>
345 bool operator== (T other) const
346 {
347 if (std::is_signed<T>::value)
348 {
349 if (sizeof (T) <= sizeof (long))
350 return mpz_cmp_si (m_val, other) == 0;
351 }
352 else
353 {
354 if (sizeof (T) <= sizeof (unsigned long))
355 return mpz_cmp_ui (m_val, other) == 0;
356 }
357 return *this == gdb_mpz (other);
358 }
359
360 bool operator== (const gdb_mpz &other) const
361 {
362 return mpz_cmp (m_val, other.m_val) == 0;
363 }
364
365 bool operator!= (const gdb_mpz &other) const
366 {
367 return mpz_cmp (m_val, other.m_val) != 0;
368 }
369
370 private:
371
372 /* Helper template for constructor and operator=. */
373 template<typename T> void set (T src);
374
375 /* Low-level function to export VAL into BUF as a number whose byte size
376 is the size of BUF.
377
378 If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
379 Otherwise, export it as a signed value.
380
381 The API is inspired from GMP's mpz_export, hence the naming and types
382 of the following parameter:
383 - ENDIAN should be:
384 . 1 for most significant byte first; or
385 . -1 for least significant byte first; or
386 . 0 for native endianness.
387
388 If SAFE is true, an error is raised if BUF is not large enough to
389 contain the value being exported. If SAFE is false, the value is
390 truncated to fit in BUF. */
391 void export_bits (gdb::array_view<gdb_byte> buf, int endian, bool unsigned_p,
392 bool safe) const;
393
394 friend struct gdb_mpq;
395 friend struct gdb_mpf;
396
397 mpz_t m_val;
398 };
399
400 /* A class to make it easier to use GMP's mpq_t values within GDB. */
401
402 struct gdb_mpq
403 {
404 /* Constructors. */
405 gdb_mpq () { mpq_init (m_val); }
406
407 explicit gdb_mpq (const mpq_t &from_val)
408 {
409 mpq_init (m_val);
410 mpq_set (m_val, from_val);
411 }
412
413 gdb_mpq (const gdb_mpq &from)
414 {
415 mpq_init (m_val);
416 mpq_set (m_val, from.m_val);
417 }
418
419 explicit gdb_mpq (gdb_mpq &&from)
420 {
421 mpq_init (m_val);
422 mpq_swap (m_val, from.m_val);
423 }
424
425 gdb_mpq (const gdb_mpz &num, const gdb_mpz &denom)
426 {
427 mpq_init (m_val);
428 mpz_set (mpq_numref (m_val), num.m_val);
429 mpz_set (mpq_denref (m_val), denom.m_val);
430 mpq_canonicalize (m_val);
431 }
432
433 gdb_mpq (long num, long denom)
434 {
435 mpq_init (m_val);
436 mpq_set_si (m_val, num, denom);
437 mpq_canonicalize (m_val);
438 }
439
440 /* Copy assignment operator. */
441 gdb_mpq &operator= (const gdb_mpq &from)
442 {
443 mpq_set (m_val, from.m_val);
444 return *this;
445 }
446
447 gdb_mpq &operator= (gdb_mpq &&from)
448 {
449 mpq_swap (m_val, from.m_val);
450 return *this;
451 }
452
453 gdb_mpq &operator= (const gdb_mpz &from)
454 {
455 mpq_set_z (m_val, from.m_val);
456 return *this;
457 }
458
459 gdb_mpq &operator= (double d)
460 {
461 mpq_set_d (m_val, d);
462 return *this;
463 }
464
465 /* Return the sign of this value. This returns -1 for a negative
466 value, 0 if the value is 0, and 1 for a positive value. */
467 int sgn () const
468 { return mpq_sgn (m_val); }
469
470 gdb_mpq operator+ (const gdb_mpq &other) const
471 {
472 gdb_mpq result;
473 mpq_add (result.m_val, m_val, other.m_val);
474 return result;
475 }
476
477 gdb_mpq operator- (const gdb_mpq &other) const
478 {
479 gdb_mpq result;
480 mpq_sub (result.m_val, m_val, other.m_val);
481 return result;
482 }
483
484 gdb_mpq operator* (const gdb_mpq &other) const
485 {
486 gdb_mpq result;
487 mpq_mul (result.m_val, m_val, other.m_val);
488 return result;
489 }
490
491 gdb_mpq operator/ (const gdb_mpq &other) const
492 {
493 gdb_mpq result;
494 mpq_div (result.m_val, m_val, other.m_val);
495 return result;
496 }
497
498 gdb_mpq &operator*= (const gdb_mpq &other)
499 {
500 mpq_mul (m_val, m_val, other.m_val);
501 return *this;
502 }
503
504 gdb_mpq &operator/= (const gdb_mpq &other)
505 {
506 mpq_div (m_val, m_val, other.m_val);
507 return *this;
508 }
509
510 bool operator== (const gdb_mpq &other) const
511 {
512 return mpq_cmp (m_val, other.m_val) == 0;
513 }
514
515 bool operator< (const gdb_mpq &other) const
516 {
517 return mpq_cmp (m_val, other.m_val) < 0;
518 }
519
520 /* Return a string representing VAL as "<numerator> / <denominator>". */
521 std::string str () const { return gmp_string_printf ("%Qd", m_val); }
522
523 /* Return VAL rounded to the nearest integer. */
524 gdb_mpz get_rounded () const;
525
526 /* Return this value as an integer, rounded toward zero. */
527 gdb_mpz as_integer () const
528 {
529 gdb_mpz result;
530 mpz_tdiv_q (result.m_val, mpq_numref (m_val), mpq_denref (m_val));
531 return result;
532 }
533
534 /* Return this value converted to a host double. */
535 double as_double () const
536 { return mpq_get_d (m_val); }
537
538 /* Set VAL from the contents of the given byte array (BUF), which
539 contains the unscaled value of a fixed point type object.
540 The byte size of the data is the size of BUF.
541
542 BYTE_ORDER provides the byte_order to use when reading the data.
543
544 UNSIGNED_P indicates whether the number has an unsigned type.
545 SCALING_FACTOR is the scaling factor to apply after having
546 read the unscaled value from our buffer. */
547 void read_fixed_point (gdb::array_view<const gdb_byte> buf,
548 enum bfd_endian byte_order, bool unsigned_p,
549 const gdb_mpq &scaling_factor);
550
551 /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
552 The size of BUF is used as the length to write the value into.
553
554 UNSIGNED_P indicates whether the number has an unsigned type.
555 SCALING_FACTOR is the scaling factor to apply before writing
556 the unscaled value to our buffer. */
557 void write_fixed_point (gdb::array_view<gdb_byte> buf,
558 enum bfd_endian byte_order, bool unsigned_p,
559 const gdb_mpq &scaling_factor) const;
560
561 /* The destructor. */
562 ~gdb_mpq () { mpq_clear (m_val); }
563
564 private:
565
566 friend struct gdb_mpf;
567
568 mpq_t m_val;
569 };
570
571 /* A class to make it easier to use GMP's mpf_t values within GDB.
572
573 Should MPFR become a required dependency, we should probably
574 drop this class in favor of using MPFR. */
575
576 struct gdb_mpf
577 {
578 /* Constructors. */
579 gdb_mpf () { mpf_init (m_val); }
580
581 DISABLE_COPY_AND_ASSIGN (gdb_mpf);
582
583 /* Set VAL from the contents of the given buffer (BUF), which
584 contains the unscaled value of a fixed point type object
585 with the given size (LEN) and byte order (BYTE_ORDER).
586
587 UNSIGNED_P indicates whether the number has an unsigned type.
588 SCALING_FACTOR is the scaling factor to apply after having
589 read the unscaled value from our buffer. */
590 void read_fixed_point (gdb::array_view<const gdb_byte> buf,
591 enum bfd_endian byte_order, bool unsigned_p,
592 const gdb_mpq &scaling_factor)
593 {
594 gdb_mpq tmp_q;
595
596 tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor);
597 mpf_set_q (m_val, tmp_q.m_val);
598 }
599
600 /* Convert this value to a string. FMT is the format to use, and
601 should have a single '%' substitution. */
602 std::string str (const char *fmt) const
603 { return gmp_string_printf (fmt, m_val); }
604
605 /* The destructor. */
606 ~gdb_mpf () { mpf_clear (m_val); }
607
608 private:
609
610 mpf_t m_val;
611 };
612
613 /* See declaration above. */
614
615 template<typename T>
616 void
617 gdb_mpz::set (T src)
618 {
619 mpz_import (m_val, 1 /* count */, -1 /* order */,
620 sizeof (T) /* size */, 0 /* endian (0 = native) */,
621 0 /* nails */, &src /* op */);
622 if (std::is_signed<T>::value && src < 0)
623 {
624 /* mpz_import does not handle the sign, so our value was imported
625 as an unsigned. Adjust that imported value so as to make it
626 the correct negative value. */
627 gdb_mpz neg_offset;
628
629 mpz_ui_pow_ui (neg_offset.m_val, 2, sizeof (T) * HOST_CHAR_BIT);
630 mpz_sub (m_val, m_val, neg_offset.m_val);
631 }
632 }
633
634 /* See declaration above. */
635
636 template<typename T>
637 T
638 gdb_mpz::as_integer () const
639 {
640 T result;
641
642 this->export_bits ({(gdb_byte *) &result, sizeof (result)},
643 0 /* endian (0 = native) */,
644 !std::is_signed<T>::value /* unsigned_p */,
645 true /* safe */);
646
647 return result;
648 }
649
650 /* See declaration above. */
651
652 template<typename T>
653 T
654 gdb_mpz::as_integer_truncate () const
655 {
656 T result;
657
658 this->export_bits ({(gdb_byte *) &result, sizeof (result)},
659 0 /* endian (0 = native) */,
660 !std::is_signed<T>::value /* unsigned_p */,
661 false /* safe */);
662
663 return result;
664 }
665
666 #endif
667