From: Tom de Vries Date: Tue, 11 Nov 2025 21:34:24 +0000 (+0100) Subject: [gdb/rust] Fix handling of unsigned discriminant X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0c103861db6f9d33c1b415d0d34ee812746ebb41;p=thirdparty%2Fbinutils-gdb.git [gdb/rust] Fix handling of unsigned discriminant On i686-linux, with test-case gdb.rust/simple.exp, we get: ... (gdb) print str_none^M $71 = core::option::Option::Some(alloc::string::String {vec: alloc::vec::Vec {buf: alloc::raw_vec::RawVec {inner: alloc::raw_vec::RawVecInner {ptr: core::ptr::unique::Unique {pointer: core::ptr::non_null::NonNull {pointer: 0xbfffe6e8}, _marker: core::marker::PhantomData}, cap: core::num::niche_types::UsizeNoHighBit (2147483648), alloc: alloc::alloc::Global}, _marker: core::marker::PhantomData}, len: 4321411}})^M (gdb) FAIL: $exp: print str_none ... while this is expected: ... (gdb) print str_none^M $71 = core::option::Option::None^M (gdb) PASS: $exp: print str_none ... Printing the variable in C mode: ... $ gdb -q -batch outputs/gdb.rust/simple/simple \ -ex "b 161" \ -ex run \ -ex "set language c" \ -ex "p /x str_none" ... $1 = {0x80000000, Some = {__0 = {vec = {buf = {inner = {ptr = {pointer = {pointer = 0xbfffedd8}, _marker = {}}, cap = {__0 = 0x80000000}, alloc = {}}, _marker = {}}, len = 0x41f083}}}} ... shows us that the discriminant value is 0x80000000, which matches the "None" variant: ... <3><1427>: Abbrev Number: 16 (DW_TAG_structure_type) <1428> DW_AT_name : Option <142c> DW_AT_byte_size : 12 <142d> DW_AT_accessibility: 1 (public) <142e> DW_AT_alignment : 4 <4><142f>: Abbrev Number: 47 (DW_TAG_variant_part) <1430> DW_AT_discr : <0x1434> <5><1434>: Abbrev Number: 48 (DW_TAG_member) <1435> DW_AT_type : <0x2cba> <1439> DW_AT_alignment : 4 <143a> DW_AT_data_member_location: 0 <143b> DW_AT_artificial : 1 <5><143b>: Abbrev Number: 52 (DW_TAG_variant) <143c> DW_AT_discr_value : 0x80000000 <6><1440>: Abbrev Number: 4 (DW_TAG_member) <1441> DW_AT_name : None <1445> DW_AT_type : <0x145a> <1449> DW_AT_alignment : 4 <144a> DW_AT_data_member_location: 0 <6><144b>: Abbrev Number: 0 <5><144c>: Abbrev Number: 51 (DW_TAG_variant) <6><144d>: Abbrev Number: 4 (DW_TAG_member) <144e> DW_AT_name : Some <1452> DW_AT_type : <0x146c> <1456> DW_AT_alignment : 4 <1457> DW_AT_data_member_location: 0 <6><1458>: Abbrev Number: 0 <5><1459>: Abbrev Number: 0 ... but the dynamic type resolves to the "Some" variant instead. This is caused by signedness confusion. The DW_AT_discr_value 0x80000000 is encoded as an LEB128 number, and the signedness is determined by the "tag type for the variant part", which in this case is unsigned: ... <1><2cba>: Abbrev Number: 6 (DW_TAG_base_type) <2cbb> DW_AT_name : u32 <2cbf> DW_AT_encoding : 7 (unsigned) <2cc0> DW_AT_byte_size : 4 ... However, the value gets interpreted as signed instead (value printed in resolve_dynamic_struct): ... (gdb) p /x variant_prop.m_data.variant_parts.m_array.variants.m_array[0].discriminants.m_array[0] $3 = {low = 0xffffffff80000000, high = 0xffffffff80000000} ... and then compared against an unsigned 0x80000000 in variant::matches(). Fix this in create_one_variant_part, by passing the required signedness as a parameter to create_one_variant. Tested on i686-linux and x86_64-linux. Approved-By: Tom Tromey PR rust/33620 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33620 --- diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index df6e784025d..29f100b7638 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -10439,14 +10439,16 @@ static const gdb::array_view create_variant_parts the variant to fill in. OBSTACK is where any needed allocations will be done. OFFSET_MAP holds the mapping from section offsets to fields for the type. FI describes the fields of the type we're - processing. FIELD is the variant field we're converting. */ + processing. FIELD is the variant field we're converting. IS_UNSIGNED + contains the signedness of the discriminant. */ static void create_one_variant (variant &result, struct obstack *obstack, const offset_map_type &offset_map, - struct field_info *fi, const variant_field &field) + struct field_info *fi, const variant_field &field, + bool is_unsigned) { - result.discriminants = convert_variant_range (obstack, field, false); + result.discriminants = convert_variant_range (obstack, field, is_unsigned); result.first_field = field.first_field + fi->baseclasses.size (); result.last_field = field.last_field + fi->baseclasses.size (); result.parts = create_variant_parts (obstack, offset_map, fi, @@ -10485,7 +10487,7 @@ create_one_variant_part (variant_part &result, variant *output = new (obstack) variant[n]; for (size_t i = 0; i < n; ++i) create_one_variant (output[i], obstack, offset_map, fi, - builder.variants[i]); + builder.variants[i], result.is_unsigned); result.variants = gdb::array_view (output, n); }