1*6881a400Schristos /* Copyright (C) 2019-2023 Free Software Foundation, Inc. 2*6881a400Schristos 3*6881a400Schristos This file is part of GDB. 4*6881a400Schristos 5*6881a400Schristos This program is free software; you can redistribute it and/or modify 6*6881a400Schristos it under the terms of the GNU General Public License as published by 7*6881a400Schristos the Free Software Foundation; either version 3 of the License, or 8*6881a400Schristos (at your option) any later version. 9*6881a400Schristos 10*6881a400Schristos This program is distributed in the hope that it will be useful, 11*6881a400Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 12*6881a400Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*6881a400Schristos GNU General Public License for more details. 14*6881a400Schristos 15*6881a400Schristos You should have received a copy of the GNU General Public License 16*6881a400Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17*6881a400Schristos 18*6881a400Schristos #include "gmp-utils.h" 19*6881a400Schristos 20*6881a400Schristos /* See gmp-utils.h. */ 21*6881a400Schristos 22*6881a400Schristos std::string 23*6881a400Schristos gmp_string_printf (const char *fmt, ...) 24*6881a400Schristos { 25*6881a400Schristos va_list vp; 26*6881a400Schristos 27*6881a400Schristos va_start (vp, fmt); 28*6881a400Schristos int size = gmp_vsnprintf (NULL, 0, fmt, vp); 29*6881a400Schristos va_end (vp); 30*6881a400Schristos 31*6881a400Schristos std::string str (size, '\0'); 32*6881a400Schristos 33*6881a400Schristos /* C++11 and later guarantee std::string uses contiguous memory and 34*6881a400Schristos always includes the terminating '\0'. */ 35*6881a400Schristos va_start (vp, fmt); 36*6881a400Schristos gmp_vsprintf (&str[0], fmt, vp); 37*6881a400Schristos va_end (vp); 38*6881a400Schristos 39*6881a400Schristos return str; 40*6881a400Schristos } 41*6881a400Schristos 42*6881a400Schristos /* See gmp-utils.h. */ 43*6881a400Schristos 44*6881a400Schristos void 45*6881a400Schristos gdb_mpz::read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order, 46*6881a400Schristos bool unsigned_p) 47*6881a400Schristos { 48*6881a400Schristos mpz_import (val, 1 /* count */, -1 /* order */, buf.size () /* size */, 49*6881a400Schristos byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */, 50*6881a400Schristos 0 /* nails */, buf.data () /* op */); 51*6881a400Schristos 52*6881a400Schristos if (!unsigned_p) 53*6881a400Schristos { 54*6881a400Schristos /* The value was imported as if it was a positive value, 55*6881a400Schristos as mpz_import does not handle signs. If the original value 56*6881a400Schristos was in fact negative, we need to adjust VAL accordingly. */ 57*6881a400Schristos gdb_mpz max; 58*6881a400Schristos 59*6881a400Schristos mpz_ui_pow_ui (max.val, 2, buf.size () * HOST_CHAR_BIT - 1); 60*6881a400Schristos if (mpz_cmp (val, max.val) >= 0) 61*6881a400Schristos mpz_submul_ui (val, max.val, 2); 62*6881a400Schristos } 63*6881a400Schristos } 64*6881a400Schristos 65*6881a400Schristos /* See gmp-utils.h. */ 66*6881a400Schristos 67*6881a400Schristos void 68*6881a400Schristos gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order, 69*6881a400Schristos bool unsigned_p) const 70*6881a400Schristos { 71*6881a400Schristos this->safe_export 72*6881a400Schristos (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */, unsigned_p); 73*6881a400Schristos } 74*6881a400Schristos 75*6881a400Schristos /* See gmp-utils.h. */ 76*6881a400Schristos 77*6881a400Schristos void 78*6881a400Schristos gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf, 79*6881a400Schristos int endian, bool unsigned_p) const 80*6881a400Schristos { 81*6881a400Schristos gdb_assert (buf.size () > 0); 82*6881a400Schristos 83*6881a400Schristos if (mpz_sgn (val) == 0) 84*6881a400Schristos { 85*6881a400Schristos /* Our value is zero, so no need to call mpz_export to do the work, 86*6881a400Schristos especially since mpz_export's documentation explicitly says 87*6881a400Schristos that the function is a noop in this case. Just write zero to 88*6881a400Schristos BUF ourselves. */ 89*6881a400Schristos memset (buf.data (), 0, buf.size ()); 90*6881a400Schristos return; 91*6881a400Schristos } 92*6881a400Schristos 93*6881a400Schristos /* Determine the maximum range of values that our buffer can hold, 94*6881a400Schristos and verify that VAL is within that range. */ 95*6881a400Schristos 96*6881a400Schristos gdb_mpz lo, hi; 97*6881a400Schristos const size_t max_usable_bits = buf.size () * HOST_CHAR_BIT; 98*6881a400Schristos if (unsigned_p) 99*6881a400Schristos { 100*6881a400Schristos lo = 0; 101*6881a400Schristos 102*6881a400Schristos mpz_ui_pow_ui (hi.val, 2, max_usable_bits); 103*6881a400Schristos mpz_sub_ui (hi.val, hi.val, 1); 104*6881a400Schristos } 105*6881a400Schristos else 106*6881a400Schristos { 107*6881a400Schristos mpz_ui_pow_ui (lo.val, 2, max_usable_bits - 1); 108*6881a400Schristos mpz_neg (lo.val, lo.val); 109*6881a400Schristos 110*6881a400Schristos mpz_ui_pow_ui (hi.val, 2, max_usable_bits - 1); 111*6881a400Schristos mpz_sub_ui (hi.val, hi.val, 1); 112*6881a400Schristos } 113*6881a400Schristos 114*6881a400Schristos if (mpz_cmp (val, lo.val) < 0 || mpz_cmp (val, hi.val) > 0) 115*6881a400Schristos error (_("Cannot export value %s as %zu-bits %s integer" 116*6881a400Schristos " (must be between %s and %s)"), 117*6881a400Schristos this->str ().c_str (), 118*6881a400Schristos max_usable_bits, 119*6881a400Schristos unsigned_p ? _("unsigned") : _("signed"), 120*6881a400Schristos lo.str ().c_str (), 121*6881a400Schristos hi.str ().c_str ()); 122*6881a400Schristos 123*6881a400Schristos gdb_mpz exported_val (val); 124*6881a400Schristos 125*6881a400Schristos if (mpz_cmp_ui (exported_val.val, 0) < 0) 126*6881a400Schristos { 127*6881a400Schristos /* mpz_export does not handle signed values, so create a positive 128*6881a400Schristos value whose bit representation as an unsigned of the same length 129*6881a400Schristos would be the same as our negative value. */ 130*6881a400Schristos gdb_mpz neg_offset; 131*6881a400Schristos 132*6881a400Schristos mpz_ui_pow_ui (neg_offset.val, 2, buf.size () * HOST_CHAR_BIT); 133*6881a400Schristos mpz_add (exported_val.val, exported_val.val, neg_offset.val); 134*6881a400Schristos } 135*6881a400Schristos 136*6881a400Schristos /* Do the export into a buffer allocated by GMP itself; that way, 137*6881a400Schristos we can detect cases where BUF is not large enough to export 138*6881a400Schristos our value, and thus avoid a buffer overlow. Normally, this should 139*6881a400Schristos never happen, since we verified earlier that the buffer is large 140*6881a400Schristos enough to accomodate our value, but doing this allows us to be 141*6881a400Schristos extra safe with the export. 142*6881a400Schristos 143*6881a400Schristos After verification that the export behaved as expected, we will 144*6881a400Schristos copy the data over to BUF. */ 145*6881a400Schristos 146*6881a400Schristos size_t word_countp; 147*6881a400Schristos gdb::unique_xmalloc_ptr<void> exported 148*6881a400Schristos (mpz_export (NULL, &word_countp, -1 /* order */, buf.size () /* size */, 149*6881a400Schristos endian, 0 /* nails */, exported_val.val)); 150*6881a400Schristos 151*6881a400Schristos gdb_assert (word_countp == 1); 152*6881a400Schristos 153*6881a400Schristos memcpy (buf.data (), exported.get (), buf.size ()); 154*6881a400Schristos } 155*6881a400Schristos 156*6881a400Schristos /* See gmp-utils.h. */ 157*6881a400Schristos 158*6881a400Schristos gdb_mpz 159*6881a400Schristos gdb_mpq::get_rounded () const 160*6881a400Schristos { 161*6881a400Schristos /* Work with a positive number so as to make the "floor" rounding 162*6881a400Schristos always round towards zero. */ 163*6881a400Schristos 164*6881a400Schristos gdb_mpq abs_val (val); 165*6881a400Schristos mpq_abs (abs_val.val, abs_val.val); 166*6881a400Schristos 167*6881a400Schristos /* Convert our rational number into a quotient and remainder, 168*6881a400Schristos with "floor" rounding, which in our case means rounding 169*6881a400Schristos towards zero. */ 170*6881a400Schristos 171*6881a400Schristos gdb_mpz quotient, remainder; 172*6881a400Schristos mpz_fdiv_qr (quotient.val, remainder.val, 173*6881a400Schristos mpq_numref (abs_val.val), mpq_denref (abs_val.val)); 174*6881a400Schristos 175*6881a400Schristos /* Multiply the remainder by 2, and see if it is greater or equal 176*6881a400Schristos to abs_val's denominator. If yes, round to the next integer. */ 177*6881a400Schristos 178*6881a400Schristos mpz_mul_ui (remainder.val, remainder.val, 2); 179*6881a400Schristos if (mpz_cmp (remainder.val, mpq_denref (abs_val.val)) >= 0) 180*6881a400Schristos mpz_add_ui (quotient.val, quotient.val, 1); 181*6881a400Schristos 182*6881a400Schristos /* Re-apply the sign if needed. */ 183*6881a400Schristos if (mpq_sgn (val) < 0) 184*6881a400Schristos mpz_neg (quotient.val, quotient.val); 185*6881a400Schristos 186*6881a400Schristos return quotient; 187*6881a400Schristos } 188*6881a400Schristos 189*6881a400Schristos /* See gmp-utils.h. */ 190*6881a400Schristos 191*6881a400Schristos void 192*6881a400Schristos gdb_mpq::read_fixed_point (gdb::array_view<const gdb_byte> buf, 193*6881a400Schristos enum bfd_endian byte_order, bool unsigned_p, 194*6881a400Schristos const gdb_mpq &scaling_factor) 195*6881a400Schristos { 196*6881a400Schristos gdb_mpz vz; 197*6881a400Schristos vz.read (buf, byte_order, unsigned_p); 198*6881a400Schristos 199*6881a400Schristos mpq_set_z (val, vz.val); 200*6881a400Schristos mpq_mul (val, val, scaling_factor.val); 201*6881a400Schristos } 202*6881a400Schristos 203*6881a400Schristos /* See gmp-utils.h. */ 204*6881a400Schristos 205*6881a400Schristos void 206*6881a400Schristos gdb_mpq::write_fixed_point (gdb::array_view<gdb_byte> buf, 207*6881a400Schristos enum bfd_endian byte_order, bool unsigned_p, 208*6881a400Schristos const gdb_mpq &scaling_factor) const 209*6881a400Schristos { 210*6881a400Schristos gdb_mpq unscaled (val); 211*6881a400Schristos 212*6881a400Schristos mpq_div (unscaled.val, unscaled.val, scaling_factor.val); 213*6881a400Schristos 214*6881a400Schristos gdb_mpz unscaled_z = unscaled.get_rounded (); 215*6881a400Schristos unscaled_z.write (buf, byte_order, unsigned_p); 216*6881a400Schristos } 217*6881a400Schristos 218*6881a400Schristos /* A wrapper around xrealloc that we can then register with GMP 219*6881a400Schristos as the "realloc" function. */ 220*6881a400Schristos 221*6881a400Schristos static void * 222*6881a400Schristos xrealloc_for_gmp (void *ptr, size_t old_size, size_t new_size) 223*6881a400Schristos { 224*6881a400Schristos return xrealloc (ptr, new_size); 225*6881a400Schristos } 226*6881a400Schristos 227*6881a400Schristos /* A wrapper around xfree that we can then register with GMP 228*6881a400Schristos as the "free" function. */ 229*6881a400Schristos 230*6881a400Schristos static void 231*6881a400Schristos xfree_for_gmp (void *ptr, size_t size) 232*6881a400Schristos { 233*6881a400Schristos xfree (ptr); 234*6881a400Schristos } 235*6881a400Schristos 236*6881a400Schristos void _initialize_gmp_utils (); 237*6881a400Schristos 238*6881a400Schristos void 239*6881a400Schristos _initialize_gmp_utils () 240*6881a400Schristos { 241*6881a400Schristos /* Tell GMP to use GDB's memory management routines. */ 242*6881a400Schristos mp_set_memory_functions (xmalloc, xrealloc_for_gmp, xfree_for_gmp); 243*6881a400Schristos } 244