Home | History | Annotate | Line # | Download | only in gdb
      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