From 3d0e5b99929b0192abfd8dc12b37ac6eaf7fdfd1 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Mon, 24 Feb 2025 12:26:36 -0700 Subject: [PATCH] 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 --- gdb/dwarf2/attribute.c | 30 ++++++++++++++++++++++++++++++ gdb/dwarf2/attribute.h | 9 +++++++++ gdbsupport/common-utils.h | 10 ++++++++++ 3 files changed, 49 insertions(+) diff --git a/gdb/dwarf2/attribute.c b/gdb/dwarf2/attribute.c index 2d14ebdc6c0..7d6372d1574 100644 --- a/gdb/dwarf2/attribute.c +++ b/gdb/dwarf2/attribute.c @@ -186,6 +186,36 @@ attribute::unsigned_constant () const /* See attribute.h. */ +std::optional +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 ec4f3d81f76..460cbcf264a 100644 --- a/gdb/dwarf2/attribute.h +++ b/gdb/dwarf2/attribute.h @@ -114,6 +114,15 @@ struct attribute returned. */ std::optional 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 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 a168458786d..10bf9f49e2a 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); -- 2.39.5