]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/unittests/gmp-utils-selftests.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / unittests / gmp-utils-selftests.c
1 /* Self tests of the gmp-utils API.
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 #include "gmp-utils.h"
21 #include "gdbsupport/selftest.h"
22
23 #include <math.h>
24
25 namespace selftests {
26
27 /* Perform a series of general tests of gdb_mpz's as_integer method.
28
29 This function limits itself to values which are in range (out-of-range
30 values will be tested separately). In doing so, it tries to be reasonably
31 exhaustive, by testing the edges, as well as a resonable set of values
32 including negative ones, zero, and positive values. */
33
34 static void
35 gdb_mpz_as_integer ()
36 {
37 /* Test a range of values, both as LONGEST and ULONGEST. */
38 gdb_mpz v;
39 LONGEST l_expected;
40 ULONGEST ul_expected;
41
42 /* Start with the smallest LONGEST */
43 l_expected = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
44
45 mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
46 mpz_neg (v.val, v.val);
47
48 SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
49
50 /* Try with a small range of integers including negative, zero,
51 and positive values. */
52 for (int i = -256; i <= 256; i++)
53 {
54 l_expected = (LONGEST) i;
55 mpz_set_si (v.val, i);
56 SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
57
58 if (i >= 0)
59 {
60 ul_expected = (ULONGEST) i;
61 mpz_set_ui (v.val, i);
62 SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
63 }
64 }
65
66 /* Try with LONGEST_MAX. */
67 l_expected = LONGEST_MAX;
68 ul_expected = (ULONGEST) l_expected;
69
70 mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
71 mpz_sub_ui (v.val, v.val, 1);
72
73 SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
74 SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
75
76 /* Try with ULONGEST_MAX. */
77 ul_expected = ULONGEST_MAX;
78 mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8);
79 mpz_sub_ui (v.val, v.val, 1);
80
81 SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
82 }
83
84 /* A helper function which calls the given gdb_mpz object's as_integer
85 method with the given type T, and verifies that this triggers
86 an error due to VAL's value being out of range for type T. */
87
88 template<typename T, typename = gdb::Requires<std::is_integral<T>>>
89 static void
90 check_as_integer_raises_out_of_range_error (const gdb_mpz &val)
91 {
92 try
93 {
94 val.as_integer<T> ();
95 }
96 catch (const gdb_exception_error &ex)
97 {
98 SELF_CHECK (ex.reason == RETURN_ERROR);
99 SELF_CHECK (ex.error == GENERIC_ERROR);
100 SELF_CHECK (strstr (ex.what (), "Cannot export value") != nullptr);
101 return;
102 }
103 /* The expected exception did not get raised. */
104 SELF_CHECK (false);
105 }
106
107 /* Perform out-of-range tests of gdb_mpz's as_integer method.
108
109 The goal of this function is to verify that gdb_mpz::as_integer
110 handles out-of-range values correctly. */
111
112 static void
113 gdb_mpz_as_integer_out_of_range ()
114 {
115 gdb_mpz v;
116
117 /* Try LONGEST_MIN minus 1. */
118 mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
119 mpz_neg (v.val, v.val);
120 mpz_sub_ui (v.val, v.val, 1);
121
122 check_as_integer_raises_out_of_range_error<ULONGEST> (v);
123 check_as_integer_raises_out_of_range_error<LONGEST> (v);
124
125 /* Try negative one (-1). */
126 v = -1;
127
128 check_as_integer_raises_out_of_range_error<ULONGEST> (v);
129 SELF_CHECK (v.as_integer<LONGEST> () == (LONGEST) -1);
130
131 /* Try LONGEST_MAX plus 1. */
132 v = LONGEST_MAX;
133 mpz_add_ui (v.val, v.val, 1);
134
135 SELF_CHECK (v.as_integer<ULONGEST> () == (ULONGEST) LONGEST_MAX + 1);
136 check_as_integer_raises_out_of_range_error<LONGEST> (v);
137
138 /* Try ULONGEST_MAX plus 1. */
139 v = ULONGEST_MAX;
140 mpz_add_ui (v.val, v.val, 1);
141
142 check_as_integer_raises_out_of_range_error<ULONGEST> (v);
143 check_as_integer_raises_out_of_range_error<LONGEST> (v);
144 }
145
146 /* A helper function to store the given integer value into a buffer,
147 before reading it back into a gdb_mpz. Sets ACTUAL to the value
148 read back, while at the same time setting EXPECTED as the value
149 we would expect to be read back.
150
151 Note that this function does not perform the comparison between
152 EXPECTED and ACTUAL. The caller will do it inside a SELF_CHECK
153 call, allowing the line information shown when the test fails
154 to provide a bit more information about the kind of values
155 that were used when the check failed. This makes the writing
156 of the tests a little more verbose, but the debugging in case
157 of problems should hopefuly be easier. */
158
159 template<typename T>
160 void
161 store_and_read_back (T val, size_t buf_len, enum bfd_endian byte_order,
162 gdb_mpz &expected, gdb_mpz &actual)
163 {
164 gdb_byte *buf;
165
166 expected = val;
167
168 buf = (gdb_byte *) alloca (buf_len);
169 store_integer (buf, buf_len, byte_order, val);
170
171 /* Pre-initialize ACTUAL to something that's not the expected value. */
172 mpz_set (actual.val, expected.val);
173 mpz_sub_ui (actual.val, actual.val, 500);
174
175 actual.read ({buf, buf_len}, byte_order, !std::is_signed<T>::value);
176 }
177
178 /* Test the gdb_mpz::read method over a reasonable range of values.
179
180 The testing is done by picking an arbitrary buffer length, after
181 which we test every possible value that this buffer allows, both
182 with signed numbers as well as unsigned ones. */
183
184 static void
185 gdb_mpz_read_all_from_small ()
186 {
187 /* Start with a type whose size is small enough that we can afford
188 to check the complete range. */
189
190 int buf_len = 1;
191 LONGEST l_min = -pow (2.0, buf_len * 8 - 1);
192 LONGEST l_max = pow (2.0, buf_len * 8 - 1) - 1;
193
194 for (LONGEST l = l_min; l <= l_max; l++)
195 {
196 gdb_mpz expected, actual;
197
198 store_and_read_back (l, buf_len, BFD_ENDIAN_BIG, expected, actual);
199 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
200
201 store_and_read_back (l, buf_len, BFD_ENDIAN_LITTLE, expected, actual);
202 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
203 }
204
205 /* Do the same as above, but with an unsigned type. */
206 ULONGEST ul_min = 0;
207 ULONGEST ul_max = pow (2.0, buf_len * 8) - 1;
208
209 for (ULONGEST ul = ul_min; ul <= ul_max; ul++)
210 {
211 gdb_mpz expected, actual;
212
213 store_and_read_back (ul, buf_len, BFD_ENDIAN_BIG, expected, actual);
214 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
215
216 store_and_read_back (ul, buf_len, BFD_ENDIAN_LITTLE, expected, actual);
217 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
218 }
219 }
220
221 /* Test the gdb_mpz::read the extremes of LONGEST and ULONGEST. */
222
223 static void
224 gdb_mpz_read_min_max ()
225 {
226 gdb_mpz expected, actual;
227
228 /* Start with the smallest LONGEST. */
229
230 LONGEST l_min = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
231
232 store_and_read_back (l_min, sizeof (LONGEST), BFD_ENDIAN_BIG,
233 expected, actual);
234 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
235
236 store_and_read_back (l_min, sizeof (LONGEST), BFD_ENDIAN_LITTLE,
237 expected, actual);
238 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
239
240 /* Same with LONGEST_MAX. */
241
242 LONGEST l_max = LONGEST_MAX;
243
244 store_and_read_back (l_max, sizeof (LONGEST), BFD_ENDIAN_BIG,
245 expected, actual);
246 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
247
248 store_and_read_back (l_max, sizeof (LONGEST), BFD_ENDIAN_LITTLE,
249 expected, actual);
250 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
251
252 /* Same with the smallest ULONGEST. */
253
254 ULONGEST ul_min = 0;
255
256 store_and_read_back (ul_min, sizeof (ULONGEST), BFD_ENDIAN_BIG,
257 expected, actual);
258 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
259
260 store_and_read_back (ul_min, sizeof (ULONGEST), BFD_ENDIAN_LITTLE,
261 expected, actual);
262 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
263
264 /* Same with ULONGEST_MAX. */
265
266 ULONGEST ul_max = ULONGEST_MAX;
267
268 store_and_read_back (ul_max, sizeof (ULONGEST), BFD_ENDIAN_BIG,
269 expected, actual);
270 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
271
272 store_and_read_back (ul_max, sizeof (ULONGEST), BFD_ENDIAN_LITTLE,
273 expected, actual);
274 SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
275 }
276
277 /* A helper function which creates a gdb_mpz object from the given
278 integer VAL, and then writes it using its gdb_mpz::write method.
279
280 The written value is then extracted from the buffer and returned,
281 for comparison with the original.
282
283 Note that this function does not perform the comparison between
284 VAL and the returned value. The caller will do it inside a SELF_CHECK
285 call, allowing the line information shown when the test fails
286 to provide a bit more information about the kind of values
287 that were used when the check failed. This makes the writing
288 of the tests a little more verbose, but the debugging in case
289 of problems should hopefuly be easier. */
290
291 template<typename T>
292 T
293 write_and_extract (T val, size_t buf_len, enum bfd_endian byte_order)
294 {
295 gdb_mpz v (val);
296
297 SELF_CHECK (v.as_integer<T> () == val);
298
299 gdb_byte *buf = (gdb_byte *) alloca (buf_len);
300 v.write ({buf, buf_len}, byte_order, !std::is_signed<T>::value);
301
302 return extract_integer<T> ({buf, buf_len}, byte_order);
303 }
304
305 /* Test the gdb_mpz::write method over a reasonable range of values.
306
307 The testing is done by picking an arbitrary buffer length, after
308 which we test every possible value that this buffer allows. */
309
310 static void
311 gdb_mpz_write_all_from_small ()
312 {
313 int buf_len = 1;
314 LONGEST l_min = -pow (2.0, buf_len * 8 - 1);
315 LONGEST l_max = pow (2.0, buf_len * 8 - 1) - 1;
316
317 for (LONGEST l = l_min; l <= l_max; l++)
318 {
319 SELF_CHECK (write_and_extract (l, buf_len, BFD_ENDIAN_BIG) == l);
320 SELF_CHECK (write_and_extract (l, buf_len, BFD_ENDIAN_LITTLE) == l);
321 }
322
323 /* Do the same as above, but with an unsigned type. */
324 ULONGEST ul_min = 0;
325 ULONGEST ul_max = pow (2.0, buf_len * 8) - 1;
326
327 for (ULONGEST ul = ul_min; ul <= ul_max; ul++)
328 {
329 SELF_CHECK (write_and_extract (ul, buf_len, BFD_ENDIAN_BIG) == ul);
330 SELF_CHECK (write_and_extract (ul, buf_len, BFD_ENDIAN_LITTLE) == ul);
331 }
332 }
333
334 /* Test the gdb_mpz::write the extremes of LONGEST and ULONGEST. */
335
336 static void
337 gdb_mpz_write_min_max ()
338 {
339 /* Start with the smallest LONGEST. */
340
341 LONGEST l_min = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
342 SELF_CHECK (write_and_extract (l_min, sizeof (LONGEST), BFD_ENDIAN_BIG)
343 == l_min);
344 SELF_CHECK (write_and_extract (l_min, sizeof (LONGEST), BFD_ENDIAN_LITTLE)
345 == l_min);
346
347 /* Same with LONGEST_MAX. */
348
349 LONGEST l_max = LONGEST_MAX;
350 SELF_CHECK (write_and_extract (l_max, sizeof (LONGEST), BFD_ENDIAN_BIG)
351 == l_max);
352 SELF_CHECK (write_and_extract (l_max, sizeof (LONGEST), BFD_ENDIAN_LITTLE)
353 == l_max);
354
355 /* Same with the smallest ULONGEST. */
356
357 ULONGEST ul_min = (ULONGEST) 1 << (sizeof (ULONGEST) * 8 - 1);
358 SELF_CHECK (write_and_extract (ul_min, sizeof (ULONGEST), BFD_ENDIAN_BIG)
359 == ul_min);
360 SELF_CHECK (write_and_extract (ul_min, sizeof (ULONGEST), BFD_ENDIAN_LITTLE)
361 == ul_min);
362
363 /* Same with ULONGEST_MAX. */
364
365 ULONGEST ul_max = ULONGEST_MAX;
366 SELF_CHECK (write_and_extract (ul_max, sizeof (ULONGEST), BFD_ENDIAN_BIG)
367 == ul_max);
368 SELF_CHECK (write_and_extract (ul_max, sizeof (ULONGEST), BFD_ENDIAN_LITTLE)
369 == ul_max);
370 }
371
372 /* A helper function which stores the signed number, the unscaled value
373 of a fixed point object, into a buffer, and then uses gdb_mpq's
374 read_fixed_point to read it as a fixed_point value, with
375 the given parameters.
376
377 EXPECTED is set to the value we expected to get after the call
378 to read_fixed_point. ACTUAL is the value we actually do get.
379
380 Note that this function does not perform the comparison between
381 EXPECTED and ACTUAL. The caller will do it inside a SELF_CHECK
382 call, allowing the line information shown when the test fails
383 to provide a bit more information about the kind of values
384 that were used when the check failed. This makes the writing
385 of the tests a little more verbose, but the debugging in case
386 of problems should hopefuly be easier. */
387
388 static void
389 read_fp_test (int unscaled, const gdb_mpq &scaling_factor,
390 enum bfd_endian byte_order,
391 gdb_mpq &expected, gdb_mpq &actual)
392 {
393 /* For this kind of testing, we'll use a buffer the same size as
394 our unscaled parameter. */
395 const size_t len = sizeof (unscaled);
396 gdb_byte buf[len];
397 store_signed_integer (buf, len, byte_order, unscaled);
398
399 actual.read_fixed_point ({buf, len}, byte_order, 0, scaling_factor);
400
401 mpq_set_si (expected.val, unscaled, 1);
402 mpq_mul (expected.val, expected.val, scaling_factor.val);
403 }
404
405 /* Perform various tests of the gdb_mpq::read_fixed_point method. */
406
407 static void
408 gdb_mpq_read_fixed_point ()
409 {
410 gdb_mpq expected, actual;
411 gdb_mpq scaling_factor;
412
413 /* Pick an arbitrary scaling_factor; this operation is trivial enough
414 thanks to GMP that the value we use isn't really important. */
415 mpq_set_ui (scaling_factor.val, 3, 5);
416
417 /* Try a few values, both negative and positive... */
418
419 read_fp_test (-256, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
420 SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
421 read_fp_test (-256, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
422 SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
423
424 read_fp_test (-1, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
425 SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
426 read_fp_test (-1, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
427 SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
428
429 read_fp_test (0, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
430 SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
431 read_fp_test (0, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
432 SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
433
434 read_fp_test (1, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
435 SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
436 read_fp_test (1, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
437 SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
438
439 read_fp_test (1025, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
440 SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
441 read_fp_test (1025, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
442 SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
443 }
444
445 /* A helper function which builds a gdb_mpq object from the given
446 NUMERATOR and DENOMINATOR, and then calls gdb_mpq's write_fixed_point
447 method to write it to a buffer.
448
449 The value written into the buffer is then read back as is,
450 and returned. */
451
452 static LONGEST
453 write_fp_test (int numerator, unsigned int denominator,
454 const gdb_mpq &scaling_factor,
455 enum bfd_endian byte_order)
456 {
457 /* For this testing, we'll use a buffer the size of LONGEST.
458 This is really an arbitrary decision, as long as the buffer
459 is long enough to hold the unscaled values that we'll be
460 writing. */
461 const size_t len = sizeof (LONGEST);
462 gdb_byte buf[len];
463 memset (buf, 0, len);
464
465 gdb_mpq v;
466 mpq_set_si (v.val, numerator, denominator);
467 mpq_canonicalize (v.val);
468 v.write_fixed_point ({buf, len}, byte_order, 0, scaling_factor);
469
470 return extract_unsigned_integer (buf, len, byte_order);
471 }
472
473 /* Perform various tests of the gdb_mpq::write_fixed_point method. */
474
475 static void
476 gdb_mpq_write_fixed_point ()
477 {
478 /* Pick an arbitrary factor; this operations is sufficiently trivial
479 with the use of GMP that the value of this factor is not really
480 all that important. */
481 gdb_mpq scaling_factor;
482 mpq_set_ui (scaling_factor.val, 1, 3);
483
484 gdb_mpq vq;
485
486 /* Try a few multiples of the scaling factor, both negative,
487 and positive... */
488
489 SELF_CHECK (write_fp_test (-8, 1, scaling_factor, BFD_ENDIAN_BIG) == -24);
490 SELF_CHECK (write_fp_test (-8, 1, scaling_factor, BFD_ENDIAN_LITTLE) == -24);
491
492 SELF_CHECK (write_fp_test (-2, 3, scaling_factor, BFD_ENDIAN_BIG) == -2);
493 SELF_CHECK (write_fp_test (-2, 3, scaling_factor, BFD_ENDIAN_LITTLE) == -2);
494
495 SELF_CHECK (write_fp_test (0, 3, scaling_factor, BFD_ENDIAN_BIG) == 0);
496 SELF_CHECK (write_fp_test (0, 3, scaling_factor, BFD_ENDIAN_LITTLE) == 0);
497
498 SELF_CHECK (write_fp_test (5, 3, scaling_factor, BFD_ENDIAN_BIG) == 5);
499 SELF_CHECK (write_fp_test (5, 3, scaling_factor, BFD_ENDIAN_LITTLE) == 5);
500 }
501
502 }
503
504 void _initialize_gmp_utils_selftests ();
505
506 void
507 _initialize_gmp_utils_selftests ()
508 {
509 selftests::register_test ("gdb_mpz_as_integer",
510 selftests::gdb_mpz_as_integer);
511 selftests::register_test ("gdb_mpz_as_integer_out_of_range",
512 selftests::gdb_mpz_as_integer_out_of_range);
513 selftests::register_test ("gdb_mpz_read_all_from_small",
514 selftests::gdb_mpz_read_all_from_small);
515 selftests::register_test ("gdb_mpz_read_min_max",
516 selftests::gdb_mpz_read_min_max);
517 selftests::register_test ("gdb_mpz_write_all_from_small",
518 selftests::gdb_mpz_write_all_from_small);
519 selftests::register_test ("gdb_mpz_write_min_max",
520 selftests::gdb_mpz_write_min_max);
521 selftests::register_test ("gdb_mpq_read_fixed_point",
522 selftests::gdb_mpq_read_fixed_point);
523 selftests::register_test ("gdb_mpq_write_fixed_point",
524 selftests::gdb_mpq_write_fixed_point);
525 }