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