xref: /netbsd-src/external/gpl3/gdb/dist/gdb/gmp-utils.h (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
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