/* Miscellaneous routines making it easier to use GMP within GDB's framework.
- Copyright (C) 2019-2020 Free Software Foundation, Inc.
+ Copyright (C) 2019-2021 Free Software Foundation, Inc.
This file is part of GDB.
The return type can signed or unsigned, with no size restriction. */
template<typename T> T as_integer () const;
- /* Set VAL by importing the number stored in the byte buffer (BUF),
- given its size (LEN) and BYTE_ORDER.
+ /* Set VAL by importing the number stored in the byte array (BUF),
+ using the given BYTE_ORDER. The size of the data to read is
+ the byte array's size.
UNSIGNED_P indicates whether the number has an unsigned type. */
- void read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+ void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
bool unsigned_p);
- /* Write VAL into BUF as a LEN-bytes number with the given BYTE_ORDER.
+ /* Write VAL into BUF as a number whose byte size is the size of BUF,
+ using the given BYTE_ORDER.
UNSIGNED_P indicates whether the number has an unsigned type. */
- void write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+ void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
bool unsigned_p) const;
/* Return a string containing VAL. */
/* Helper template for constructor and operator=. */
template<typename T> void set (T src);
+
+ /* Low-level function to export VAL into BUF as a number whose byte size
+ is the size of BUF.
+
+ If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
+ Otherwise, export it as a signed value.
+
+ The API is inspired from GMP's mpz_export, hence the naming and types
+ of the following parameter:
+ - ENDIAN should be:
+ . 1 for most significant byte first; or
+ . -1 for least significant byte first; or
+ . 0 for native endianness.
+
+ An error is raised if BUF is not large enough to contain the value
+ being exported. */
+ void safe_export (gdb::array_view<gdb_byte> buf,
+ int endian, bool unsigned_p) const;
};
/* A class to make it easier to use GMP's mpq_t values within GDB. */
/* Return VAL rounded to the nearest integer. */
gdb_mpz get_rounded () const;
- /* Set VAL from the contents of the given buffer (BUF), which
- contains the unscaled value of a fixed point type object
- with the given size (LEN) and byte order (BYTE_ORDER).
+ /* Set VAL from the contents of the given byte array (BUF), which
+ contains the unscaled value of a fixed point type object.
+ The byte size of the data is the size of BUF.
+
+ BYTE_ORDER provides the byte_order to use when reading the data.
UNSIGNED_P indicates whether the number has an unsigned type.
SCALING_FACTOR is the scaling factor to apply after having
read the unscaled value from our buffer. */
- void read_fixed_point (const gdb_byte *buf, int len,
+ void read_fixed_point (gdb::array_view<const gdb_byte> buf,
enum bfd_endian byte_order, bool unsigned_p,
const gdb_mpq &scaling_factor);
- /* Write VAL into BUF as a LEN-bytes fixed point value following
- the given BYTE_ORDER.
+ /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
+ The size of BUF is used as the length to write the value into.
UNSIGNED_P indicates whether the number has an unsigned type.
SCALING_FACTOR is the scaling factor to apply before writing
the unscaled value to our buffer. */
- void write_fixed_point (gdb_byte *buf, int len,
+ void write_fixed_point (gdb::array_view<gdb_byte> buf,
enum bfd_endian byte_order, bool unsigned_p,
const gdb_mpq &scaling_factor) const;
UNSIGNED_P indicates whether the number has an unsigned type.
SCALING_FACTOR is the scaling factor to apply after having
read the unscaled value from our buffer. */
- void read_fixed_point (const gdb_byte *buf, int len,
+ void read_fixed_point (gdb::array_view<const gdb_byte> buf,
enum bfd_endian byte_order, bool unsigned_p,
const gdb_mpq &scaling_factor)
{
gdb_mpq tmp_q;
- tmp_q.read_fixed_point (buf, len, byte_order, unsigned_p, scaling_factor);
+ tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor);
mpf_set_q (val, tmp_q.val);
}
T
gdb_mpz::as_integer () const
{
- /* Initialize RESULT, because mpz_export only write the minimum
- number of bytes, including none if our value is zero! */
- T result = 0;
+ T result;
- gdb_mpz exported_val (val);
- if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
- {
- /* We want to use mpz_export to set the return value, but
- this function does not handle the sign. So give exported_val
- a value which is at the same time positive, and has the same
- bit representation as our negative value. */
- gdb_mpz neg_offset;
+ this->safe_export ({(gdb_byte *) &result, sizeof (result)},
+ 0 /* endian (0 = native) */,
+ !std::is_signed<T>::value /* unsigned_p */);
- mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
- mpz_add (exported_val.val, exported_val.val, neg_offset.val);
- }
-
- mpz_export (&result, NULL /* count */, -1 /* order */,
- sizeof (T) /* size */, 0 /* endian (0 = native) */,
- 0 /* nails */, exported_val.val);
return result;
}