From: Dodji Seketeli Date: Fri, 7 Apr 2023 10:25:58 +0000 (+0200) Subject: dwarf-reader: Support indirectly referenced subrange_type DIEs X-Git-Tag: upstream/2.3~22 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ff8cba872e581768337db30881ba3764067626c0;p=platform%2Fupstream%2Flibabigail.git dwarf-reader: Support indirectly referenced subrange_type DIEs This is about supporting an Ada-induced DWARF construct related to ranged types. To reproduce the issue this patch originated from, you can type: $ fedabipkgdiff --self-compare -a --from fc37 gprbuild From that gprbuild package from fc37, consider this subrange_type DIE coming from the debuginfo file prtests/gprbuild-2020-11.fc37.aarch64: 1 [ 3c10d] subrange_type abbrev: 34 2 type (ref_addr) [ 6191e] 3 lower_bound (sdata) 2 4 upper_bound (ref_udata) [ 3c0eb] At line 4, look at how the DW_AT_upper_bound attribute is a reference to another DIE, instead of being a (signed) constant value, like the DW_AT_lower_bound attribute at line 3. The referenced DIE is at offset 0x3c0eb. How do we get the actual value of the upper_bound of that subrange type? To answer that question, let's look at the DIE, at offset 0x3c0eb that is referenced by the DW_AT_upper_bound attribute at line 4: 1 [ 3c0eb] member abbrev: 87 2 name (strp) "last" 3 decl_file (data1) a-coinve.ads (35) 4 decl_line (data2) 415 5 decl_column (data1) 24 6 type (ref_udata) [ 3c0f7] It's a data member which type is referenced at line 6. Let's look at that type, which offset is 0x3c0f7: 1 [ 3c0f7] subrange_type abbrev: 122 2 upper_bound (sdata) 99999999 3 name (strp) "gpr__names__name_vectors__T449bXn" 4 type (ref_addr) [ 6191e] 5 artificial (flag_present) yes That type is a DW_TAG_subrange_type and its DW_AT_upper_bound value is a constant. Finally. Actually, the value of DW_AT_upper_bound of this DIE at offset 0x3c0f7 is the value of the DW_AT_upper_bound of the subrange_type DIE at offset 0x3c10d that we were initially looking for. The DIE at 0x3c0f7 is said to be indirectly referenced by the DIE at 0x3c10d, through its DW_AT_upper_bound attribute. This patch supports retrieving the value of the DW_AT_upper_bound of 0x3c10d through the 0x3c0f7 DIE that it indirectly references. The package gprbuild from fc37 now passes self comparison with this patch. * src/abg-dwarf-reader.cc (subrange_die_indirect_bound_value) (subrange_die_indirectly_references_subrange_die): Define new static function. (build_subrange_type): If the value of DW_AT_upper_bound is not a constant, try to consider it as an indirect reference to a DW_TAG_subrange_type DIE, whose DW_AT_upper_bound might carry the constant value that we are looking for. Signed-off-by: Dodji Seketeli --- diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index d5dfc48f..ef1d8a45 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -523,6 +523,16 @@ die_die_attribute(const Dwarf_Die* die, Dwarf_Die& result, bool recursively = true); +static bool +subrange_die_indirect_bound_value(const Dwarf_Die *die, + unsigned attr_name, + array_type_def::subrange_type::bound_value& v, + bool& is_signed); + +static bool +subrange_die_indirectly_references_subrange_die(const Dwarf_Die *die, + unsigned attr_name, + Dwarf_Die& referenced_subrange); static string get_internal_anonymous_die_prefix_name(const Dwarf_Die *die); @@ -6199,6 +6209,110 @@ die_die_attribute(const Dwarf_Die* die, return dwarf_formref_die(&attr, &result); } +/// Test if a subrange DIE indirectly references another subrange DIE +/// through a given attribute. +/// +/// A DW_TAG_subrange_type DIE can have its DW_AT_{lower,upper}_bound +/// attribute be a reference to either a data member or a variable +/// which type is itself a DW_TAG_subrange_type. This latter subrange +/// DIE is said to be "indirectly referenced" by the former subrange +/// DIE. In that case, the DW_AT_{lower,upper}_bound of the latter is +/// the value we want for the DW_AT_upper_bound of the former. +/// +/// This function tests if the former subrange DIE does indirectly +/// reference another subrange DIE through a given attribute (not +/// necessarily DW_AT_upper_bound). +/// +/// @param die the DIE to consider. Note that It must be a +/// DW_TAG_subrange_type. +/// +/// @param attr_name the name of the attribute to look through for the +/// indirectly referenced subrange DIE. +/// +/// @param referenced_subrange if the function returns true, then the +/// argument of this parameter is set to the indirectly referenced +/// DW_TAG_subrange_type DIE. +/// +/// @return true iff @p DIE indirectly references a subrange DIE +/// through the attribute @p attr_name. +static bool +subrange_die_indirectly_references_subrange_die(const Dwarf_Die *die, + unsigned attr_name, + Dwarf_Die& referenced_subrange) +{ + bool result = false; + + if (dwarf_tag(const_cast(die)) != DW_TAG_subrange_type) + return result; + + Dwarf_Die referenced_die; + if (die_die_attribute(die, attr_name, referenced_die)) + { + unsigned tag = dwarf_tag(&referenced_die); + if ( tag == DW_TAG_member || tag == DW_TAG_variable) + { + Dwarf_Die type_die; + if (die_die_attribute(&referenced_die, DW_AT_type, type_die)) + { + tag = dwarf_tag(&type_die); + if (tag == DW_TAG_subrange_type) + { + memcpy(&referenced_subrange, &type_die, sizeof(type_die)); + result = true; + } + } + } + } + return result; +} + +/// Return the bound value of subrange die by looking at an indirectly +/// referenced subrange DIE. +/// +/// A DW_TAG_subrange_type DIE can have its DW_AT_{lower,upper}_bound +/// attribute be a reference to either a data member or a variable +/// which type is itself a DW_TAG_subrange_type. This latter subrange +/// DIE is said to be "indirectly referenced" by the former subrange +/// DIE. In that case, the DW_AT_{lower,upper}_bound of the latter is +/// the value we want for the DW_AT_{lower,upper}_bound of the former. +/// +/// This function gets the DW_AT_{lower,upper}_bound value of a +/// subrange type by looking at the DW_AT_{lower,upper}_bound value of +/// the indirectly referenced subrange type, if it exists. +/// +/// @param die the subrange DIE to consider. +/// +/// @param attr_name the name of the attribute to consider, typically, +/// DW_AT_{lower,upper}_bound. +/// +/// @param v the found value, iff this function returned true. +/// +/// @param is_signed, this is set to true if @p v is signed. This +/// parameter is set at all only if the function returns true. +/// +/// @return true iff the DW_AT_{lower,upper}_bound was found on the +/// indirectly referenced subrange type. +static bool +subrange_die_indirect_bound_value(const Dwarf_Die *die, + unsigned attr_name, + array_type_def::subrange_type::bound_value& v, + bool& is_signed) +{ + bool result = false; + + if (dwarf_tag(const_cast(die)) != DW_TAG_subrange_type) + return result; + + Dwarf_Die subrange_die; + if (subrange_die_indirectly_references_subrange_die(die, attr_name, + subrange_die)) + { + if (die_constant_attribute(&subrange_die, attr_name, is_signed, v)) + result = true; + } + return result; +} + /// Read and return an addresss class attribute from a given DIE. /// /// @param die the DIE to consider. @@ -14162,8 +14276,15 @@ build_subrange_type(reader& rdr, // So let's look for DW_AT_lower_bound first. die_constant_attribute(die, DW_AT_lower_bound, is_signed, lower_bound); + bool found_upper_bound = die_constant_attribute(die, DW_AT_upper_bound, + is_signed, upper_bound); + if (!found_upper_bound) + found_upper_bound = subrange_die_indirect_bound_value(die, + DW_AT_upper_bound, + upper_bound, + is_signed); // Then, DW_AT_upper_bound. - if (!die_constant_attribute(die, DW_AT_upper_bound, is_signed, upper_bound)) + if (!found_upper_bound) { // The DWARF 4 spec says, in [5.11 Subrange Type // Entries]: