blob: 39ec5b4c96ee74ab0d5f8692d8e8f21fe1db52f8 [file] [log] [blame]
Apply basic patch by David Blaikie to update gold dwp tool to handle
DWARF v5. This is the first of three patches for DWARF v5.
This does the main work of updating dwp to handle DWARF v5.
This patch created for Chrome OS by Caroline Tice.
Date: 19-Nov-2020
diff --git a/gold/dwp.cc b/gold/dwp.cc
index df771e8b..5501985c 100644
--- a/gold/dwp.cc
+++ b/gold/dwp.cc
@@ -22,6 +22,7 @@
#include "dwp.h"
+#include <cassert>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
@@ -31,6 +32,7 @@
#include <vector>
#include <algorithm>
+#include <functional>
#include "getopt.h"
#include "libiberty.h"
@@ -129,6 +131,11 @@ class Dwo_file
bool
verify(const File_list& files);
+ void
+ remap_str_offsets(
+ unsigned int cu_version, unsigned int offset_size,
+ const std::vector<std::pair<unsigned char*, section_size_type> >& str_offs);
+
private:
// Types for mapping input string offsets to output string offsets.
typedef std::pair<section_offset_type, section_offset_type>
@@ -204,16 +211,23 @@ class Dwo_file
// Copy a section from the input file to the output file.
Section_bounds
- copy_section(Dwp_output_file* output_file, unsigned int shndx,
- elfcpp::DW_SECT section_id);
+ copy_section(
+ Dwp_output_file* output_file, unsigned int shndx,
+ elfcpp::DW_SECT section_id,
+ std::vector<std::pair<unsigned char*, section_size_type> >& str_offs);
// Remap the string offsets in the .debug_str_offsets.dwo section.
- const unsigned char*
- remap_str_offsets(const unsigned char* contents, section_size_type len);
+ void
+ remap_str_offsets(unsigned char* contents, section_size_type len);
+
+ // void
+ //remap_str_offsets(
+ // unsigned int cu_version, unsigned int offset_size,
+ // const std::vector<std::pair<unsigned char*, section_size_type> >& str_offs);
template <bool big_endian>
- const unsigned char*
- sized_remap_str_offsets(const unsigned char* contents, section_size_type len);
+ void
+ sized_remap_str_offsets(unsigned char* contents, section_size_type len);
// Remap a single string offsets from an offset in the input string table
// to an offset in the output string table.
@@ -452,7 +466,7 @@ class Dwp_output_file
abiversion_(0), fd_(NULL), next_file_offset_(0), shnum_(1), sections_(),
section_id_map_(), shoff_(0), shstrndx_(0), have_strings_(false),
stringpool_(), shstrtab_(), cu_index_(), tu_index_(), last_type_sig_(0),
- last_tu_slot_(0)
+ last_tu_slot_(0), index_version_(0)
{
this->section_id_map_.resize(elfcpp::DW_SECT_MAX + 1);
this->stringpool_.set_no_zero_null();
@@ -484,6 +498,20 @@ class Dwp_output_file
void
add_tu_set(Unit_set* tu_set);
+ bool
+ update_index_version(unsigned int version)
+ {
+ // Translate the DWARF version to a Split DWARF index version.
+ if (version < 5)
+ version = 2;
+ if (version > 5)
+ gold_fatal(_("unsupported DWARF version"));
+ if (index_version_ != 0 && version != index_version_)
+ return false;
+ index_version_ = version;
+ return true;
+ }
+
// Finalize the file, write the string tables and index sections,
// and close the file.
void
@@ -677,6 +705,7 @@ class Dwp_output_file
uint64_t last_type_sig_;
// Cache of the slot index for the last type signature.
unsigned int last_tu_slot_;
+ unsigned int index_version_;
};
// A specialization of Dwarf_info_reader, for reading dwo_names from
@@ -704,22 +733,47 @@ class Dwo_name_info_reader : public Dwarf_info_reader
protected:
// Visit a compilation unit.
virtual void
- visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die*);
+ visit_compilation_unit(off_t cu_offset, off_t cu_length, uint64_t signature,
+ Dwarf_die*);
private:
// The list of files to populate.
File_list* files_;
};
+class remap_callback
+{
+ public:
+
+ remap_callback(std::vector<std::pair<unsigned char*, section_size_type> > offsets, Dwo_file* dwo_file)
+ : str_offs_(offsets), dwo_file_(dwo_file)
+ { }
+
+ void
+ run_remap(unsigned int cu_version, unsigned int offset_size)
+ {
+ dwo_file_->remap_str_offsets(cu_version, offset_size, str_offs_);
+ }
+
+ virtual ~remap_callback()
+ { }
+
+ std::vector<std::pair<unsigned char*, section_size_type> > str_offs_;
+ Dwo_file *dwo_file_;
+};
+
// A specialization of Dwarf_info_reader, for reading DWARF CUs and TUs
// and adding them to the output file.
class Unit_reader : public Dwarf_info_reader
{
public:
- Unit_reader(bool is_type_unit, Relobj* object, unsigned int shndx)
+ Unit_reader(bool is_type_unit, Relobj* object, unsigned int shndx,
+ // std::function<void(unsigned int, unsigned int)> remap_str_offsets)
+ remap_callback* remap_str_offsets)
: Dwarf_info_reader(is_type_unit, object, NULL, 0, shndx, 0, 0),
- output_file_(NULL), sections_(NULL)
+ output_file_(NULL), sections_(NULL),
+ remap_str_offsets_(remap_str_offsets)
{ }
~Unit_reader()
@@ -732,7 +786,8 @@ class Unit_reader : public Dwarf_info_reader
protected:
// Visit a compilation unit.
virtual void
- visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die*);
+ visit_compilation_unit(off_t cu_offset, off_t cu_length, uint64_t signature,
+ Dwarf_die*);
// Visit a type unit.
virtual void
@@ -740,8 +795,13 @@ class Unit_reader : public Dwarf_info_reader
uint64_t signature, Dwarf_die*);
private:
+ Unit_set*
+ make_unit(off_t cu_length, uint64_t signature);
+
Dwp_output_file* output_file_;
Section_bounds* sections_;
+ //std::function<void(unsigned int, unsigned int)> remap_str_offsets_;
+ remap_callback *remap_str_offsets_;
};
// Return the name of a DWARF .dwo section.
@@ -750,15 +810,29 @@ static const char*
get_dwarf_section_name(elfcpp::DW_SECT section_id)
{
static const char* dwarf_section_names[] = {
- NULL, // unused
- ".debug_info.dwo", // DW_SECT_INFO = 1
- ".debug_types.dwo", // DW_SECT_TYPES = 2
- ".debug_abbrev.dwo", // DW_SECT_ABBREV = 3
- ".debug_line.dwo", // DW_SECT_LINE = 4
- ".debug_loc.dwo", // DW_SECT_LOC = 5
- ".debug_str_offsets.dwo", // DW_SECT_STR_OFFSETS = 6
- ".debug_macinfo.dwo", // DW_SECT_MACINFO = 7
- ".debug_macro.dwo", // DW_SECT_MACRO = 8
+ NULL, // unused
+ ".debug_info.dwo", // DW_SECT_INFO = 1
+ NULL, // unused
+ ".debug_abbrev.dwo", // DW_SECT_ABBREV = 3
+ ".debug_line.dwo", // DW_SECT_LINE = 4
+ ".debug_loclists.dwo", // DW_SECT_LOCLISTS = 5
+ ".debug_str_offsets.dwo", // DW_SECT_STR_OFFSETS = 6
+ ".debug_macro.dwo", // DW_SECT_MACRO = 7
+ ".debug_rnglists.dwo", // DW_SECT_RNGLISTS = 8
+ NULL, // unused
+ NULL, // unused
+ NULL, // unused
+ NULL, // unused
+ NULL, // unused
+ NULL, // unused
+ NULL, // unused
+ NULL, // unused
+ NULL, // unused
+ NULL, // unused
+ NULL, // unused
+ ".debug_types.dwo", // LEGACY_DW_SECT_TYPES = 20
+ ".debug_loc.dwo", // LEGACY_DW_SECT_LOC = 21
+ ".debug_macinfo.dwo", // LEGACY_DW_SECT_MACINFO = 22
};
gold_assert(section_id > 0 && section_id <= elfcpp::DW_SECT_MAX);
@@ -925,16 +999,20 @@ Dwo_file::read(Dwp_output_file* output_file)
debug_shndx[elfcpp::DW_SECT_ABBREV] = i;
else if (strcmp(suffix, "line.dwo") == 0)
debug_shndx[elfcpp::DW_SECT_LINE] = i;
+ else if (strcmp(suffix, "loclists.dwo") == 0)
+ debug_shndx[elfcpp::DW_SECT_LOCLISTS] = i;
else if (strcmp(suffix, "loc.dwo") == 0)
- debug_shndx[elfcpp::DW_SECT_LOC] = i;
+ debug_shndx[elfcpp::LEGACY_DW_SECT_LOC] = i;
else if (strcmp(suffix, "str.dwo") == 0)
debug_str = i;
else if (strcmp(suffix, "str_offsets.dwo") == 0)
debug_shndx[elfcpp::DW_SECT_STR_OFFSETS] = i;
- else if (strcmp(suffix, "macinfo.dwo") == 0)
- debug_shndx[elfcpp::DW_SECT_MACINFO] = i;
else if (strcmp(suffix, "macro.dwo") == 0)
debug_shndx[elfcpp::DW_SECT_MACRO] = i;
+ else if (strcmp(suffix, "rnglists.dwo") == 0)
+ debug_shndx[elfcpp::DW_SECT_RNGLISTS] = i;
+ else if (strcmp(suffix, "macinfo.dwo") == 0)
+ debug_shndx[elfcpp::LEGACY_DW_SECT_MACINFO] = i;
else if (strcmp(suffix, "cu_index") == 0)
debug_cu_index = i;
else if (strcmp(suffix, "tu_index") == 0)
@@ -956,9 +1034,9 @@ Dwo_file::read(Dwp_output_file* output_file)
gold_fatal(_("%s: .dwp file must have no more than one "
".debug_types.dwo section"), this->name_);
if (debug_types.size() == 1)
- debug_shndx[elfcpp::DW_SECT_TYPES] = debug_types[0];
+ debug_shndx[elfcpp::LEGACY_DW_SECT_TYPES] = debug_types[0];
else
- debug_shndx[elfcpp::DW_SECT_TYPES] = 0;
+ debug_shndx[elfcpp::LEGACY_DW_SECT_TYPES] = 0;
this->read_unit_index(debug_tu_index, debug_shndx, output_file, true);
}
return;
@@ -973,7 +1051,7 @@ Dwo_file::read(Dwp_output_file* output_file)
tp != debug_types.end();
++tp)
{
- debug_shndx[elfcpp::DW_SECT_TYPES] = *tp;
+ debug_shndx[elfcpp::LEGACY_DW_SECT_TYPES] = *tp;
this->add_unit_set(output_file, debug_shndx, true);
}
}
@@ -1127,6 +1205,72 @@ Dwo_file::read_unit_index(unsigned int shndx, unsigned int *debug_shndx,
is_tu_index);
}
+unsigned int
+get_unit_version(const unsigned char* unit_start, unsigned int unit_length,
+ bool is_big_endian, unsigned int* offset_size)
+{
+ if (unit_length < 4)
+ return 0;
+
+ unsigned int length = elfcpp::Swap_unaligned<32, true>::readval(unit_start);
+ unsigned int version_offset = 4;
+ *offset_size = 4;
+ if (length == 0xffffffff)
+ {
+ version_offset += 8;
+ *offset_size = 8;
+ }
+ if (unit_length < version_offset + 2)
+ return 0;
+ unit_start += version_offset;
+ return is_big_endian ? elfcpp::Swap_unaligned<16, true>::readval(unit_start)
+ : elfcpp::Swap_unaligned<16, false>::readval(unit_start);
+}
+
+unsigned int
+get_versioned_column_index(unsigned int index_version, unsigned int column)
+{
+ if (index_version == 5)
+ {
+ return column;
+ }
+ switch (column)
+ {
+ case elfcpp::LEGACY_DW_SECT_TYPES:
+ return 2;
+ case elfcpp::LEGACY_DW_SECT_LOC:
+ return 5;
+ case elfcpp::LEGACY_DW_SECT_MACINFO:
+ return 7;
+ case elfcpp::DW_SECT_MACRO:
+ return 8;
+ default:
+ return column;
+ }
+}
+
+unsigned int
+get_uniform_column_index(unsigned int index_version, unsigned int column)
+{
+ if (index_version == 5)
+ {
+ return column;
+ }
+ switch (column)
+ {
+ case 2:
+ return elfcpp::LEGACY_DW_SECT_TYPES;
+ case 5:
+ return elfcpp::LEGACY_DW_SECT_LOC;
+ case 7:
+ return elfcpp::LEGACY_DW_SECT_MACINFO;
+ case 8:
+ return elfcpp::DW_SECT_MACRO;
+ default:
+ return column;
+ }
+}
+
template <bool big_endian>
void
Dwo_file::sized_read_unit_index(unsigned int shndx,
@@ -1134,11 +1278,6 @@ Dwo_file::sized_read_unit_index(unsigned int shndx,
Dwp_output_file* output_file,
bool is_tu_index)
{
- elfcpp::DW_SECT info_sect = (is_tu_index
- ? elfcpp::DW_SECT_TYPES
- : elfcpp::DW_SECT_INFO);
- unsigned int info_shndx = debug_shndx[info_sect];
-
gold_assert(shndx > 0);
section_size_type index_len;
@@ -1152,10 +1291,18 @@ Dwo_file::sized_read_unit_index(unsigned int shndx,
// We don't support version 1 anymore because it was experimental
// and because in normal use, dwp is not expected to read .dwp files
// produced by an earlier version of the tool.
- if (version != 2)
+ if (version != 2 && version != 5)
gold_fatal(_("%s: section %s has unsupported version number %d"),
this->name_, this->section_name(shndx).c_str(), version);
+ elfcpp::DW_SECT info_sect
+ = (is_tu_index && version == 2 ? elfcpp::LEGACY_DW_SECT_TYPES
+ : elfcpp::DW_SECT_INFO);
+ unsigned int info_shndx = debug_shndx[info_sect];
+
+ if (!output_file->update_index_version(version))
+ gold_fatal(_("mismatched unit version in index"));
+
unsigned int ncols =
elfcpp::Swap_unaligned<32, big_endian>::readval(contents
+ sizeof(uint32_t));
@@ -1184,12 +1331,18 @@ Dwo_file::sized_read_unit_index(unsigned int shndx,
// Copy the related sections and track the section offsets and sizes.
Section_bounds sections[elfcpp::DW_SECT_MAX + 1];
- for (int i = elfcpp::DW_SECT_ABBREV; i <= elfcpp::DW_SECT_MAX; ++i)
+ std::vector<std::pair<unsigned char*, section_size_type> > str_offs;
+ for (int i = 1; i <= elfcpp::DW_SECT_MAX; ++i)
{
- if (debug_shndx[i] > 0)
- sections[i] = this->copy_section(output_file, debug_shndx[i],
- static_cast<elfcpp::DW_SECT>(i));
+ if (i != elfcpp::DW_SECT_INFO && i != elfcpp::LEGACY_DW_SECT_TYPES
+ && debug_shndx[i] > 0)
+ sections[i]
+ = this->copy_section(output_file, debug_shndx[i],
+ static_cast<elfcpp::DW_SECT>(i), str_offs);
}
+ if (str_offs.size() > 1)
+ gold_fatal(_("%s: contains more than one .debug_str_offsets.dwo section"),
+ this->name_);
// Get the contents of the .debug_info.dwo or .debug_types.dwo section.
section_size_type info_len;
@@ -1213,13 +1366,15 @@ Dwo_file::sized_read_unit_index(unsigned int shndx,
poffsets + (index - 1) * ncols * sizeof(uint32_t);
const unsigned char* psrow =
psizes + (index - 1) * ncols * sizeof(uint32_t);
+ std::vector<std::pair<unsigned char*, section_size_type> >
+ str_off = str_offs;
// Adjust the offset of each contribution within the input section
// by the offset of the input section within the output section.
- for (unsigned int j = 0; j <= ncols; j++)
+ for (unsigned int j = 0; j < ncols; j++)
{
- unsigned int dw_sect =
- elfcpp::Swap_unaligned<64, big_endian>::readval(pch);
+ unsigned int dw_sect = get_uniform_column_index(
+ version, elfcpp::Swap_unaligned<64, big_endian>::readval(pch));
unsigned int offset =
elfcpp::Swap_unaligned<64, big_endian>::readval(porow);
unsigned int size =
@@ -1230,12 +1385,24 @@ Dwo_file::sized_read_unit_index(unsigned int shndx,
pch += sizeof(uint32_t);
porow += sizeof(uint32_t);
psrow += sizeof(uint32_t);
+ if (dw_sect == elfcpp::DW_SECT_STR_OFFSETS && !str_off.empty())
+ {
+ str_off[0].first += offset;
+ str_off[0].second = size;
+ }
}
const unsigned char* unit_start =
info_contents + unit_set->sections[info_sect].offset;
section_size_type unit_length = unit_set->sections[info_sect].size;
+ unsigned int offset_size;
+ if (!str_off.empty())
+ if (unsigned int unit_version
+ = get_unit_version(unit_start, unit_length,
+ this->obj_->is_big_endian(), &offset_size))
+ remap_str_offsets(unit_version, offset_size, str_off);
+
// Dwp_output_file::add_contribution writes the .debug_info.dwo
// section directly to the output file, so we only need to
// duplicate contributions for .debug_types.dwo section.
@@ -1408,8 +1575,9 @@ Dwo_file::add_strings(Dwp_output_file* output_file, unsigned int debug_str)
// the string offsets for the output string table.
Section_bounds
-Dwo_file::copy_section(Dwp_output_file* output_file, unsigned int shndx,
- elfcpp::DW_SECT section_id)
+Dwo_file::copy_section(
+ Dwp_output_file* output_file, unsigned int shndx, elfcpp::DW_SECT section_id,
+ std::vector<std::pair<unsigned char*, section_size_type> >& str_offs)
{
// Some sections may be referenced from more than one set.
// Don't copy a section more than once.
@@ -1424,20 +1592,19 @@ Dwo_file::copy_section(Dwp_output_file* output_file, unsigned int shndx,
bool is_new;
const unsigned char* contents = this->section_contents(shndx, &len, &is_new);
- if (section_id == elfcpp::DW_SECT_STR_OFFSETS)
- {
- const unsigned char* remapped = this->remap_str_offsets(contents, len);
- if (is_new)
- delete[] contents;
- contents = remapped;
- }
- else if (!is_new)
+ if (!is_new)
{
unsigned char* copy = new unsigned char[len];
memcpy(copy, contents, len);
contents = copy;
}
+ if (section_id == elfcpp::DW_SECT_STR_OFFSETS)
+ {
+ str_offs.push_back(
+ std::make_pair(const_cast<unsigned char*>(contents), len));
+ }
+
// Add the contents of the input section to the output section.
// The output file takes ownership of the memory pointed to by CONTENTS.
section_offset_type off = output_file->add_contribution(section_id, contents,
@@ -1451,38 +1618,33 @@ Dwo_file::copy_section(Dwp_output_file* output_file, unsigned int shndx,
}
// Remap the
-const unsigned char*
-Dwo_file::remap_str_offsets(const unsigned char* contents,
- section_size_type len)
+void
+Dwo_file::remap_str_offsets(unsigned char* contents, section_size_type len)
{
if ((len & 3) != 0)
gold_fatal(_("%s: .debug_str_offsets.dwo section size not a multiple of 4"),
this->name_);
if (this->obj_->is_big_endian())
- return this->sized_remap_str_offsets<true>(contents, len);
+ this->sized_remap_str_offsets<true>(contents, len);
else
- return this->sized_remap_str_offsets<false>(contents, len);
+ this->sized_remap_str_offsets<false>(contents, len);
}
template <bool big_endian>
-const unsigned char*
-Dwo_file::sized_remap_str_offsets(const unsigned char* contents,
+void
+Dwo_file::sized_remap_str_offsets(unsigned char* contents,
section_size_type len)
{
- unsigned char* remapped = new unsigned char[len];
- const unsigned char* p = contents;
- unsigned char* q = remapped;
+ unsigned char* p = contents;
while (len > 0)
{
unsigned int val = elfcpp::Swap_unaligned<32, big_endian>::readval(p);
val = this->remap_str_offset(val);
- elfcpp::Swap_unaligned<32, big_endian>::writeval(q, val);
+ elfcpp::Swap_unaligned<32, big_endian>::writeval(p, val);
len -= 4;
p += 4;
- q += 4;
}
- return remapped;
}
unsigned int
@@ -1491,10 +1653,10 @@ Dwo_file::remap_str_offset(section_offset_type val)
Str_offset_map_entry entry;
entry.first = val;
- Str_offset_map::const_iterator p =
- std::lower_bound(this->str_offset_map_.begin(),
- this->str_offset_map_.end(),
- entry, Offset_compare());
+ Str_offset_map::const_iterator p
+ = std::lower_bound(this->str_offset_map_.begin(),
+ this->str_offset_map_.end(), entry,
+ Offset_compare());
if (p == this->str_offset_map_.end() || p->first > val)
{
@@ -1510,13 +1672,40 @@ Dwo_file::remap_str_offset(section_offset_type val)
// Add a set of .debug_info.dwo or .debug_types.dwo and related sections
// to OUTPUT_FILE.
+void
+Dwo_file::remap_str_offsets(
+ unsigned int cu_version, unsigned int offset_size,
+ const std::vector<std::pair<unsigned char*, section_size_type> >& str_offs)
+{
+ unsigned int header_size = 0;
+ if (cu_version >= 5)
+ {
+ // length field
+ if (offset_size == 4)
+ header_size = 4;
+ else
+ header_size = 12;
+ // version
+ header_size += 2;
+ // padding
+ header_size += 2;
+ }
+
+ std::pair<unsigned char*, section_size_type> p;
+ for (unsigned int i = 0; i < str_offs.size(); ++i)
+ {
+ p = str_offs[i];
+ this->remap_str_offsets(p.first + header_size, p.second - header_size);
+ }
+}
+
void
Dwo_file::add_unit_set(Dwp_output_file* output_file, unsigned int *debug_shndx,
bool is_debug_types)
{
- unsigned int shndx = (is_debug_types
- ? debug_shndx[elfcpp::DW_SECT_TYPES]
- : debug_shndx[elfcpp::DW_SECT_INFO]);
+ elfcpp::DW_SECT info_sect
+ = (is_debug_types ? elfcpp::LEGACY_DW_SECT_TYPES : elfcpp::DW_SECT_INFO);
+ unsigned int shndx = debug_shndx[info_sect];
gold_assert(shndx != 0);
@@ -1525,17 +1714,24 @@ Dwo_file::add_unit_set(Dwp_output_file* output_file, unsigned int *debug_shndx,
// Copy the related sections and track the section offsets and sizes.
Section_bounds sections[elfcpp::DW_SECT_MAX + 1];
- for (int i = elfcpp::DW_SECT_ABBREV; i <= elfcpp::DW_SECT_MAX; ++i)
+ std::vector<std::pair<unsigned char*, section_size_type> > str_offs;
+ for (int i = 1; i <= elfcpp::DW_SECT_MAX; ++i)
{
- if (debug_shndx[i] > 0)
- sections[i] = this->copy_section(output_file, debug_shndx[i],
- static_cast<elfcpp::DW_SECT>(i));
- }
+ if (debug_shndx[i] > 0 && i != info_sect)
+ sections[i]
+ = this->copy_section(output_file, debug_shndx[i],
+ static_cast<elfcpp::DW_SECT>(i), str_offs);
+ }
// Parse the .debug_info or .debug_types section and add each compilation
// or type unit to the output file, along with the contributions to the
// related sections.
- Unit_reader reader(is_debug_types, this->obj_, shndx);
+ remap_callback remap_str_offsets_callback(str_offs, this);
+ Unit_reader reader(is_debug_types, this->obj_, shndx,
+ & remap_str_offsets_callback);
+ // [&](unsigned int cu_version, unsigned int offset_size) {
+ // remap_str_offsets(cu_version, offset_size, str_offs);
+ // });
reader.add_units(output_file, debug_shndx[elfcpp::DW_SECT_ABBREV], sections);
}
@@ -1992,8 +2188,20 @@ Dwp_output_file::write_index(const char* sect_name, const Dwp_index& index)
// Write the section header: version number, padding,
// number of used slots and total number of slots.
- elfcpp::Swap_unaligned<32, big_endian>::writeval(p, 2);
- p += sizeof(uint32_t);
+ if (index_version_ == 2)
+ {
+ elfcpp::Swap_unaligned<32, big_endian>::writeval(p, index_version_);
+ p += sizeof(uint32_t);
+ }
+ else
+ {
+ assert(index_version_ == 5);
+ elfcpp::Swap_unaligned<16, big_endian>::writeval(p, index_version_);
+ p += sizeof(uint16_t);
+ // zero padding
+ *p++ = 0;
+ *p++ = 0;
+ }
elfcpp::Swap_unaligned<32, big_endian>::writeval(p, ncols);
p += sizeof(uint32_t);
elfcpp::Swap_unaligned<32, big_endian>::writeval(p, nused);
@@ -2020,7 +2228,8 @@ Dwp_output_file::write_index(const char* sect_name, const Dwp_index& index)
{
if (column_mask & (1 << c))
{
- elfcpp::Swap_unaligned<32, big_endian>::writeval(p, c);
+ elfcpp::Swap_unaligned<32, big_endian>::writeval(
+ p, get_versioned_column_index(index_version_, c));
p += sizeof(uint32_t);
}
}
@@ -2208,12 +2417,16 @@ Dwp_output_file::sized_write_shdr(const char* name, unsigned int type,
// Visit a compilation unit.
void
-Dwo_name_info_reader::visit_compilation_unit(off_t, off_t, Dwarf_die* die)
+Dwo_name_info_reader::visit_compilation_unit(off_t, off_t, uint64_t signature,
+ Dwarf_die* die)
{
- const char* dwo_name = die->string_attribute(elfcpp::DW_AT_GNU_dwo_name);
+ bool dwarf_5 = cu_version() >= 5;
+ const char* dwo_name = die->string_attribute(
+ dwarf_5 ? elfcpp::DW_AT_dwo_name : elfcpp::DW_AT_GNU_dwo_name);
if (dwo_name != NULL)
{
- uint64_t dwo_id = die->uint_attribute(elfcpp::DW_AT_GNU_dwo_id);
+ uint64_t dwo_id
+ = dwarf_5 ? signature : die->uint_attribute(elfcpp::DW_AT_GNU_dwo_id);
this->files_->push_back(Dwo_file_entry(dwo_id, dwo_name));
}
}
@@ -2236,15 +2449,29 @@ Unit_reader::add_units(Dwp_output_file* output_file,
// Visit a compilation unit.
void
-Unit_reader::visit_compilation_unit(off_t, off_t cu_length, Dwarf_die* die)
+Unit_reader::visit_compilation_unit(off_t, off_t cu_length, uint64_t signature,
+ Dwarf_die* die)
{
if (cu_length == 0)
return;
+ this->remap_str_offsets_->run_remap(cu_version(), offset_size());
+
+ Unit_set* unit_set
+ = make_unit(cu_length, cu_version() >= 5
+ ? signature
+ : die->uint_attribute(elfcpp::DW_AT_GNU_dwo_id));
+ this->output_file_->add_cu_set(unit_set);
+}
+
+Unit_set*
+Unit_reader::make_unit(off_t cu_length, uint64_t signature)
+{
Unit_set* unit_set = new Unit_set();
- unit_set->signature = die->uint_attribute(elfcpp::DW_AT_GNU_dwo_id);
- for (unsigned int i = elfcpp::DW_SECT_ABBREV; i <= elfcpp::DW_SECT_MAX; ++i)
- unit_set->sections[i] = this->sections_[i];
+ unit_set->signature = signature;
+ for (unsigned int i = 1; i <= elfcpp::DW_SECT_MAX; ++i)
+ if (i != elfcpp::DW_SECT_INFO)
+ unit_set->sections[i] = this->sections_[i];
// Dwp_output_file::add_contribution writes the .debug_info.dwo section
// directly to the output file, so we do not need to duplicate the
@@ -2255,7 +2482,9 @@ Unit_reader::visit_compilation_unit(off_t, off_t cu_length, Dwarf_die* die)
cu_length, 1);
Section_bounds bounds(off, cu_length);
unit_set->sections[elfcpp::DW_SECT_INFO] = bounds;
- this->output_file_->add_cu_set(unit_set);
+ if (!this->output_file_->update_index_version(this->cu_version()))
+ gold_fatal(_("mismatched unit version in compilation unit"));
+ return unit_set;
}
// Visit a type unit.
@@ -2268,20 +2497,29 @@ Unit_reader::visit_type_unit(off_t, off_t tu_length, off_t,
return;
if (this->output_file_->lookup_tu(signature))
return;
+ if (this->cu_version() >= 5)
+ {
+ Unit_set* unit_set = make_unit(tu_length, signature);
+ this->output_file_->add_tu_set(unit_set);
+ return;
+ }
Unit_set* unit_set = new Unit_set();
unit_set->signature = signature;
- for (unsigned int i = elfcpp::DW_SECT_ABBREV; i <= elfcpp::DW_SECT_MAX; ++i)
- unit_set->sections[i] = this->sections_[i];
+ for (unsigned int i = 1; i <= elfcpp::DW_SECT_MAX; ++i)
+ if (i != elfcpp::LEGACY_DW_SECT_TYPES)
+ unit_set->sections[i] = this->sections_[i];
unsigned char* contents = new unsigned char[tu_length];
memcpy(contents, this->buffer_at_offset(0), tu_length);
- section_offset_type off =
- this->output_file_->add_contribution(elfcpp::DW_SECT_TYPES, contents,
- tu_length, 1);
+ elfcpp::DW_SECT section = elfcpp::LEGACY_DW_SECT_TYPES;
+ section_offset_type off
+ = this->output_file_->add_contribution(section, contents, tu_length, 1);
Section_bounds bounds(off, tu_length);
- unit_set->sections[elfcpp::DW_SECT_TYPES] = bounds;
+ unit_set->sections[section] = bounds;
this->output_file_->add_tu_set(unit_set);
+ if (!this->output_file_->update_index_version(this->cu_version()))
+ gold_fatal(_("mismatched unit version in type unit")); // FIXME: Untested
}
}; // End namespace gold
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 8307e57e..0bf24e79 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -1525,7 +1525,7 @@ find_cu_tu_set_v2 (dwarf_vma cu_offset, int do_types)
{
p = tu_sets;
nsets = tu_count;
- dw_sect = DW_SECT_TYPES;
+ dw_sect = LEGACY_DW_SECT_TYPES;
}
else
{
@@ -1931,7 +1931,7 @@ read_and_display_attr_value (unsigned long attribute,
debug_info_p->max_loc_offsets = lmax;
}
if (this_set != NULL)
- uvalue += this_set->section_offsets [DW_SECT_LOC];
+ uvalue += this_set->section_offsets [LEGACY_DW_SECT_LOC];
debug_info_p->loc_offsets [num] = uvalue;
debug_info_p->have_frame_base [num] = have_frame_base;
debug_info_p->num_loc_offsets++;
@@ -2538,8 +2538,8 @@ process_debug_info (struct dwarf_section *section,
dwarf_vmatoa ("x", offsets [DW_SECT_LINE]),
dwarf_vmatoa ("x", sizes [DW_SECT_LINE]));
printf (_(" .debug_loc.dwo: 0x%s 0x%s\n"),
- dwarf_vmatoa ("x", offsets [DW_SECT_LOC]),
- dwarf_vmatoa ("x", sizes [DW_SECT_LOC]));
+ dwarf_vmatoa ("x", offsets [LEGACY_DW_SECT_LOC]),
+ dwarf_vmatoa ("x", sizes [LEGACY_DW_SECT_LOC]));
printf (_(" .debug_str_offsets.dwo: 0x%s 0x%s\n"),
dwarf_vmatoa ("x", offsets [DW_SECT_STR_OFFSETS]),
dwarf_vmatoa ("x", sizes [DW_SECT_STR_OFFSETS]));
@@ -7390,17 +7390,17 @@ get_DW_SECT_short_name (unsigned int dw_sect)
{
case DW_SECT_INFO:
return "info";
- case DW_SECT_TYPES:
+ case LEGACY_DW_SECT_TYPES:
return "types";
case DW_SECT_ABBREV:
return "abbrev";
case DW_SECT_LINE:
return "line";
- case DW_SECT_LOC:
+ case LEGACY_DW_SECT_LOC:
return "loc";
case DW_SECT_STR_OFFSETS:
return "str_off";
- case DW_SECT_MACINFO:
+ case LEGACY_DW_SECT_MACINFO:
return "macinfo";
case DW_SECT_MACRO:
return "macro";
diff --git a/elfcpp/dwarf.h b/elfcpp/dwarf.h
index f3873594..13e065e5 100644
--- a/elfcpp/dwarf.h
+++ b/elfcpp/dwarf.h
@@ -104,6 +104,19 @@ namespace elfcpp
#undef DW_CFA
#undef DW_END_CFA
+/* Unit types in unit_type unit header field. */
+enum dwarf_unit_type
+ {
+ DW_UT_compile = 0x01,
+ DW_UT_type = 0x02,
+ DW_UT_partial = 0x03,
+ DW_UT_skeleton = 0x04,
+ DW_UT_split_compile = 0x05,
+ DW_UT_split_type = 0x06,
+ DW_UT_lo_user = 0x80,
+ DW_UT_hi_user = 0xff
+ };
+
// Frame unwind information.
enum DW_EH_PE
@@ -237,15 +250,18 @@ enum DW_LANG
enum DW_SECT
{
DW_SECT_INFO = 1,
- DW_SECT_TYPES = 2,
+ DW_SECT_TYPES = 2, // removed in v5
DW_SECT_ABBREV = 3,
DW_SECT_LINE = 4,
- DW_SECT_LOC = 5,
+ DW_SECT_LOCLISTS = 5, // was LOC pre-v5
DW_SECT_STR_OFFSETS = 6,
- DW_SECT_MACINFO = 7,
- DW_SECT_MACRO = 8,
- DW_SECT_MAX = DW_SECT_MACRO,
-};
+ DW_SECT_MACRO = 7, // was MACINFO pre-v5
+ DW_SECT_RNGLISTS = 8, // was MACRO pre-v5
+ LEGACY_DW_SECT_TYPES = 20,
+ LEGACY_DW_SECT_LOC = 21,
+ LEGACY_DW_SECT_MACINFO = 22,
+ DW_SECT_MAX = LEGACY_DW_SECT_MACINFO
+};
enum DW_LNCT
{
diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc
index 6c2b0082..f0f0d913 100644
--- a/gold/dwarf_reader.cc
+++ b/gold/dwarf_reader.cc
@@ -1299,6 +1299,21 @@ Dwarf_info_reader::do_parse()
elfcpp::Swap_unaligned<16, big_endian>::readval(pinfo);
pinfo += 2;
+ unsigned char unit_type;
+ if (this->cu_version_ >= 5)
+ {
+ // Read unit type (1 byte).
+ unit_type = elfcpp::Swap_unaligned<8, big_endian>::readval(pinfo);
+ pinfo += 1;
+
+ // unit_type should be either DW_UT_split_compile or DW_UT_split_type
+ this->is_type_unit_ = unit_type == elfcpp::DW_UT_split_type;
+
+ // Read address_size (1 byte).
+ this->address_size_ = *pinfo++;
+ }
+
+ // For type units, read the two extra fields.
// Read debug_abbrev_offset (4 or 8 bytes).
if (this->offset_size_ == 4)
abbrev_offset = elfcpp::Swap_unaligned<32, big_endian>::readval(pinfo);
@@ -1319,29 +1334,37 @@ Dwarf_info_reader::do_parse()
}
pinfo += this->offset_size_;
- // Read address_size (1 byte).
- this->address_size_ = *pinfo++;
+ if (this->cu_version_ < 5)
+ {
+ // Read address_size (1 byte).
+ this->address_size_ = *pinfo++;
+ }
// For type units, read the two extra fields.
uint64_t signature = 0;
off_t type_offset = 0;
- if (this->is_type_unit_)
+ if (this->is_type_unit_ || this->cu_version_ >= 5)
{
- if (!this->check_buffer(pinfo + 8 + this->offset_size_))
+ if (!this->check_buffer(pinfo + 8))
break;
// Read type_signature (8 bytes).
signature = elfcpp::Swap_unaligned<64, big_endian>::readval(pinfo);
pinfo += 8;
- // Read type_offset (4 or 8 bytes).
- if (this->offset_size_ == 4)
- type_offset =
- elfcpp::Swap_unaligned<32, big_endian>::readval(pinfo);
- else
- type_offset =
- elfcpp::Swap_unaligned<64, big_endian>::readval(pinfo);
- pinfo += this->offset_size_;
+ if (this->is_type_unit_)
+ {
+ if (!this->check_buffer(pinfo + this->offset_size_))
+ break;
+ // Read type_offset (4 or 8 bytes).
+ if (this->offset_size_ == 4)
+ type_offset
+ = elfcpp::Swap_unaligned<32, big_endian>::readval(pinfo);
+ else
+ type_offset
+ = elfcpp::Swap_unaligned<64, big_endian>::readval(pinfo);
+ pinfo += this->offset_size_;
+ }
}
// Read the .debug_abbrev table.
@@ -1361,7 +1384,8 @@ Dwarf_info_reader::do_parse()
&root_die);
else
this->visit_compilation_unit(section_offset + this->cu_offset_,
- cu_end - cu_start, &root_die);
+ cu_end - cu_start, signature,
+ &root_die);
}
// Advance to the next CU.
@@ -1494,7 +1518,7 @@ Dwarf_info_reader::get_string(off_t str_off, unsigned int string_shndx)
// Process a compilation unit and parse its child DIE.
void
-Dwarf_info_reader::visit_compilation_unit(off_t, off_t, Dwarf_die*)
+Dwarf_info_reader::visit_compilation_unit(off_t, off_t, uint64_t, Dwarf_die*)
{
}
diff --git a/gold/dwarf_reader.h b/gold/dwarf_reader.h
index 90a799ed..087b88aa 100644
--- a/gold/dwarf_reader.h
+++ b/gold/dwarf_reader.h
@@ -764,7 +764,11 @@ class Dwarf_info_reader
address_size() const
{ return this->address_size_; }
- // Set the section index of the .debug_abbrev section.
+ unsigned int
+ cu_version() const
+ { return this->cu_version_; }
+
+ // Set the section index of the .debug_abbrev section.
// We use this if there are no relocations for the .debug_info section.
// If not set, the code parse() routine will search for the section by name.
void
@@ -800,7 +804,8 @@ class Dwarf_info_reader
// Visit a compilation unit.
virtual void
- visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die* root_die);
+ visit_compilation_unit(off_t cu_offset, off_t cu_length, uint64_t signature,
+ Dwarf_die* root_die);
// Visit a type unit.
virtual void
diff --git a/gold/gdb-index.cc b/gold/gdb-index.cc
index e1df0698..cdf80d1e 100644
--- a/gold/gdb-index.cc
+++ b/gold/gdb-index.cc
@@ -199,7 +199,8 @@ class Gdb_index_info_reader : public Dwarf_info_reader
protected:
// Visit a compilation unit.
virtual void
- visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die*);
+ visit_compilation_unit(off_t cu_offset, off_t cu_length, uint64_t signature,
+ Dwarf_die*);
// Visit a type unit.
virtual void
@@ -319,6 +320,7 @@ unsigned int Gdb_index_info_reader::dwarf_tu_nopubnames_count = 0;
void
Gdb_index_info_reader::visit_compilation_unit(off_t cu_offset, off_t cu_length,
+ uint64_t signature,
Dwarf_die* root_die)
{
++Gdb_index_info_reader::dwarf_cu_count;
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 4d479f6e..69b3ba91 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -311,6 +311,7 @@ DW_AT (DW_AT_const_expr, 0x6c)
DW_AT (DW_AT_enum_class, 0x6d)
DW_AT (DW_AT_linkage_name, 0x6e)
/* DWARF 5. */
+DW_AT (DW_AT_dwo_name, 0x76)
DW_AT (DW_AT_noreturn, 0x87)
DW_AT_DUP (DW_AT_lo_user, 0x2000) /* Implementation-defined range start. */
diff --git a/include/dwarf2.h b/include/dwarf2.h
index 9e69cd5a..7248db64 100644
--- a/include/dwarf2.h
+++ b/include/dwarf2.h
@@ -411,14 +411,17 @@ enum dwarf_macro_record_type
enum dwarf_sect
{
DW_SECT_INFO = 1,
- DW_SECT_TYPES = 2,
+ DW_SECT_TYPES = 2, // removed in v5
DW_SECT_ABBREV = 3,
DW_SECT_LINE = 4,
- DW_SECT_LOC = 5,
+ DW_SECT_LOCLISTS = 5, // was LOC pre-v5
DW_SECT_STR_OFFSETS = 6,
- DW_SECT_MACINFO = 7,
- DW_SECT_MACRO = 8,
- DW_SECT_MAX = 8
+ DW_SECT_MACRO = 7, // was MACINFO pre-v5
+ DW_SECT_RNGLISTS = 8, // was MACRO pre-v5
+ LEGACY_DW_SECT_TYPES = 20,
+ LEGACY_DW_SECT_LOC = 21,
+ LEGACY_DW_SECT_MACINFO = 22,
+ DW_SECT_MAX = LEGACY_DW_SECT_MACINFO
};
#ifdef __cplusplus