[02/13] Introduce attribute::signed_constant

Message ID 20250320-attribute-madness-v1-2-79d42789f881@adacore.com
State New
Headers
Series More work on DW_FORM_* and sign handling |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 fail Patch failed to apply
linaro-tcwg-bot/tcwg_gdb_build--master-arm fail Patch failed to apply

Commit Message

Tom Tromey March 20, 2025, 7:26 p.m. UTC
  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    | 30 ++++++++++++++++++++++++++++++
 gdb/dwarf2/attribute.h    |  9 +++++++++
 gdbsupport/common-utils.h | 10 ++++++++++
 3 files changed, 49 insertions(+)
  

Patch

diff --git a/gdb/dwarf2/attribute.c b/gdb/dwarf2/attribute.c
index 49c0bc07d75dd23f5b4f952f4ccb7c46cebc5265..25cf2b62cfd1c8f4981be2787fe4ade8c8c66b81 100644
--- a/gdb/dwarf2/attribute.c
+++ b/gdb/dwarf2/attribute.c
@@ -185,6 +185,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
 {
diff --git a/gdb/dwarf2/attribute.h b/gdb/dwarf2/attribute.h
index ce6c5639c1ae25644844447399988648842d8f58..6f321a53844141f408f45e99f16608eb86f33e6b 100644
--- a/gdb/dwarf2/attribute.h
+++ b/gdb/dwarf2/attribute.h
@@ -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.
diff --git a/gdbsupport/common-utils.h b/gdbsupport/common-utils.h
index 114342d845d8d76ce919e7c0518ab1251e7f2d5b..316ce89af23b926f10cb6a6fdda6621a7d4e507c 100644
--- a/gdbsupport/common-utils.h
+++ b/gdbsupport/common-utils.h
@@ -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);