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
This commit is contained in:
Tom Tromey
2025-02-24 12:26:36 -07:00
parent 5f90d44355
commit 3d0e5b9992
3 changed files with 49 additions and 0 deletions

View 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
{

View 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.

View 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);