Home | History | Annotate | Line # | Download | only in gdb
gmp-utils.h revision 1.1.1.1
      1  1.1  christos /* Miscellaneous routines making it easier to use GMP within GDB's framework.
      2  1.1  christos 
      3  1.1  christos    Copyright (C) 2019-2023 Free Software Foundation, Inc.
      4  1.1  christos 
      5  1.1  christos    This file is part of GDB.
      6  1.1  christos 
      7  1.1  christos    This program is free software; you can redistribute it and/or modify
      8  1.1  christos    it under the terms of the GNU General Public License as published by
      9  1.1  christos    the Free Software Foundation; either version 3 of the License, or
     10  1.1  christos    (at your option) any later version.
     11  1.1  christos 
     12  1.1  christos    This program is distributed in the hope that it will be useful,
     13  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  1.1  christos    GNU General Public License for more details.
     16  1.1  christos 
     17  1.1  christos    You should have received a copy of the GNU General Public License
     18  1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19  1.1  christos 
     20  1.1  christos #ifndef GMP_UTILS_H
     21  1.1  christos #define GMP_UTILS_H
     22  1.1  christos 
     23  1.1  christos #include "defs.h"
     24  1.1  christos 
     25  1.1  christos /* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
     26  1.1  christos    access to GMP's various formatting functions.  */
     27  1.1  christos #include <stdio.h>
     28  1.1  christos #include <stdarg.h>
     29  1.1  christos #include <gmp.h>
     30  1.1  christos #include "gdbsupport/traits.h"
     31  1.1  christos 
     32  1.1  christos /* Same as gmp_asprintf, but returning an std::string.  */
     33  1.1  christos 
     34  1.1  christos std::string gmp_string_printf (const char *fmt, ...);
     35  1.1  christos 
     36  1.1  christos /* A class to make it easier to use GMP's mpz_t values within GDB.  */
     37  1.1  christos 
     38  1.1  christos struct gdb_mpz
     39  1.1  christos {
     40  1.1  christos   mpz_t val;
     41  1.1  christos 
     42  1.1  christos   /* Constructors.  */
     43  1.1  christos   gdb_mpz () { mpz_init (val); }
     44  1.1  christos 
     45  1.1  christos   explicit gdb_mpz (const mpz_t &from_val)
     46  1.1  christos   {
     47  1.1  christos     mpz_init (val);
     48  1.1  christos     mpz_set (val, from_val);
     49  1.1  christos   }
     50  1.1  christos 
     51  1.1  christos   gdb_mpz (const gdb_mpz &from)
     52  1.1  christos   {
     53  1.1  christos     mpz_init (val);
     54  1.1  christos     mpz_set (val, from.val);
     55  1.1  christos   }
     56  1.1  christos 
     57  1.1  christos   /* Initialize using the given integral value.
     58  1.1  christos 
     59  1.1  christos      The main advantage of this method is that it handles both signed
     60  1.1  christos      and unsigned types, with no size restriction.  */
     61  1.1  christos   template<typename T, typename = gdb::Requires<std::is_integral<T>>>
     62  1.1  christos   explicit gdb_mpz (T src)
     63  1.1  christos   {
     64  1.1  christos     mpz_init (val);
     65  1.1  christos     set (src);
     66  1.1  christos   }
     67  1.1  christos 
     68  1.1  christos   explicit gdb_mpz (gdb_mpz &&from)
     69  1.1  christos   {
     70  1.1  christos     mpz_init (val);
     71  1.1  christos     mpz_swap (val, from.val);
     72  1.1  christos   }
     73  1.1  christos 
     74  1.1  christos 
     75  1.1  christos   gdb_mpz &operator= (const gdb_mpz &from)
     76  1.1  christos   {
     77  1.1  christos     mpz_set (val, from.val);
     78  1.1  christos     return *this;
     79  1.1  christos   }
     80  1.1  christos 
     81  1.1  christos   gdb_mpz &operator= (gdb_mpz &&other)
     82  1.1  christos   {
     83  1.1  christos     mpz_swap (val, other.val);
     84  1.1  christos     return *this;
     85  1.1  christos   }
     86  1.1  christos 
     87  1.1  christos   template<typename T, typename = gdb::Requires<std::is_integral<T>>>
     88  1.1  christos   gdb_mpz &operator= (T src)
     89  1.1  christos   {
     90  1.1  christos     set (src);
     91  1.1  christos     return *this;
     92  1.1  christos   }
     93  1.1  christos 
     94  1.1  christos   /* Convert VAL to an integer of the given type.
     95  1.1  christos 
     96  1.1  christos      The return type can signed or unsigned, with no size restriction.  */
     97  1.1  christos   template<typename T> T as_integer () const;
     98  1.1  christos 
     99  1.1  christos   /* Set VAL by importing the number stored in the byte array (BUF),
    100  1.1  christos      using the given BYTE_ORDER.  The size of the data to read is
    101  1.1  christos      the byte array's size.
    102  1.1  christos 
    103  1.1  christos      UNSIGNED_P indicates whether the number has an unsigned type.  */
    104  1.1  christos   void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
    105  1.1  christos 	     bool unsigned_p);
    106  1.1  christos 
    107  1.1  christos   /* Write VAL into BUF as a number whose byte size is the size of BUF,
    108  1.1  christos      using the given BYTE_ORDER.
    109  1.1  christos 
    110  1.1  christos      UNSIGNED_P indicates whether the number has an unsigned type.  */
    111  1.1  christos   void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
    112  1.1  christos 	      bool unsigned_p) const;
    113  1.1  christos 
    114  1.1  christos   /* Return a string containing VAL.  */
    115  1.1  christos   std::string str () const { return gmp_string_printf ("%Zd", val); }
    116  1.1  christos 
    117  1.1  christos   /* The destructor.  */
    118  1.1  christos   ~gdb_mpz () { mpz_clear (val); }
    119  1.1  christos 
    120  1.1  christos private:
    121  1.1  christos 
    122  1.1  christos   /* Helper template for constructor and operator=.  */
    123  1.1  christos   template<typename T> void set (T src);
    124  1.1  christos 
    125  1.1  christos   /* Low-level function to export VAL into BUF as a number whose byte size
    126  1.1  christos      is the size of BUF.
    127  1.1  christos 
    128  1.1  christos      If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
    129  1.1  christos      Otherwise, export it as a signed value.
    130  1.1  christos 
    131  1.1  christos      The API is inspired from GMP's mpz_export, hence the naming and types
    132  1.1  christos      of the following parameter:
    133  1.1  christos        - ENDIAN should be:
    134  1.1  christos            . 1 for most significant byte first; or
    135  1.1  christos 	   . -1 for least significant byte first; or
    136  1.1  christos 	   . 0 for native endianness.
    137  1.1  christos 
    138  1.1  christos     An error is raised if BUF is not large enough to contain the value
    139  1.1  christos     being exported.  */
    140  1.1  christos   void safe_export (gdb::array_view<gdb_byte> buf,
    141  1.1  christos 		    int endian, bool unsigned_p) const;
    142  1.1  christos };
    143  1.1  christos 
    144  1.1  christos /* A class to make it easier to use GMP's mpq_t values within GDB.  */
    145  1.1  christos 
    146  1.1  christos struct gdb_mpq
    147  1.1  christos {
    148  1.1  christos   mpq_t val;
    149  1.1  christos 
    150  1.1  christos   /* Constructors.  */
    151  1.1  christos   gdb_mpq () { mpq_init (val); }
    152  1.1  christos 
    153  1.1  christos   explicit gdb_mpq (const mpq_t &from_val)
    154  1.1  christos   {
    155  1.1  christos     mpq_init (val);
    156  1.1  christos     mpq_set (val, from_val);
    157  1.1  christos   }
    158  1.1  christos 
    159  1.1  christos   gdb_mpq (const gdb_mpq &from)
    160  1.1  christos   {
    161  1.1  christos     mpq_init (val);
    162  1.1  christos     mpq_set (val, from.val);
    163  1.1  christos   }
    164  1.1  christos 
    165  1.1  christos   explicit gdb_mpq (gdb_mpq &&from)
    166  1.1  christos   {
    167  1.1  christos     mpq_init (val);
    168  1.1  christos     mpq_swap (val, from.val);
    169  1.1  christos   }
    170  1.1  christos 
    171  1.1  christos   /* Copy assignment operator.  */
    172  1.1  christos   gdb_mpq &operator= (const gdb_mpq &from)
    173  1.1  christos   {
    174  1.1  christos     mpq_set (val, from.val);
    175  1.1  christos     return *this;
    176  1.1  christos   }
    177  1.1  christos 
    178  1.1  christos   gdb_mpq &operator= (gdb_mpq &&from)
    179  1.1  christos   {
    180  1.1  christos     mpq_swap (val, from.val);
    181  1.1  christos     return *this;
    182  1.1  christos   }
    183  1.1  christos 
    184  1.1  christos   /* Return a string representing VAL as "<numerator> / <denominator>".  */
    185  1.1  christos   std::string str () const { return gmp_string_printf ("%Qd", val); }
    186  1.1  christos 
    187  1.1  christos   /* Return VAL rounded to the nearest integer.  */
    188  1.1  christos   gdb_mpz get_rounded () const;
    189  1.1  christos 
    190  1.1  christos   /* Set VAL from the contents of the given byte array (BUF), which
    191  1.1  christos      contains the unscaled value of a fixed point type object.
    192  1.1  christos      The byte size of the data is the size of BUF.
    193  1.1  christos 
    194  1.1  christos      BYTE_ORDER provides the byte_order to use when reading the data.
    195  1.1  christos 
    196  1.1  christos      UNSIGNED_P indicates whether the number has an unsigned type.
    197  1.1  christos      SCALING_FACTOR is the scaling factor to apply after having
    198  1.1  christos      read the unscaled value from our buffer.  */
    199  1.1  christos   void read_fixed_point (gdb::array_view<const gdb_byte> buf,
    200  1.1  christos 			 enum bfd_endian byte_order, bool unsigned_p,
    201  1.1  christos 			 const gdb_mpq &scaling_factor);
    202  1.1  christos 
    203  1.1  christos   /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
    204  1.1  christos      The size of BUF is used as the length to write the value into.
    205  1.1  christos 
    206  1.1  christos      UNSIGNED_P indicates whether the number has an unsigned type.
    207  1.1  christos      SCALING_FACTOR is the scaling factor to apply before writing
    208  1.1  christos      the unscaled value to our buffer.  */
    209  1.1  christos   void write_fixed_point (gdb::array_view<gdb_byte> buf,
    210  1.1  christos 			  enum bfd_endian byte_order, bool unsigned_p,
    211  1.1  christos 			  const gdb_mpq &scaling_factor) const;
    212  1.1  christos 
    213  1.1  christos   /* The destructor.  */
    214  1.1  christos   ~gdb_mpq () { mpq_clear (val); }
    215  1.1  christos };
    216  1.1  christos 
    217  1.1  christos /* A class to make it easier to use GMP's mpf_t values within GDB.
    218  1.1  christos 
    219  1.1  christos    Should MPFR become a required dependency, we should probably
    220  1.1  christos    drop this class in favor of using MPFR.  */
    221  1.1  christos 
    222  1.1  christos struct gdb_mpf
    223  1.1  christos {
    224  1.1  christos   mpf_t val;
    225  1.1  christos 
    226  1.1  christos   /* Constructors.  */
    227  1.1  christos   gdb_mpf () { mpf_init (val); }
    228  1.1  christos 
    229  1.1  christos   DISABLE_COPY_AND_ASSIGN (gdb_mpf);
    230  1.1  christos 
    231  1.1  christos   /* Set VAL from the contents of the given buffer (BUF), which
    232  1.1  christos      contains the unscaled value of a fixed point type object
    233  1.1  christos      with the given size (LEN) and byte order (BYTE_ORDER).
    234  1.1  christos 
    235  1.1  christos      UNSIGNED_P indicates whether the number has an unsigned type.
    236  1.1  christos      SCALING_FACTOR is the scaling factor to apply after having
    237  1.1  christos      read the unscaled value from our buffer.  */
    238  1.1  christos   void read_fixed_point (gdb::array_view<const gdb_byte> buf,
    239  1.1  christos 			 enum bfd_endian byte_order, bool unsigned_p,
    240  1.1  christos 			 const gdb_mpq &scaling_factor)
    241  1.1  christos   {
    242  1.1  christos     gdb_mpq tmp_q;
    243  1.1  christos 
    244  1.1  christos     tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor);
    245  1.1  christos     mpf_set_q (val, tmp_q.val);
    246  1.1  christos   }
    247  1.1  christos 
    248  1.1  christos   /* The destructor.  */
    249  1.1  christos   ~gdb_mpf () { mpf_clear (val); }
    250  1.1  christos };
    251  1.1  christos 
    252  1.1  christos /* See declaration above.  */
    253  1.1  christos 
    254  1.1  christos template<typename T>
    255  1.1  christos void
    256  1.1  christos gdb_mpz::set (T src)
    257  1.1  christos {
    258  1.1  christos   mpz_import (val, 1 /* count */, -1 /* order */,
    259  1.1  christos 	      sizeof (T) /* size */, 0 /* endian (0 = native) */,
    260  1.1  christos 	      0 /* nails */, &src /* op */);
    261  1.1  christos   if (std::is_signed<T>::value && src < 0)
    262  1.1  christos     {
    263  1.1  christos       /* mpz_import does not handle the sign, so our value was imported
    264  1.1  christos 	 as an unsigned. Adjust that imported value so as to make it
    265  1.1  christos 	 the correct negative value.  */
    266  1.1  christos       gdb_mpz neg_offset;
    267  1.1  christos 
    268  1.1  christos       mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
    269  1.1  christos       mpz_sub (val, val, neg_offset.val);
    270  1.1  christos     }
    271  1.1  christos }
    272  1.1  christos 
    273  1.1  christos /* See declaration above.  */
    274  1.1  christos 
    275  1.1  christos template<typename T>
    276  1.1  christos T
    277  1.1  christos gdb_mpz::as_integer () const
    278  1.1  christos {
    279  1.1  christos   T result;
    280  1.1  christos 
    281  1.1  christos   this->safe_export ({(gdb_byte *) &result, sizeof (result)},
    282  1.1  christos 		     0 /* endian (0 = native) */,
    283  1.1  christos 		     !std::is_signed<T>::value /* unsigned_p */);
    284  1.1  christos 
    285  1.1  christos   return result;
    286  1.1  christos }
    287  1.1  christos 
    288  1.1  christos #endif
    289