#include "elfcpp_swap.h"
#include "dwarf.h"
#include "object.h"
-#include "parameters.h"
#include "reloc.h"
#include "dwarf_reader.h"
#include "int_encoding.h"
unsigned int symndx, Address* value, bool* is_ordinary)
{
const int symsize = elfcpp::Elf_sizes<size>::sym_size;
- gold_assert((symndx + 1) * symsize <= this->symtab_size_);
+ gold_assert(static_cast<off_t>((symndx + 1) * symsize) <= this->symtab_size_);
elfcpp::Sym<size, big_endian> elfsym(this->symtab_ + symndx * symsize);
*value = elfsym.get_st_value();
return this->object_->adjust_sym_shndx(symndx, elfsym.get_st_shndx(),
}
static inline Elf_reloc_mapper*
-make_elf_reloc_mapper(Object* object, const unsigned char* symtab,
+make_elf_reloc_mapper(Relobj* object, const unsigned char* symtab,
off_t symtab_size)
{
- switch (parameters->size_and_endianness())
+ if (object->elfsize() == 32)
{
-#ifdef HAVE_TARGET_32_LITTLE
- case Parameters::TARGET_32_LITTLE:
- return new Sized_elf_reloc_mapper<32, false>(object, symtab,
- symtab_size);
-#endif
+ if (object->is_big_endian())
+ {
#ifdef HAVE_TARGET_32_BIG
- case Parameters::TARGET_32_BIG:
- return new Sized_elf_reloc_mapper<32, true>(object, symtab,
- symtab_size);
+ return new Sized_elf_reloc_mapper<32, true>(object, symtab,
+ symtab_size);
+#else
+ gold_unreachable();
#endif
-#ifdef HAVE_TARGET_64_LITTLE
- case Parameters::TARGET_64_LITTLE:
- return new Sized_elf_reloc_mapper<64, false>(object, symtab,
- symtab_size);
+ }
+ else
+ {
+#ifdef HAVE_TARGET_32_LITTLE
+ return new Sized_elf_reloc_mapper<32, false>(object, symtab,
+ symtab_size);
+#else
+ gold_unreachable();
#endif
+ }
+ }
+ else if (object->elfsize() == 64)
+ {
+ if (object->is_big_endian())
+ {
#ifdef HAVE_TARGET_64_BIG
- case Parameters::TARGET_64_BIG:
- return new Sized_elf_reloc_mapper<64, true>(object, symtab,
- symtab_size);
+ return new Sized_elf_reloc_mapper<64, true>(object, symtab,
+ symtab_size);
+#else
+ gold_unreachable();
#endif
- default:
- gold_unreachable();
+ }
+ else
+ {
+#ifdef HAVE_TARGET_64_LITTLE
+ return new Sized_elf_reloc_mapper<64, false>(object, symtab,
+ symtab_size);
+#else
+ gold_unreachable();
+#endif
+ }
}
+ else
+ gold_unreachable();
}
// class Dwarf_abbrev_table
this->ranges_reloc_mapper_ = make_elf_reloc_mapper(object, symtab,
symtab_size);
this->ranges_reloc_mapper_->initialize(reloc_shndx, reloc_type);
+ this->reloc_type_ = reloc_type;
return true;
}
// Read the raw contents of the section.
if (addr_size == 4)
{
- start = read_from_pointer<32>(this->ranges_buffer_ + offset);
- end = read_from_pointer<32>(this->ranges_buffer_ + offset + 4);
+ start = this->dwinfo_->read_from_pointer<32>(this->ranges_buffer_
+ + offset);
+ end = this->dwinfo_->read_from_pointer<32>(this->ranges_buffer_
+ + offset + 4);
}
else
{
- start = read_from_pointer<64>(this->ranges_buffer_ + offset);
- end = read_from_pointer<64>(this->ranges_buffer_ + offset + 8);
+ start = this->dwinfo_->read_from_pointer<64>(this->ranges_buffer_
+ + offset);
+ end = this->dwinfo_->read_from_pointer<64>(this->ranges_buffer_
+ + offset + 8);
}
// Check for relocations and adjust the values.
unsigned int shndx2 = 0;
if (this->ranges_reloc_mapper_ != NULL)
{
- shndx1 =
- this->ranges_reloc_mapper_->get_reloc_target(offset, &start);
- shndx2 =
- this->ranges_reloc_mapper_->get_reloc_target(offset + addr_size,
- &end);
+ shndx1 = this->lookup_reloc(offset, &start);
+ shndx2 = this->lookup_reloc(offset + addr_size, &end);
}
// End of list is marked by a pair of zeroes.
return ranges;
}
+// Look for a relocation at offset OFF in the range table,
+// and return the section index and offset of the target.
+
+unsigned int
+Dwarf_ranges_table::lookup_reloc(off_t off, off_t* target_off)
+{
+ off_t value;
+ unsigned int shndx =
+ this->ranges_reloc_mapper_->get_reloc_target(off, &value);
+ if (shndx == 0)
+ return 0;
+ if (this->reloc_type_ == elfcpp::SHT_REL)
+ *target_off += value;
+ else
+ *target_off = value;
+ return shndx;
+}
+
// class Dwarf_pubnames_table
-// Read the pubnames section SHNDX from the object file.
+// Read the pubnames section from the object file.
bool
-Dwarf_pubnames_table::read_section(Relobj* object, unsigned int shndx)
+Dwarf_pubnames_table::read_section(Relobj* object, const unsigned char* symtab,
+ off_t symtab_size)
{
section_size_type buffer_size;
+ unsigned int shndx = 0;
- // If we don't have relocations, shndx will be 0, and
- // we'll have to hunt for the .debug_pubnames/pubtypes section.
- if (shndx == 0)
+ // Find the .debug_pubnames/pubtypes section.
+ const char* name = (this->is_pubtypes_
+ ? ".debug_pubtypes"
+ : ".debug_pubnames");
+ for (unsigned int i = 1; i < object->shnum(); ++i)
{
- const char* name = (this->is_pubtypes_
- ? ".debug_pubtypes"
- : ".debug_pubnames");
- for (unsigned int i = 1; i < object->shnum(); ++i)
- {
- if (object->section_name(i) == name)
- {
- shndx = i;
- this->output_section_offset_ = object->output_section_offset(i);
- break;
- }
- }
- if (shndx == 0)
- return false;
+ if (object->section_name(i) == name)
+ {
+ shndx = i;
+ this->output_section_offset_ = object->output_section_offset(i);
+ break;
+ }
}
+ if (shndx == 0)
+ return false;
+
this->buffer_ = object->decompressed_section_contents(shndx,
&buffer_size,
if (this->buffer_ == NULL)
return false;
this->buffer_end_ = this->buffer_ + buffer_size;
+
+ // For incremental objects, we have no relocations.
+ if (object->is_incremental())
+ return true;
+
+ // Find the relocation section
+ unsigned int reloc_shndx = 0;
+ unsigned int reloc_type = 0;
+ for (unsigned int i = 0; i < object->shnum(); ++i)
+ {
+ reloc_type = object->section_type(i);
+ if ((reloc_type == elfcpp::SHT_REL
+ || reloc_type == elfcpp::SHT_RELA)
+ && object->section_info(i) == shndx)
+ {
+ reloc_shndx = i;
+ break;
+ }
+ }
+
+ this->reloc_mapper_ = make_elf_reloc_mapper(object, symtab, symtab_size);
+ this->reloc_mapper_->initialize(reloc_shndx, reloc_type);
+ this->reloc_type_ = reloc_type;
+
return true;
}
bool
Dwarf_pubnames_table::read_header(off_t offset)
{
+ // Make sure we have actually read the section.
+ gold_assert(this->buffer_ != NULL);
+
// Correct the offset. For incremental update links, we have a
// relocated offset that is relative to the output section, but
// here we need an offset relative to the input section.
const unsigned char* pinfo = this->buffer_ + offset;
// Read the unit_length field.
- uint32_t unit_length = read_from_pointer<32>(pinfo);
+ uint64_t unit_length = this->dwinfo_->read_from_pointer<32>(pinfo);
pinfo += 4;
if (unit_length == 0xffffffff)
{
- unit_length = read_from_pointer<64>(pinfo);
+ unit_length = this->dwinfo_->read_from_pointer<64>(pinfo);
+ this->unit_length_ = unit_length + 12;
pinfo += 8;
this->offset_size_ = 8;
}
else
- this->offset_size_ = 4;
+ {
+ this->unit_length_ = unit_length + 4;
+ this->offset_size_ = 4;
+ }
// Check the version.
- unsigned int version = read_from_pointer<16>(pinfo);
+ unsigned int version = this->dwinfo_->read_from_pointer<16>(pinfo);
pinfo += 2;
if (version != 2)
return false;
-
+
+ this->reloc_mapper_->get_reloc_target(pinfo - this->buffer_,
+ &this->cu_offset_);
+
// Skip the debug_info_offset and debug_info_size fields.
pinfo += 2 * this->offset_size_;
// the end of the list.
uint32_t offset;
if (this->offset_size_ == 4)
- offset = read_from_pointer<32>(&pinfo);
+ offset = this->dwinfo_->read_from_pointer<32>(&pinfo);
else
- offset = read_from_pointer<64>(&pinfo);
+ offset = this->dwinfo_->read_from_pointer<64>(&pinfo);
if (offset == 0)
return NULL;
attr_value.aux.shndx = 0;
switch(form)
{
- case elfcpp::DW_FORM_null:
- attr_value.val.intval = 0;
- break;
case elfcpp::DW_FORM_flag_present:
attr_value.val.intval = 1;
break;
{
off_t str_off;
if (this->dwinfo_->offset_size() == 4)
- str_off = read_from_pointer<32>(&pattr);
+ str_off = this->dwinfo_->read_from_pointer<32>(&pattr);
else
- str_off = read_from_pointer<64>(&pattr);
+ str_off = this->dwinfo_->read_from_pointer<64>(&pattr);
unsigned int shndx =
this->dwinfo_->lookup_reloc(attr_off, &str_off);
attr_value.aux.shndx = shndx;
{
off_t sec_off;
if (this->dwinfo_->offset_size() == 4)
- sec_off = read_from_pointer<32>(&pattr);
+ sec_off = this->dwinfo_->read_from_pointer<32>(&pattr);
else
- sec_off = read_from_pointer<64>(&pattr);
+ sec_off = this->dwinfo_->read_from_pointer<64>(&pattr);
unsigned int shndx =
this->dwinfo_->lookup_reloc(attr_off, &sec_off);
attr_value.aux.shndx = shndx;
{
off_t sec_off;
if (this->dwinfo_->address_size() == 4)
- sec_off = read_from_pointer<32>(&pattr);
+ sec_off = this->dwinfo_->read_from_pointer<32>(&pattr);
else
- sec_off = read_from_pointer<64>(&pattr);
+ sec_off = this->dwinfo_->read_from_pointer<64>(&pattr);
unsigned int shndx =
this->dwinfo_->lookup_reloc(attr_off, &sec_off);
attr_value.aux.shndx = shndx;
pattr += attr_value.aux.blocklen;
break;
case elfcpp::DW_FORM_block2:
- attr_value.aux.blocklen = read_from_pointer<16>(&pattr);
+ attr_value.aux.blocklen =
+ this->dwinfo_->read_from_pointer<16>(&pattr);
attr_value.val.blockval = pattr;
pattr += attr_value.aux.blocklen;
break;
case elfcpp::DW_FORM_block4:
- attr_value.aux.blocklen = read_from_pointer<32>(&pattr);
+ attr_value.aux.blocklen =
+ this->dwinfo_->read_from_pointer<32>(&pattr);
attr_value.val.blockval = pattr;
pattr += attr_value.aux.blocklen;
break;
ref_form = true;
break;
case elfcpp::DW_FORM_data2:
- attr_value.val.intval = read_from_pointer<16>(&pattr);
+ attr_value.val.intval =
+ this->dwinfo_->read_from_pointer<16>(&pattr);
break;
case elfcpp::DW_FORM_ref2:
- attr_value.val.refval = read_from_pointer<16>(&pattr);
+ attr_value.val.refval =
+ this->dwinfo_->read_from_pointer<16>(&pattr);
ref_form = true;
break;
case elfcpp::DW_FORM_data4:
{
off_t sec_off;
- sec_off = read_from_pointer<32>(&pattr);
+ sec_off = this->dwinfo_->read_from_pointer<32>(&pattr);
unsigned int shndx =
this->dwinfo_->lookup_reloc(attr_off, &sec_off);
attr_value.aux.shndx = shndx;
case elfcpp::DW_FORM_ref4:
{
off_t sec_off;
- sec_off = read_from_pointer<32>(&pattr);
+ sec_off = this->dwinfo_->read_from_pointer<32>(&pattr);
unsigned int shndx =
this->dwinfo_->lookup_reloc(attr_off, &sec_off);
attr_value.aux.shndx = shndx;
case elfcpp::DW_FORM_data8:
{
off_t sec_off;
- sec_off = read_from_pointer<64>(&pattr);
+ sec_off = this->dwinfo_->read_from_pointer<64>(&pattr);
unsigned int shndx =
this->dwinfo_->lookup_reloc(attr_off, &sec_off);
attr_value.aux.shndx = shndx;
break;
}
case elfcpp::DW_FORM_ref_sig8:
- attr_value.val.uintval = read_from_pointer<64>(&pattr);
+ attr_value.val.uintval =
+ this->dwinfo_->read_from_pointer<64>(&pattr);
break;
case elfcpp::DW_FORM_ref8:
{
off_t sec_off;
- sec_off = read_from_pointer<64>(&pattr);
+ sec_off = this->dwinfo_->read_from_pointer<64>(&pattr);
unsigned int shndx =
this->dwinfo_->lookup_reloc(attr_off, &sec_off);
attr_value.aux.shndx = shndx;
pattr += len;
break;
case elfcpp::DW_FORM_udata:
+ case elfcpp::DW_FORM_GNU_addr_index:
+ case elfcpp::DW_FORM_GNU_str_index:
attr_value.val.uintval = read_unsigned_LEB_128(pattr, &len);
pattr += len;
break;
off_t
Dwarf_die::skip_attributes()
{
- typedef Dwarf_abbrev_table::Attribute Attribute;
-
gold_assert(this->abbrev_code_ != NULL);
const unsigned char* pdie =
}
switch(form)
{
- case elfcpp::DW_FORM_null:
case elfcpp::DW_FORM_flag_present:
break;
case elfcpp::DW_FORM_strp:
case elfcpp::DW_FORM_block2:
{
uint16_t block_size;
- block_size = read_from_pointer<16>(&pattr);
+ block_size = this->dwinfo_->read_from_pointer<16>(&pattr);
pattr += block_size;
break;
}
case elfcpp::DW_FORM_block4:
{
uint32_t block_size;
- block_size = read_from_pointer<32>(&pattr);
+ block_size = this->dwinfo_->read_from_pointer<32>(&pattr);
pattr += block_size;
break;
}
break;
case elfcpp::DW_FORM_ref_udata:
case elfcpp::DW_FORM_udata:
+ case elfcpp::DW_FORM_GNU_addr_index:
+ case elfcpp::DW_FORM_GNU_str_index:
read_unsigned_LEB_128(pattr, &len);
pattr += len;
break;
return 0;
switch (attr_val->form)
{
- case elfcpp::DW_FORM_null:
case elfcpp::DW_FORM_flag_present:
case elfcpp::DW_FORM_data1:
case elfcpp::DW_FORM_flag:
return 0;
switch (attr_val->form)
{
- case elfcpp::DW_FORM_null:
case elfcpp::DW_FORM_flag_present:
case elfcpp::DW_FORM_data1:
case elfcpp::DW_FORM_flag:
}
}
+off_t
+Dwarf_die::address_attribute(unsigned int attr, unsigned int* shndx)
+{
+ const Attribute_value* attr_val = this->attribute(attr);
+ if (attr_val == NULL || attr_val->form != elfcpp::DW_FORM_addr)
+ return -1;
+
+ *shndx = attr_val->aux.shndx;
+ return attr_val->val.refval;
+}
+
// Return the offset of this DIE's first child.
off_t
// class Dwarf_info_reader
-// Check that the pointer P is within the current compilation unit.
-
-inline bool
-Dwarf_info_reader::check_buffer(const unsigned char* p) const
-{
- if (p > this->buffer_ + this->cu_offset_ + this->cu_length_)
- {
- gold_warning(_("%s: corrupt debug info in %s"),
- this->object_->name().c_str(),
- this->object_->section_name(this->shndx_).c_str());
- return false;
- }
- return true;
-}
-
// Begin parsing the debug info. This calls visit_compilation_unit()
// or visit_type_unit() for each compilation or type unit found in the
// section, and visit_die() for each top-level DIE.
void
Dwarf_info_reader::parse()
{
- switch (parameters->size_and_endianness())
+ if (this->object_->is_big_endian())
{
-#ifdef HAVE_TARGET_32_LITTLE
- case Parameters::TARGET_32_LITTLE:
- this->do_parse<false>();
- break;
-#endif
-#ifdef HAVE_TARGET_32_BIG
- case Parameters::TARGET_32_BIG:
- this->do_parse<true>();
- break;
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+ this->do_parse<true>();
+#else
+ gold_unreachable();
#endif
-#ifdef HAVE_TARGET_64_LITTLE
- case Parameters::TARGET_64_LITTLE:
- this->do_parse<false>();
- break;
-#endif
-#ifdef HAVE_TARGET_64_BIG
- case Parameters::TARGET_64_BIG:
- this->do_parse<true>();
- break;
+ }
+ else
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+ this->do_parse<false>();
+#else
+ gold_unreachable();
#endif
- default:
- gold_unreachable();
}
}
this->reloc_mapper_->initialize(this->reloc_shndx_, this->reloc_type_);
// Loop over compilation units (or type units).
- unsigned int abbrev_shndx = 0;
+ unsigned int abbrev_shndx = this->abbrev_shndx_;
off_t abbrev_offset = 0;
const unsigned char* pinfo = this->buffer_;
while (pinfo < this->buffer_end_)
// Visit the CU or TU.
if (this->is_type_unit_)
this->visit_type_unit(section_offset + this->cu_offset_,
- type_offset, signature, &root_die);
+ cu_end - cu_start, type_offset, signature,
+ &root_die);
else
this->visit_compilation_unit(section_offset + this->cu_offset_,
cu_end - cu_start, &root_die);
return true;
}
+// Read a possibly unaligned integer of SIZE.
+template <int valsize>
+inline typename elfcpp::Valtype_base<valsize>::Valtype
+Dwarf_info_reader::read_from_pointer(const unsigned char* source)
+{
+ typename elfcpp::Valtype_base<valsize>::Valtype return_value;
+ if (this->object_->is_big_endian())
+ return_value = elfcpp::Swap_unaligned<valsize, true>::readval(source);
+ else
+ return_value = elfcpp::Swap_unaligned<valsize, false>::readval(source);
+ return return_value;
+}
+
+// Read a possibly unaligned integer of SIZE. Update SOURCE after read.
+template <int valsize>
+inline typename elfcpp::Valtype_base<valsize>::Valtype
+Dwarf_info_reader::read_from_pointer(const unsigned char** source)
+{
+ typename elfcpp::Valtype_base<valsize>::Valtype return_value;
+ if (this->object_->is_big_endian())
+ return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source);
+ else
+ return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source);
+ *source += valsize / 8;
+ return return_value;
+}
+
// Look for a relocation at offset ATTR_OFF in the dwarf info,
// and return the section index and offset of the target.
// Process a type unit and parse its child DIE.
void
-Dwarf_info_reader::visit_type_unit(off_t, off_t, uint64_t, Dwarf_die*)
+Dwarf_info_reader::visit_type_unit(off_t, off_t, off_t, uint64_t, Dwarf_die*)
+{
+}
+
+// Print a warning about a corrupt debug section.
+
+void
+Dwarf_info_reader::warn_corrupt_debug_section() const
{
+ gold_warning(_("%s: corrupt debug info in %s"),
+ this->object_->name().c_str(),
+ this->object_->section_name(this->shndx_).c_str());
}
// class Sized_dwarf_line_info