diff options
author | Tom Tromey <tromey@adacore.com> | 2025-02-24 12:26:36 -0700 |
---|---|---|
committer | Tom Tromey <tromey@adacore.com> | 2025-04-24 13:25:08 -0600 |
commit | 3d0e5b99929b0192abfd8dc12b37ac6eaf7fdfd1 (patch) | |
tree | 4f87b0210331b4adfa93776eff74aa43d71174c5 | |
parent | 5f90d44355bdd441cd77db00f414872088952f85 (diff) | |
download | binutils-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.c | 30 | ||||
-rw-r--r-- | gdb/dwarf2/attribute.h | 9 | ||||
-rw-r--r-- | gdbsupport/common-utils.h | 10 |
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); |