Home | History | Annotate | Line # | Download | only in gdb
gmp-utils.h revision 1.1.1.1
      1 /* Miscellaneous routines making it easier to use GMP within GDB's framework.
      2 
      3    Copyright (C) 2019-2023 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 "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 
     32 /* Same as gmp_asprintf, but returning an std::string.  */
     33 
     34 std::string gmp_string_printf (const char *fmt, ...);
     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 
     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.
    102 
    103      UNSIGNED_P indicates whether the number has an unsigned type.  */
    104   void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
    105 	     bool unsigned_p);
    106 
    107   /* Write VAL into BUF as a number whose byte size is the size of BUF,
    108      using the given BYTE_ORDER.
    109 
    110      UNSIGNED_P indicates whether the number has an unsigned type.  */
    111   void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
    112 	      bool unsigned_p) const;
    113 
    114   /* Return a string containing VAL.  */
    115   std::string str () const { return gmp_string_printf ("%Zd", val); }
    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);
    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;
    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>".  */
    185   std::string str () const { return gmp_string_printf ("%Qd", val); }
    186 
    187   /* Return VAL rounded to the nearest integer.  */
    188   gdb_mpz get_rounded () const;
    189 
    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.
    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.  */
    199   void read_fixed_point (gdb::array_view<const gdb_byte> buf,
    200 			 enum bfd_endian byte_order, bool unsigned_p,
    201 			 const gdb_mpq &scaling_factor);
    202 
    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.
    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.  */
    209   void write_fixed_point (gdb::array_view<gdb_byte> buf,
    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.  */
    238   void read_fixed_point (gdb::array_view<const gdb_byte> buf,
    239 			 enum bfd_endian byte_order, bool unsigned_p,
    240 			 const gdb_mpq &scaling_factor)
    241   {
    242     gdb_mpq tmp_q;
    243 
    244     tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor);
    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 {
    279   T result;
    280 
    281   this->safe_export ({(gdb_byte *) &result, sizeof (result)},
    282 		     0 /* endian (0 = native) */,
    283 		     !std::is_signed<T>::value /* unsigned_p */);
    284 
    285   return result;
    286 }
    287 
    288 #endif
    289