1 /* Miscellaneous routines making it easier to use GMP within GDB's framework. 2 3 Copyright (C) 2019-2024 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 <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get 24 access to GMP's various formatting functions. */ 25 #include <stdio.h> 26 #include <stdarg.h> 27 #include <gmp.h> 28 #include "gdbsupport/traits.h" 29 30 /* Same as gmp_asprintf, but returning an std::string. */ 31 32 std::string gmp_string_printf (const char *fmt, ...); 33 34 struct gdb_mpq; 35 struct gdb_mpf; 36 37 /* A class to make it easier to use GMP's mpz_t values within GDB. */ 38 39 struct gdb_mpz 40 { 41 /* Constructors. */ 42 gdb_mpz () { mpz_init (m_val); } 43 44 explicit gdb_mpz (const mpz_t &from_val) 45 { 46 mpz_init (m_val); 47 mpz_set (m_val, from_val); 48 } 49 50 gdb_mpz (const gdb_mpz &from) 51 { 52 mpz_init (m_val); 53 mpz_set (m_val, from.m_val); 54 } 55 56 /* Initialize using the given integral value. 57 58 The main advantage of this method is that it handles both signed 59 and unsigned types, with no size restriction. */ 60 template<typename T, typename = gdb::Requires<std::is_integral<T>>> 61 explicit gdb_mpz (T src) 62 { 63 mpz_init (m_val); 64 set (src); 65 } 66 67 explicit gdb_mpz (gdb_mpz &&from) 68 { 69 mpz_init (m_val); 70 mpz_swap (m_val, from.m_val); 71 } 72 73 74 gdb_mpz &operator= (const gdb_mpz &from) 75 { 76 mpz_set (m_val, from.m_val); 77 return *this; 78 } 79 80 gdb_mpz &operator= (gdb_mpz &&other) 81 { 82 mpz_swap (m_val, other.m_val); 83 return *this; 84 } 85 86 template<typename T, typename = gdb::Requires<std::is_integral<T>>> 87 gdb_mpz &operator= (T src) 88 { 89 set (src); 90 return *this; 91 } 92 93 gdb_mpz &operator= (bool src) 94 { 95 mpz_set_ui (m_val, (unsigned long) src); 96 return *this; 97 } 98 99 /* Initialize this value from a string and a base. Returns true if 100 the string was parsed successfully, false otherwise. */ 101 bool set (const char *str, int base) 102 { 103 return mpz_set_str (m_val, str, base) != -1; 104 } 105 106 /* Return a new value that is BASE**EXP. */ 107 static gdb_mpz pow (unsigned long base, unsigned long exp) 108 { 109 gdb_mpz result; 110 mpz_ui_pow_ui (result.m_val, base, exp); 111 return result; 112 } 113 114 /* Return a new value that is this value raised to EXP. */ 115 gdb_mpz pow (unsigned long exp) const 116 { 117 gdb_mpz result; 118 mpz_pow_ui (result.m_val, m_val, exp); 119 return result; 120 } 121 122 /* Convert this value to an integer of the given type. 123 124 The return type can signed or unsigned, with no size restriction. */ 125 template<typename T> T as_integer () const; 126 127 /* Convert this value to an integer of the given type. If this 128 value is too large, it is truncated. 129 130 The return type can signed or unsigned, with no size restriction. */ 131 template<typename T> T as_integer_truncate () const; 132 133 /* Set VAL by importing the number stored in the byte array (BUF), 134 using the given BYTE_ORDER. The size of the data to read is 135 the byte array's size. 136 137 UNSIGNED_P indicates whether the number has an unsigned type. */ 138 void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order, 139 bool unsigned_p); 140 141 /* Write VAL into BUF as a number whose byte size is the size of BUF, 142 using the given BYTE_ORDER. 143 144 UNSIGNED_P indicates whether the number has an unsigned type. */ 145 void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order, 146 bool unsigned_p) const 147 { 148 export_bits (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */, 149 unsigned_p, true /* safe */); 150 } 151 152 /* Like write, but truncates the value to the desired number of 153 bytes. */ 154 void truncate (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order, 155 bool unsigned_p) const 156 { 157 export_bits (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */, 158 unsigned_p, false /* safe */); 159 } 160 161 /* Return a string containing VAL. */ 162 std::string str () const { return gmp_string_printf ("%Zd", m_val); } 163 164 /* The destructor. */ 165 ~gdb_mpz () { mpz_clear (m_val); } 166 167 /* Negate this value in place. */ 168 void negate () 169 { 170 mpz_neg (m_val, m_val); 171 } 172 173 /* Take the one's complement in place. */ 174 void complement () 175 { mpz_com (m_val, m_val); } 176 177 /* Mask this value to N bits, in place. */ 178 void mask (unsigned n) 179 { mpz_tdiv_r_2exp (m_val, m_val, n); } 180 181 /* Return the sign of this value. This returns -1 for a negative 182 value, 0 if the value is 0, and 1 for a positive value. */ 183 int sgn () const 184 { return mpz_sgn (m_val); } 185 186 explicit operator bool () const 187 { return sgn () != 0; } 188 189 gdb_mpz &operator*= (long other) 190 { 191 mpz_mul_si (m_val, m_val, other); 192 return *this; 193 } 194 195 gdb_mpz operator* (const gdb_mpz &other) const 196 { 197 gdb_mpz result; 198 mpz_mul (result.m_val, m_val, other.m_val); 199 return result; 200 } 201 202 gdb_mpz operator/ (const gdb_mpz &other) const 203 { 204 gdb_mpz result; 205 mpz_tdiv_q (result.m_val, m_val, other.m_val); 206 return result; 207 } 208 209 gdb_mpz operator% (const gdb_mpz &other) const 210 { 211 gdb_mpz result; 212 mpz_tdiv_r (result.m_val, m_val, other.m_val); 213 return result; 214 } 215 216 gdb_mpz &operator+= (unsigned long other) 217 { 218 mpz_add_ui (m_val, m_val, other); 219 return *this; 220 } 221 222 gdb_mpz &operator+= (const gdb_mpz &other) 223 { 224 mpz_add (m_val, m_val, other.m_val); 225 return *this; 226 } 227 228 gdb_mpz operator+ (const gdb_mpz &other) const 229 { 230 gdb_mpz result; 231 mpz_add (result.m_val, m_val, other.m_val); 232 return result; 233 } 234 235 gdb_mpz &operator-= (unsigned long other) 236 { 237 mpz_sub_ui (m_val, m_val, other); 238 return *this; 239 } 240 241 gdb_mpz &operator-= (const gdb_mpz &other) 242 { 243 mpz_sub (m_val, m_val, other.m_val); 244 return *this; 245 } 246 247 gdb_mpz operator- (const gdb_mpz &other) const 248 { 249 gdb_mpz result; 250 mpz_sub (result.m_val, m_val, other.m_val); 251 return result; 252 } 253 254 gdb_mpz operator- () const 255 { 256 gdb_mpz result; 257 mpz_neg (result.m_val, m_val); 258 return result; 259 } 260 261 gdb_mpz &operator<<= (unsigned long nbits) 262 { 263 mpz_mul_2exp (m_val, m_val, nbits); 264 return *this; 265 } 266 267 gdb_mpz operator<< (unsigned long nbits) const & 268 { 269 gdb_mpz result; 270 mpz_mul_2exp (result.m_val, m_val, nbits); 271 return result; 272 } 273 274 gdb_mpz operator<< (unsigned long nbits) && 275 { 276 mpz_mul_2exp (m_val, m_val, nbits); 277 return *this; 278 } 279 280 gdb_mpz operator>> (unsigned long nbits) const 281 { 282 gdb_mpz result; 283 mpz_fdiv_q_2exp (result.m_val, m_val, nbits); 284 return result; 285 } 286 287 gdb_mpz &operator>>= (unsigned long nbits) 288 { 289 mpz_fdiv_q_2exp (m_val, m_val, nbits); 290 return *this; 291 } 292 293 gdb_mpz operator& (const gdb_mpz &other) const 294 { 295 gdb_mpz result; 296 mpz_and (result.m_val, m_val, other.m_val); 297 return result; 298 } 299 300 gdb_mpz operator| (const gdb_mpz &other) const 301 { 302 gdb_mpz result; 303 mpz_ior (result.m_val, m_val, other.m_val); 304 return result; 305 } 306 307 gdb_mpz operator^ (const gdb_mpz &other) const 308 { 309 gdb_mpz result; 310 mpz_xor (result.m_val, m_val, other.m_val); 311 return result; 312 } 313 314 bool operator> (const gdb_mpz &other) const 315 { 316 return mpz_cmp (m_val, other.m_val) > 0; 317 } 318 319 bool operator>= (const gdb_mpz &other) const 320 { 321 return mpz_cmp (m_val, other.m_val) >= 0; 322 } 323 324 bool operator< (const gdb_mpz &other) const 325 { 326 return mpz_cmp (m_val, other.m_val) < 0; 327 } 328 329 bool operator<= (const gdb_mpz &other) const 330 { 331 return mpz_cmp (m_val, other.m_val) <= 0; 332 } 333 334 bool operator< (long other) const 335 { 336 return mpz_cmp_si (m_val, other) < 0; 337 } 338 339 /* We want an operator== that can handle all integer types. For 340 types that are 'long' or narrower, we can use a GMP function and 341 avoid boxing the RHS. But, because overloading based on integer 342 type is a pain in C++, we accept all such types here and check 343 the size in the body. */ 344 template<typename T, typename = gdb::Requires<std::is_integral<T>>> 345 bool operator== (T other) const 346 { 347 if (std::is_signed<T>::value) 348 { 349 if (sizeof (T) <= sizeof (long)) 350 return mpz_cmp_si (m_val, other) == 0; 351 } 352 else 353 { 354 if (sizeof (T) <= sizeof (unsigned long)) 355 return mpz_cmp_ui (m_val, other) == 0; 356 } 357 return *this == gdb_mpz (other); 358 } 359 360 bool operator== (const gdb_mpz &other) const 361 { 362 return mpz_cmp (m_val, other.m_val) == 0; 363 } 364 365 bool operator!= (const gdb_mpz &other) const 366 { 367 return mpz_cmp (m_val, other.m_val) != 0; 368 } 369 370 private: 371 372 /* Helper template for constructor and operator=. */ 373 template<typename T> void set (T src); 374 375 /* Low-level function to export VAL into BUF as a number whose byte size 376 is the size of BUF. 377 378 If UNSIGNED_P is true, then export VAL into BUF as an unsigned value. 379 Otherwise, export it as a signed value. 380 381 The API is inspired from GMP's mpz_export, hence the naming and types 382 of the following parameter: 383 - ENDIAN should be: 384 . 1 for most significant byte first; or 385 . -1 for least significant byte first; or 386 . 0 for native endianness. 387 388 If SAFE is true, an error is raised if BUF is not large enough to 389 contain the value being exported. If SAFE is false, the value is 390 truncated to fit in BUF. */ 391 void export_bits (gdb::array_view<gdb_byte> buf, int endian, bool unsigned_p, 392 bool safe) const; 393 394 friend struct gdb_mpq; 395 friend struct gdb_mpf; 396 397 mpz_t m_val; 398 }; 399 400 /* A class to make it easier to use GMP's mpq_t values within GDB. */ 401 402 struct gdb_mpq 403 { 404 /* Constructors. */ 405 gdb_mpq () { mpq_init (m_val); } 406 407 explicit gdb_mpq (const mpq_t &from_val) 408 { 409 mpq_init (m_val); 410 mpq_set (m_val, from_val); 411 } 412 413 gdb_mpq (const gdb_mpq &from) 414 { 415 mpq_init (m_val); 416 mpq_set (m_val, from.m_val); 417 } 418 419 explicit gdb_mpq (gdb_mpq &&from) 420 { 421 mpq_init (m_val); 422 mpq_swap (m_val, from.m_val); 423 } 424 425 gdb_mpq (const gdb_mpz &num, const gdb_mpz &denom) 426 { 427 mpq_init (m_val); 428 mpz_set (mpq_numref (m_val), num.m_val); 429 mpz_set (mpq_denref (m_val), denom.m_val); 430 mpq_canonicalize (m_val); 431 } 432 433 gdb_mpq (long num, long denom) 434 { 435 mpq_init (m_val); 436 mpq_set_si (m_val, num, denom); 437 mpq_canonicalize (m_val); 438 } 439 440 /* Copy assignment operator. */ 441 gdb_mpq &operator= (const gdb_mpq &from) 442 { 443 mpq_set (m_val, from.m_val); 444 return *this; 445 } 446 447 gdb_mpq &operator= (gdb_mpq &&from) 448 { 449 mpq_swap (m_val, from.m_val); 450 return *this; 451 } 452 453 gdb_mpq &operator= (const gdb_mpz &from) 454 { 455 mpq_set_z (m_val, from.m_val); 456 return *this; 457 } 458 459 gdb_mpq &operator= (double d) 460 { 461 mpq_set_d (m_val, d); 462 return *this; 463 } 464 465 /* Return the sign of this value. This returns -1 for a negative 466 value, 0 if the value is 0, and 1 for a positive value. */ 467 int sgn () const 468 { return mpq_sgn (m_val); } 469 470 gdb_mpq operator+ (const gdb_mpq &other) const 471 { 472 gdb_mpq result; 473 mpq_add (result.m_val, m_val, other.m_val); 474 return result; 475 } 476 477 gdb_mpq operator- (const gdb_mpq &other) const 478 { 479 gdb_mpq result; 480 mpq_sub (result.m_val, m_val, other.m_val); 481 return result; 482 } 483 484 gdb_mpq operator* (const gdb_mpq &other) const 485 { 486 gdb_mpq result; 487 mpq_mul (result.m_val, m_val, other.m_val); 488 return result; 489 } 490 491 gdb_mpq operator/ (const gdb_mpq &other) const 492 { 493 gdb_mpq result; 494 mpq_div (result.m_val, m_val, other.m_val); 495 return result; 496 } 497 498 gdb_mpq &operator*= (const gdb_mpq &other) 499 { 500 mpq_mul (m_val, m_val, other.m_val); 501 return *this; 502 } 503 504 gdb_mpq &operator/= (const gdb_mpq &other) 505 { 506 mpq_div (m_val, m_val, other.m_val); 507 return *this; 508 } 509 510 bool operator== (const gdb_mpq &other) const 511 { 512 return mpq_cmp (m_val, other.m_val) == 0; 513 } 514 515 bool operator< (const gdb_mpq &other) const 516 { 517 return mpq_cmp (m_val, other.m_val) < 0; 518 } 519 520 /* Return a string representing VAL as "<numerator> / <denominator>". */ 521 std::string str () const { return gmp_string_printf ("%Qd", m_val); } 522 523 /* Return VAL rounded to the nearest integer. */ 524 gdb_mpz get_rounded () const; 525 526 /* Return this value as an integer, rounded toward zero. */ 527 gdb_mpz as_integer () const 528 { 529 gdb_mpz result; 530 mpz_tdiv_q (result.m_val, mpq_numref (m_val), mpq_denref (m_val)); 531 return result; 532 } 533 534 /* Return this value converted to a host double. */ 535 double as_double () const 536 { return mpq_get_d (m_val); } 537 538 /* Set VAL from the contents of the given byte array (BUF), which 539 contains the unscaled value of a fixed point type object. 540 The byte size of the data is the size of BUF. 541 542 BYTE_ORDER provides the byte_order to use when reading the data. 543 544 UNSIGNED_P indicates whether the number has an unsigned type. 545 SCALING_FACTOR is the scaling factor to apply after having 546 read the unscaled value from our buffer. */ 547 void read_fixed_point (gdb::array_view<const gdb_byte> buf, 548 enum bfd_endian byte_order, bool unsigned_p, 549 const gdb_mpq &scaling_factor); 550 551 /* Write VAL into BUF as fixed point value following the given BYTE_ORDER. 552 The size of BUF is used as the length to write the value into. 553 554 UNSIGNED_P indicates whether the number has an unsigned type. 555 SCALING_FACTOR is the scaling factor to apply before writing 556 the unscaled value to our buffer. */ 557 void write_fixed_point (gdb::array_view<gdb_byte> buf, 558 enum bfd_endian byte_order, bool unsigned_p, 559 const gdb_mpq &scaling_factor) const; 560 561 /* The destructor. */ 562 ~gdb_mpq () { mpq_clear (m_val); } 563 564 private: 565 566 friend struct gdb_mpf; 567 568 mpq_t m_val; 569 }; 570 571 /* A class to make it easier to use GMP's mpf_t values within GDB. 572 573 Should MPFR become a required dependency, we should probably 574 drop this class in favor of using MPFR. */ 575 576 struct gdb_mpf 577 { 578 /* Constructors. */ 579 gdb_mpf () { mpf_init (m_val); } 580 581 DISABLE_COPY_AND_ASSIGN (gdb_mpf); 582 583 /* Set VAL from the contents of the given buffer (BUF), which 584 contains the unscaled value of a fixed point type object 585 with the given size (LEN) and byte order (BYTE_ORDER). 586 587 UNSIGNED_P indicates whether the number has an unsigned type. 588 SCALING_FACTOR is the scaling factor to apply after having 589 read the unscaled value from our buffer. */ 590 void read_fixed_point (gdb::array_view<const gdb_byte> buf, 591 enum bfd_endian byte_order, bool unsigned_p, 592 const gdb_mpq &scaling_factor) 593 { 594 gdb_mpq tmp_q; 595 596 tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor); 597 mpf_set_q (m_val, tmp_q.m_val); 598 } 599 600 /* Convert this value to a string. FMT is the format to use, and 601 should have a single '%' substitution. */ 602 std::string str (const char *fmt) const 603 { return gmp_string_printf (fmt, m_val); } 604 605 /* The destructor. */ 606 ~gdb_mpf () { mpf_clear (m_val); } 607 608 private: 609 610 mpf_t m_val; 611 }; 612 613 /* See declaration above. */ 614 615 template<typename T> 616 void 617 gdb_mpz::set (T src) 618 { 619 mpz_import (m_val, 1 /* count */, -1 /* order */, 620 sizeof (T) /* size */, 0 /* endian (0 = native) */, 621 0 /* nails */, &src /* op */); 622 if (std::is_signed<T>::value && src < 0) 623 { 624 /* mpz_import does not handle the sign, so our value was imported 625 as an unsigned. Adjust that imported value so as to make it 626 the correct negative value. */ 627 gdb_mpz neg_offset; 628 629 mpz_ui_pow_ui (neg_offset.m_val, 2, sizeof (T) * HOST_CHAR_BIT); 630 mpz_sub (m_val, m_val, neg_offset.m_val); 631 } 632 } 633 634 /* See declaration above. */ 635 636 template<typename T> 637 T 638 gdb_mpz::as_integer () const 639 { 640 T result; 641 642 this->export_bits ({(gdb_byte *) &result, sizeof (result)}, 643 0 /* endian (0 = native) */, 644 !std::is_signed<T>::value /* unsigned_p */, 645 true /* safe */); 646 647 return result; 648 } 649 650 /* See declaration above. */ 651 652 template<typename T> 653 T 654 gdb_mpz::as_integer_truncate () const 655 { 656 T result; 657 658 this->export_bits ({(gdb_byte *) &result, sizeof (result)}, 659 0 /* endian (0 = native) */, 660 !std::is_signed<T>::value /* unsigned_p */, 661 false /* safe */); 662 663 return result; 664 } 665 666 #endif 667