Don't edit bogus sh_link on reading relocatable objects (Oracle fix)
[binutils-gdb.git] / gdb / gmp-utils.h
index 59965e504c54cc5c6aad529450c206006eea2770..c1b6fb3abf1be00a32f1dbc3141992b290d31fa7 100644 (file)
@@ -1,6 +1,6 @@
 /* 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.
 
@@ -96,17 +96,19 @@ struct gdb_mpz
      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.  */
@@ -119,6 +121,24 @@ private:
 
   /* 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.  */
@@ -167,24 +187,26 @@ struct gdb_mpq
   /* 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;
 
@@ -213,13 +235,13 @@ struct gdb_mpf
      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);
   }
 
@@ -254,26 +276,12 @@ template<typename T>
 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;
 }