aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@adacore.com>2025-02-24 12:26:36 -0700
committerTom Tromey <tromey@adacore.com>2025-04-24 13:25:08 -0600
commit3d0e5b99929b0192abfd8dc12b37ac6eaf7fdfd1 (patch)
tree4f87b0210331b4adfa93776eff74aa43d71174c5
parent5f90d44355bdd441cd77db00f414872088952f85 (diff)
downloadbinutils-3d0e5b99929b0192abfd8dc12b37ac6eaf7fdfd1.zip
binutils-3d0e5b99929b0192abfd8dc12b37ac6eaf7fdfd1.tar.gz
binutils-3d0e5b99929b0192abfd8dc12b37ac6eaf7fdfd1.tar.bz2
Introduce attribute::signed_constant
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
-rw-r--r--gdb/dwarf2/attribute.c30
-rw-r--r--gdb/dwarf2/attribute.h9
-rw-r--r--gdbsupport/common-utils.h10
3 files changed, 49 insertions, 0 deletions
diff --git a/gdb/dwarf2/attribute.c b/gdb/dwarf2/attribute.c
index 2d14ebd..7d6372d 100644
--- a/gdb/dwarf2/attribute.c
+++ b/gdb/dwarf2/attribute.c
@@ -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
{
diff --git a/gdb/dwarf2/attribute.h b/gdb/dwarf2/attribute.h
index ec4f3d8..460cbcf 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 a168458..10bf9f4 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);