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