]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Introduce attribute::signed_constant
authorTom Tromey <tromey@adacore.com>
Mon, 24 Feb 2025 19:26:36 +0000 (12:26 -0700)
committerTom Tromey <tromey@adacore.com>
Thu, 24 Apr 2025 19:25:08 +0000 (13:25 -0600)
This introduces a new method, attribute::signed_constant.  This should
be used wherever DWARF specifies a signed integer constant, or where
this is implied by the context.  It properly handles sign-extension
for DW_FORM_data*.

To my surprise, there doesn't seem to be a pre-existing sign-extension
function.  I've added one to common-utils.h alongside the align
functions.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32680

gdb/dwarf2/attribute.c
gdb/dwarf2/attribute.h
gdbsupport/common-utils.h

index 2d14ebdc6c0d466a178b2a08c7d4e1ae4aa18f99..7d6372d15745d87b0b6fc354b9c231f2337872d9 100644 (file)
@@ -186,6 +186,36 @@ attribute::unsigned_constant () const
 
 /* See attribute.h.  */
 
+std::optional<LONGEST>
+attribute::signed_constant () const
+{
+  if (form_is_strictly_signed ())
+    return u.snd;
+
+  switch (form)
+    {
+    case DW_FORM_data8:
+    case DW_FORM_udata:
+      /* Not sure if DW_FORM_udata should be handled or not.  Anyway
+        for DW_FORM_data8, there's no need to sign-extend.  */
+      return u.snd;
+
+    case DW_FORM_data1:
+      return sign_extend (u.unsnd, 8);
+    case DW_FORM_data2:
+      return sign_extend (u.unsnd, 16);
+    case DW_FORM_data4:
+      return sign_extend (u.unsnd, 32);
+    }
+
+  /* For DW_FORM_data16 see attribute::form_is_constant.  */
+  complaint (_("Attribute value is not a constant (%s)"),
+            dwarf_form_name (form));
+  return {};
+}
+
+/* See attribute.h.  */
+
 bool
 attribute::form_is_unsigned () const
 {
index ec4f3d81f769cf982d1652047403ce3089a7b321..460cbcf264a72b26ba1ea9e4618f46fa8f1ff82b 100644 (file)
@@ -114,6 +114,15 @@ struct attribute
      returned.  */
   std::optional<ULONGEST> unsigned_constant () const;
 
+  /* Return a signed constant value.  This only handles constant forms
+     (i.e., form_is_constant -- and not the extended list of
+     "unsigned" forms) and assumes a signed value is desired.  This
+     function will sign-extend DW_FORM_data* values.
+
+     If non-constant form is used, then complaint is issued and an
+     empty value is returned.  */
+  std::optional<LONGEST> signed_constant () const;
+
   /* Return non-zero if ATTR's value falls in the 'constant' class, or
      zero otherwise.  When this function returns true, you can apply
      the constant_value method to it.
index a168458786d4742fae54c1f82cca700fd56e4c04..10bf9f49e2a469d7d18f2bf990fdf602d5589e85 100644 (file)
@@ -196,6 +196,16 @@ in_inclusive_range (T value, T low, T high)
 extern ULONGEST align_up (ULONGEST v, int n);
 extern ULONGEST align_down (ULONGEST v, int n);
 
+/* Sign-extend the value V, using N as the number of valid bits.  That
+   is, bit N-1 is the sign bit.  The higher-order bits (those outside
+   0..N-1) must be zero.  */
+static inline ULONGEST
+sign_extend (ULONGEST v, int n)
+{
+  ULONGEST mask = (ULONGEST) 1 << (n - 1);
+  return (v ^ mask) - mask;
+}
+
 /* Convert hex digit A to a number, or throw an exception.  */
 extern int fromhex (int a);