#include "addrmap.h"
#include "cli/cli-decode.h"
+#include "cli/cli-style.h"
#include "exceptions.h"
#include "gdbsupport/byte-vector.h"
#include "gdbsupport/enumerate.h"
#include "dwarf2/tag.h"
#include "dwarf2/read-debug-names.h"
#include "extract-store-integer.h"
+#include "ui-out.h"
#include <algorithm>
#include <map>
addrmap_index_data.previous_cu_index);
}
+/* Is this symbol a compile unit, local type unit (type unit in the main file)
+ or foreign type unit (type unit in a .dwo file)? */
+enum class unit_kind { cu, local_tu, foreign_tu };
+
/* Return true if TU is a foreign type unit, that is a type unit defined in a
.dwo file without a corresponding skeleton in the main file. */
return endswith (tu->section ()->get_name (), ".dwo");
}
+/* Determine the unit_kind for PER_CU. */
+
+static unit_kind
+classify_unit (const dwarf2_per_cu &per_cu)
+{
+ if (auto sig_type = per_cu.as_signatured_type (); sig_type != nullptr)
+ {
+ if (is_foreign_tu (sig_type))
+ return unit_kind::foreign_tu;
+ else
+ return unit_kind::local_tu;
+ }
+ else
+ return unit_kind::cu;
+}
+
/* DWARF-5 .debug_names builder. */
class debug_names
{
return dwarf5_is_dwarf64 ? 8 : 4;
}
- /* Is this symbol from DW_TAG_compile_unit or DW_TAG_type_unit? */
- enum class unit_kind { cu, tu };
-
/* Insert one symbol. */
void insert (const cooked_index_entry *entry)
{
for (dwarf2_per_cu *one_cu : per_cus)
{
- unit_kind kind = (entry->per_cu->is_debug_types ()
- ? unit_kind::tu
- : unit_kind::cu);
+ unit_kind kind = classify_unit (*one_cu);
+
/* Some Ada parentage is synthesized by the reader and so
must be ignored here. */
const cooked_index_entry *parent = entry->get_parent ();
: DW_IDX_type_unit);
m_abbrev_table.append_unsigned_leb128 (DW_FORM_udata);
+ /* For foreign TUs only: the index of a CU that can be used
+ to locate the .dwo file containing that TU. */
+ if (kind == unit_kind::foreign_tu)
+ {
+ m_abbrev_table.append_unsigned_leb128
+ (DW_IDX_compile_unit);
+ m_abbrev_table.append_unsigned_leb128 (DW_FORM_udata);
+ }
+
/* DIE offset. */
m_abbrev_table.append_unsigned_leb128 (DW_IDX_die_offset);
m_abbrev_table.append_unsigned_leb128 (DW_FORM_ref_addr);
gdb_assert (it != m_cu_index_htab.cend ());
m_entry_pool.append_unsigned_leb128 (it->second);
+ /* For foreign TUs only: the index of a CU that can be used to
+ locate the .dwo file containing that TU.
+
+ This code implements this snippet of the DWARF 5 standard,
+ from section 6.1.1.2, "Structure of the Name Index":
+
+ When an index entry refers to a foreign type unit, it may
+ have attributes for both CU and (foreign) TU. For such
+ entries, the CU attribute gives the consumer a reference
+ to the CU that may be used to locate a split DWARF object
+ file that contains the type unit
+
+ So, the idea here is to find a CU in the same .dwo file as
+ the type unit (there will typically be one) and write the
+ offset to its skeleton. */
+ if (kind == unit_kind::foreign_tu)
+ {
+ /* If we know about this TU that is only listed in some .dwo
+ file, it means that we looked up the .dwo file from a CU
+ skeleton at some point during indexing, and recorded it
+ in ENTRY->PER_CU. */
+ gdb_assert (entry->per_cu != nullptr);
+
+ signatured_type *sig_type
+ = entry->per_cu->as_signatured_type ();
+
+ /* We know it's a TU, because it has been classified as
+ foreign_tu. */
+ gdb_assert (sig_type != nullptr);
+
+ /* We know it has a dwo_unit, because it's foreign. */
+ gdb_assert (sig_type->dwo_unit != nullptr);
+
+ /* Find a CU in the same .dwo file as the TU. */
+ dwarf2_per_cu *per_cu = nullptr;
+ for (auto &dwo_cu : sig_type->dwo_unit->dwo_file->cus)
+ if (dwo_cu->per_cu != nullptr)
+ {
+ per_cu = dwo_cu->per_cu;
+ break;
+ }
+
+ /* It would be really weird to not find a CU that we looked
+ up in this .dwo file. Otherwise, how would we know about
+ this foreign TU? But it might be possible to craft a bad
+ faith .dwo file that does this by having a one TU with a
+ skeleton and one TU without a skeleton in the same .dwo
+ file (i.e. non-standard DWARF 5). So, just in case, we
+ error out gracefully. */
+ if (per_cu == nullptr)
+ error (_("Could not find a CU for foreign type unit in "
+ "DWO file %ps"),
+ styled_string (file_name_style.style (),
+ (sig_type->dwo_unit->dwo_file
+ ->dwo_name.c_str ())));
+
+ /* This is the CU that can be used to find the .dwo file
+ containing the type unit, write its offset. */
+ const auto cu_it = m_cu_index_htab.find (per_cu);
+ gdb_assert (cu_it != m_cu_index_htab.cend ());
+ m_entry_pool.append_unsigned_leb128 (cu_it->second);
+ }
+
/* DIE offset. */
m_entry_pool.append_uint (dwarf5_offset_size (),
m_dwarf5_byte_order,
/* Compilation units. */
std::vector<const dwarf2_per_cu *> comp;
- /* Type units. */
- std::vector<const signatured_type *> type;
+ /* Type units, local and foreign. */
+ std::vector<const signatured_type *> local_type;
+ std::vector<const signatured_type *> foreign_type;
};
/* Get sorted (by section offset) lists of comp units and type units. */
unit_lists lists;
for (const auto &unit : per_bfd.all_units)
- if (const signatured_type *sig_type = unit->as_signatured_type ();
- sig_type != nullptr)
- lists.type.emplace_back (sig_type);
- else
- lists.comp.emplace_back (unit.get ());
+ switch (classify_unit (*unit))
+ {
+ case unit_kind::cu:
+ lists.comp.emplace_back (unit.get ());
+ break;
+
+ case unit_kind::local_tu:
+ lists.local_type.emplace_back (unit->as_signatured_type ());
+ break;
+
+ case unit_kind::foreign_tu:
+ lists.foreign_type.emplace_back (unit->as_signatured_type ());
+ break;
+ }
auto by_sect_off = [] (const dwarf2_per_cu *lhs, const dwarf2_per_cu *rhs)
{ return lhs->sect_off () < rhs->sect_off (); };
- /* Sort both lists, even though it is technically not always required:
+ auto by_sig = [] (const signatured_type *lhs, const signatured_type *rhs)
+ { return lhs->signature < rhs->signature; };
+
+ /* Sort the lists, even though it is technically not always required:
- while .gdb_index requires the CU list to be sorted, DWARF 5 doesn't
say anything about the order of CUs in .debug_names.
However, it helps make sure that GDB produce a stable and predictable
output, which is nice. */
std::sort (lists.comp.begin (), lists.comp.end (), by_sect_off);
- std::sort (lists.type.begin (), lists.type.end (), by_sect_off);
+ std::sort (lists.local_type.begin (), lists.local_type.end (), by_sect_off);
+ std::sort (lists.foreign_type.begin (), lists.foreign_type.end (), by_sig);
return lists;
}
that DWARF 5's .debug_names does with "foreign type units". If the
executable has such skeletonless type units, refuse to produce an index,
instead of producing a bogus one. */
- for (const signatured_type *tu : units.type)
- if (is_foreign_tu (tu))
- error (_("Found foreign (skeletonless) type unit, unable to produce "
- ".gdb_index. Consider using .debug_names instead."));
+ if (!units.foreign_type.empty ())
+ error (_("Found foreign (skeletonless) type unit, unable to produce "
+ ".gdb_index. Consider using .debug_names instead."));
int counter = 0;
/* Write type units. */
data_buf types_cu_list;
- for (const signatured_type *sig_type : units.type)
+ for (const signatured_type *sig_type : units.local_type)
{
const auto insertpair = cu_index_htab.emplace (sig_type, counter);
gdb_assert (insertpair.second);
data_buf type_unit_list;
- for (auto [i, per_cu] : gdb::ranges::views::enumerate (units.type))
+ for (auto [i, per_cu] : gdb::ranges::views::enumerate (units.local_type))
{
nametable.add_cu (per_cu, i);
type_unit_list.append_uint (nametable.dwarf5_offset_size (),
to_underlying (per_cu->sect_off ()));
}
+ data_buf foreign_type_unit_list;
+
+ for (auto [i, sig_type] : gdb::ranges::views::enumerate (units.foreign_type))
+ {
+ /* The numbering of foreign type units follows the numbering of local type
+ units. */
+ nametable.add_cu (sig_type, units.local_type.size () + i);
+ foreign_type_unit_list.append_uint (8, dwarf5_byte_order,
+ sig_type->signature);
+ }
+
/* Verify that all units are represented. */
gdb_assert (units.comp.size () == per_bfd->num_comp_units);
- gdb_assert (units.type.size () == per_bfd->num_type_units);
+ gdb_assert (units.local_type.size () + units.foreign_type.size ()
+ == per_bfd->num_type_units);
for (const cooked_index_entry *entry : table->all_entries ())
nametable.insert (entry);
expected_bytes += bytes_of_header;
expected_bytes += comp_unit_list.size ();
expected_bytes += type_unit_list.size ();
+ expected_bytes += foreign_type_unit_list.size ();
expected_bytes += nametable.bytes ();
data_buf header;
/* local_type_unit_count - The number of TUs in the local TU
list. */
- header.append_uint (4, dwarf5_byte_order, units.type.size ());
+ header.append_uint (4, dwarf5_byte_order, units.local_type.size ());
/* foreign_type_unit_count - The number of TUs in the foreign TU
list. */
- header.append_uint (4, dwarf5_byte_order, 0);
+ header.append_uint (4, dwarf5_byte_order, units.foreign_type.size ());
/* bucket_count - The number of hash buckets in the hash lookup
table. GDB does not use the hash table, so there's also no need
header.file_write (out_file);
comp_unit_list.file_write (out_file);
type_unit_list.file_write (out_file);
+ foreign_type_unit_list.file_write (out_file);
nametable.file_write (out_file, out_file_str);
assert_file_size (out_file, expected_bytes);