gmp-utils.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /* Miscellaneous routines making it easier to use GMP within GDB's framework.
  2. Copyright (C) 2019-2022 Free Software Foundation, Inc.
  3. This file is part of GDB.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. #ifndef GMP_UTILS_H
  15. #define GMP_UTILS_H
  16. #include "defs.h"
  17. /* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
  18. access to GMP's various formatting functions. */
  19. #include <stdio.h>
  20. #include <stdarg.h>
  21. #include <gmp.h>
  22. #include "gdbsupport/traits.h"
  23. /* Same as gmp_asprintf, but returning an std::string. */
  24. std::string gmp_string_printf (const char *fmt, ...);
  25. /* A class to make it easier to use GMP's mpz_t values within GDB. */
  26. struct gdb_mpz
  27. {
  28. mpz_t val;
  29. /* Constructors. */
  30. gdb_mpz () { mpz_init (val); }
  31. explicit gdb_mpz (const mpz_t &from_val)
  32. {
  33. mpz_init (val);
  34. mpz_set (val, from_val);
  35. }
  36. gdb_mpz (const gdb_mpz &from)
  37. {
  38. mpz_init (val);
  39. mpz_set (val, from.val);
  40. }
  41. /* Initialize using the given integral value.
  42. The main advantage of this method is that it handles both signed
  43. and unsigned types, with no size restriction. */
  44. template<typename T, typename = gdb::Requires<std::is_integral<T>>>
  45. explicit gdb_mpz (T src)
  46. {
  47. mpz_init (val);
  48. set (src);
  49. }
  50. explicit gdb_mpz (gdb_mpz &&from)
  51. {
  52. mpz_init (val);
  53. mpz_swap (val, from.val);
  54. }
  55. gdb_mpz &operator= (const gdb_mpz &from)
  56. {
  57. mpz_set (val, from.val);
  58. return *this;
  59. }
  60. gdb_mpz &operator= (gdb_mpz &&other)
  61. {
  62. mpz_swap (val, other.val);
  63. return *this;
  64. }
  65. template<typename T, typename = gdb::Requires<std::is_integral<T>>>
  66. gdb_mpz &operator= (T src)
  67. {
  68. set (src);
  69. return *this;
  70. }
  71. /* Convert VAL to an integer of the given type.
  72. The return type can signed or unsigned, with no size restriction. */
  73. template<typename T> T as_integer () const;
  74. /* Set VAL by importing the number stored in the byte array (BUF),
  75. using the given BYTE_ORDER. The size of the data to read is
  76. the byte array's size.
  77. UNSIGNED_P indicates whether the number has an unsigned type. */
  78. void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
  79. bool unsigned_p);
  80. /* Write VAL into BUF as a number whose byte size is the size of BUF,
  81. using the given BYTE_ORDER.
  82. UNSIGNED_P indicates whether the number has an unsigned type. */
  83. void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
  84. bool unsigned_p) const;
  85. /* Return a string containing VAL. */
  86. std::string str () const { return gmp_string_printf ("%Zd", val); }
  87. /* The destructor. */
  88. ~gdb_mpz () { mpz_clear (val); }
  89. private:
  90. /* Helper template for constructor and operator=. */
  91. template<typename T> void set (T src);
  92. /* Low-level function to export VAL into BUF as a number whose byte size
  93. is the size of BUF.
  94. If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
  95. Otherwise, export it as a signed value.
  96. The API is inspired from GMP's mpz_export, hence the naming and types
  97. of the following parameter:
  98. - ENDIAN should be:
  99. . 1 for most significant byte first; or
  100. . -1 for least significant byte first; or
  101. . 0 for native endianness.
  102. An error is raised if BUF is not large enough to contain the value
  103. being exported. */
  104. void safe_export (gdb::array_view<gdb_byte> buf,
  105. int endian, bool unsigned_p) const;
  106. };
  107. /* A class to make it easier to use GMP's mpq_t values within GDB. */
  108. struct gdb_mpq
  109. {
  110. mpq_t val;
  111. /* Constructors. */
  112. gdb_mpq () { mpq_init (val); }
  113. explicit gdb_mpq (const mpq_t &from_val)
  114. {
  115. mpq_init (val);
  116. mpq_set (val, from_val);
  117. }
  118. gdb_mpq (const gdb_mpq &from)
  119. {
  120. mpq_init (val);
  121. mpq_set (val, from.val);
  122. }
  123. explicit gdb_mpq (gdb_mpq &&from)
  124. {
  125. mpq_init (val);
  126. mpq_swap (val, from.val);
  127. }
  128. /* Copy assignment operator. */
  129. gdb_mpq &operator= (const gdb_mpq &from)
  130. {
  131. mpq_set (val, from.val);
  132. return *this;
  133. }
  134. gdb_mpq &operator= (gdb_mpq &&from)
  135. {
  136. mpq_swap (val, from.val);
  137. return *this;
  138. }
  139. /* Return a string representing VAL as "<numerator> / <denominator>". */
  140. std::string str () const { return gmp_string_printf ("%Qd", val); }
  141. /* Return VAL rounded to the nearest integer. */
  142. gdb_mpz get_rounded () const;
  143. /* Set VAL from the contents of the given byte array (BUF), which
  144. contains the unscaled value of a fixed point type object.
  145. The byte size of the data is the size of BUF.
  146. BYTE_ORDER provides the byte_order to use when reading the data.
  147. UNSIGNED_P indicates whether the number has an unsigned type.
  148. SCALING_FACTOR is the scaling factor to apply after having
  149. read the unscaled value from our buffer. */
  150. void read_fixed_point (gdb::array_view<const gdb_byte> buf,
  151. enum bfd_endian byte_order, bool unsigned_p,
  152. const gdb_mpq &scaling_factor);
  153. /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
  154. The size of BUF is used as the length to write the value into.
  155. UNSIGNED_P indicates whether the number has an unsigned type.
  156. SCALING_FACTOR is the scaling factor to apply before writing
  157. the unscaled value to our buffer. */
  158. void write_fixed_point (gdb::array_view<gdb_byte> buf,
  159. enum bfd_endian byte_order, bool unsigned_p,
  160. const gdb_mpq &scaling_factor) const;
  161. /* The destructor. */
  162. ~gdb_mpq () { mpq_clear (val); }
  163. };
  164. /* A class to make it easier to use GMP's mpf_t values within GDB.
  165. Should MPFR become a required dependency, we should probably
  166. drop this class in favor of using MPFR. */
  167. struct gdb_mpf
  168. {
  169. mpf_t val;
  170. /* Constructors. */
  171. gdb_mpf () { mpf_init (val); }
  172. DISABLE_COPY_AND_ASSIGN (gdb_mpf);
  173. /* Set VAL from the contents of the given buffer (BUF), which
  174. contains the unscaled value of a fixed point type object
  175. with the given size (LEN) and byte order (BYTE_ORDER).
  176. UNSIGNED_P indicates whether the number has an unsigned type.
  177. SCALING_FACTOR is the scaling factor to apply after having
  178. read the unscaled value from our buffer. */
  179. void read_fixed_point (gdb::array_view<const gdb_byte> buf,
  180. enum bfd_endian byte_order, bool unsigned_p,
  181. const gdb_mpq &scaling_factor)
  182. {
  183. gdb_mpq tmp_q;
  184. tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor);
  185. mpf_set_q (val, tmp_q.val);
  186. }
  187. /* The destructor. */
  188. ~gdb_mpf () { mpf_clear (val); }
  189. };
  190. /* See declaration above. */
  191. template<typename T>
  192. void
  193. gdb_mpz::set (T src)
  194. {
  195. mpz_import (val, 1 /* count */, -1 /* order */,
  196. sizeof (T) /* size */, 0 /* endian (0 = native) */,
  197. 0 /* nails */, &src /* op */);
  198. if (std::is_signed<T>::value && src < 0)
  199. {
  200. /* mpz_import does not handle the sign, so our value was imported
  201. as an unsigned. Adjust that imported value so as to make it
  202. the correct negative value. */
  203. gdb_mpz neg_offset;
  204. mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
  205. mpz_sub (val, val, neg_offset.val);
  206. }
  207. }
  208. /* See declaration above. */
  209. template<typename T>
  210. T
  211. gdb_mpz::as_integer () const
  212. {
  213. T result;
  214. this->safe_export ({(gdb_byte *) &result, sizeof (result)},
  215. 0 /* endian (0 = native) */,
  216. !std::is_signed<T>::value /* unsigned_p */);
  217. return result;
  218. }
  219. #endif