empty value is returned. */
std::optional<LONGEST> signed_constant () const;
+ /* Return a signed constant value. However, for narrow forms like
+ DW_FORM_data1, sign extension is not done.
+
+ DWARF advises compilers to generally use DW_FORM_[su]data to
+ avoid ambiguity. However, both GCC and LLVM ignore this for
+ certain attributes. Furthermore in DWARF, whether a narrower
+ form causes sign-extension depends on the attribute -- for
+ attributes that can only assume non-negative values, sign
+ extension is not done.
+
+ Unfortunately, both compilers also emit certain attributes in a
+ "confused" way, using DW_FORM_sdata for signed values, and
+ possibly choosing a narrow form (e.g., DW_FORM_data1) otherwise
+ -- assuming that sign-extension will not be done.
+
+ This method should only be called when this "confused" treatment
+ is necessary. */
+ std::optional<LONGEST> confused_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.
if (attr2 != nullptr && attr2->form_is_constant ())
{
has_bit_offset = true;
- bit_offset = attr2->unsigned_constant ().value_or (0);
+ bit_offset = attr2->confused_constant ().value_or (0);
attr2 = dwarf2_attr (die, DW_AT_byte_size, cu);
if (attr2 != nullptr && attr2->form_is_constant ())
{
if (attr->form_is_constant ())
{
- LONGEST offset = attr->unsigned_constant ().value_or (0);
+ LONGEST offset = attr->confused_constant ().value_or (0);
/* Work around this GCC 11 bug, where it would erroneously use -1
data member locations, instead of 0:
return (sym);
}
-/* Given an attr with a DW_FORM_dataN value in host byte order,
- zero-extend it as appropriate for the symbol's type. The DWARF
- standard (v4) is not entirely clear about the meaning of using
- DW_FORM_dataN for a constant with a signed type, where the type is
- wider than the data. The conclusion of a discussion on the DWARF
- list was that this is unspecified. We choose to always zero-extend
- because that is the interpretation long in use by GCC. */
-
-static void
-dwarf2_const_value_data (const struct attribute *attr, LONGEST *value,
- int bits)
-{
- LONGEST l = attr->constant_value (0);
-
- if (bits < sizeof (*value) * 8)
- {
- l &= ((LONGEST) 1 << bits) - 1;
- *value = l;
- }
- else
- *value = l;
-}
-
/* Read a constant value from an attribute. Either set *VALUE, or if
the value does not fit in *VALUE, set *BYTES - either already
allocated on the objfile obstack, or newly allocated on OBSTACK,
converted to host endianness, so we just need to sign- or
zero-extend it as appropriate. */
case DW_FORM_data1:
- dwarf2_const_value_data (attr, value, 8);
- break;
case DW_FORM_data2:
- dwarf2_const_value_data (attr, value, 16);
- break;
case DW_FORM_data4:
- dwarf2_const_value_data (attr, value, 32);
- break;
case DW_FORM_data8:
- dwarf2_const_value_data (attr, value, 64);
- break;
-
case DW_FORM_sdata:
case DW_FORM_implicit_const:
- *value = attr->as_signed ();
- break;
-
case DW_FORM_udata:
- *value = attr->as_unsigned ();
+ *value = attr->confused_constant ().value_or (0);
break;
default:
symbol's value "represented as it would be on the target
architecture." By the time we get here, it's already been
converted to host endianness, so we just need to sign- or
- zero-extend it as appropriate. */
+ zero-extend it as appropriate.
+
+ Both GCC and LLVM agree that these are always signed, though. */
case DW_FORM_data1:
- type = die_type (die, cu);
- dwarf2_const_value_data (attr, &value, 8);
- result = write_constant_as_bytes (obstack, byte_order, type, value, len);
- break;
case DW_FORM_data2:
- type = die_type (die, cu);
- dwarf2_const_value_data (attr, &value, 16);
- result = write_constant_as_bytes (obstack, byte_order, type, value, len);
- break;
case DW_FORM_data4:
- type = die_type (die, cu);
- dwarf2_const_value_data (attr, &value, 32);
- result = write_constant_as_bytes (obstack, byte_order, type, value, len);
- break;
case DW_FORM_data8:
- type = die_type (die, cu);
- dwarf2_const_value_data (attr, &value, 64);
- result = write_constant_as_bytes (obstack, byte_order, type, value, len);
- break;
-
case DW_FORM_sdata:
case DW_FORM_implicit_const:
- type = die_type (die, cu);
- result = write_constant_as_bytes (obstack, byte_order,
- type, attr->as_signed (), len);
- break;
-
case DW_FORM_udata:
type = die_type (die, cu);
- result = write_constant_as_bytes (obstack, byte_order,
- type, attr->as_unsigned (), len);
+ value = attr->confused_constant ().value_or (0);
+ result = write_constant_as_bytes (obstack, byte_order, type, value, len);
break;
default:
--- /dev/null
+# Copyright 2025 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test negative DW_AT_bit_offset.
+
+load_lib "ada.exp"
+
+require allow_ada_tests
+
+standard_ada_testfile prog
+
+# This particular output is only generated with -gdwarf-4.
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable \
+ {debug additional_flags=-gdwarf-4}] != ""} {
+ return
+}
+
+clean_restart ${testfile}
+
+set bp_location [gdb_get_line_number "STOP" ${testdir}/prog.adb]
+runto "prog.adb:$bp_location"
+
+gdb_test "print xp" \
+ [string_to_regexp "(x => 21, y => (-1, -2, -3, -4, -5, -6, -7, -8, -9, -10))"]
--- /dev/null
+-- Copyright 2025 Free Software Foundation, Inc.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+procedure Prog is
+
+ type Small is range -32 .. 31;
+ for Small'Size use 6;
+
+ type SomeArray is array (POSITIVE range <>) of Small;
+
+ type SomePackedArray is array (POSITIVE range <>) of Small;
+ pragma Pack (SomePackedArray);
+
+ type SomePackedRecord is record
+ X: Small;
+ Y: SomePackedArray (1 .. 10);
+ end record;
+ pragma Pack (SomePackedRecord);
+
+ XP: SomePackedRecord := (21, (-1, -2, -3, -4, -5, -6, -7, -8, -9, -10));
+
+begin
+ null; -- STOP
+end;