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