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