1 /* Miscellaneous routines making it easier to use GMP within GDB's framework.
2 
3    Copyright (C) 2019-2021 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.  */
gdb_mpzgdb_mpz43   gdb_mpz () { mpz_init (val); }
44 
gdb_mpzgdb_mpz45   explicit gdb_mpz (const mpz_t &from_val)
46   {
47     mpz_init (val);
48     mpz_set (val, from_val);
49   }
50 
gdb_mpzgdb_mpz51   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>>>
gdb_mpzgdb_mpz62   explicit gdb_mpz (T src)
63   {
64     mpz_init (val);
65     set (src);
66   }
67 
gdb_mpzgdb_mpz68   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.  */
strgdb_mpz115   std::string str () const { return gmp_string_printf ("%Zd", val); }
116 
117   /* The destructor.  */
~gdb_mpzgdb_mpz118   ~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.  */
gdb_mpqgdb_mpq151   gdb_mpq () { mpq_init (val); }
152 
gdb_mpqgdb_mpq153   explicit gdb_mpq (const mpq_t &from_val)
154   {
155     mpq_init (val);
156     mpq_set (val, from_val);
157   }
158 
gdb_mpqgdb_mpq159   gdb_mpq (const gdb_mpq &from)
160   {
161     mpq_init (val);
162     mpq_set (val, from.val);
163   }
164 
gdb_mpqgdb_mpq165   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>".  */
strgdb_mpq185   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.  */
~gdb_mpqgdb_mpq214   ~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.  */
gdb_mpfgdb_mpf227   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.  */
read_fixed_pointgdb_mpf238   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.  */
~gdb_mpfgdb_mpf249   ~gdb_mpf () { mpf_clear (val); }
250 };
251 
252 /* See declaration above.  */
253 
254 template<typename T>
255 void
set(T src)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
as_integer()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