// dwarf_reader.cc -- parse dwarf2/3 debug information
-// Copyright 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+// Copyright (C) 2007-2014 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
#include "gold.h"
#include <algorithm>
+#include <utility>
#include <vector>
#include "elfcpp_swap.h"
for (unsigned int i = 1; i < object->shnum(); ++i)
{
std::string name = object->section_name(i);
- if (name == ".debug_abbrev")
+ if (name == ".debug_abbrev" || name == ".zdebug_abbrev")
{
abbrev_shndx = i;
// Correct the offset. For incremental update links, we have a
for (unsigned int i = 1; i < object->shnum(); ++i)
{
std::string name = object->section_name(i);
- if (name == ".debug_ranges")
+ if (name == ".debug_ranges" || name == ".zdebug_ranges")
{
ranges_shndx = i;
this->output_section_offset_ = object->output_section_offset(i);
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;
}
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;
+ const char* name = this->is_pubtypes_ ? "pubtypes" : "pubnames";
+ const char* gnu_name = (this->is_pubtypes_
+ ? "gnu_pubtypes"
+ : "gnu_pubnames");
- // 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)
+ 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;
+ std::string section_name = object->section_name(i);
+ const char* section_name_suffix = section_name.c_str();
+ if (is_prefix_of(".debug_", section_name_suffix))
+ section_name_suffix += 7;
+ else if (is_prefix_of(".zdebug_", section_name_suffix))
+ section_name_suffix += 8;
+ else
+ continue;
+ if (strcmp(section_name_suffix, name) == 0)
+ {
+ shndx = i;
+ break;
+ }
+ else if (strcmp(section_name_suffix, gnu_name) == 0)
+ {
+ shndx = i;
+ this->is_gnu_style_ = true;
+ 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)
{
- // 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.
- offset -= this->output_section_offset_;
+ // Make sure we have actually read the section.
+ gold_assert(this->buffer_ != NULL);
if (offset < 0 || offset + 14 >= this->buffer_end_ - this->buffer_)
return false;
const unsigned char* pinfo = this->buffer_ + offset;
// Read the unit_length field.
- uint32_t unit_length = this->dwinfo_->read_from_pointer<32>(pinfo);
+ uint64_t unit_length = this->dwinfo_->read_from_pointer<32>(pinfo);
pinfo += 4;
if (unit_length == 0xffffffff)
{
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;
+ }
+ this->end_of_table_ = pinfo + unit_length;
+
+ // If unit_length is too big, maybe we should reject the whole table,
+ // but in cases we know about, it seems OK to assume that the table
+ // is valid through the actual end of the section.
+ if (this->end_of_table_ > this->buffer_end_)
+ this->end_of_table_ = this->buffer_end_;
// Check the version.
unsigned int version = this->dwinfo_->read_from_pointer<16>(pinfo);
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_;
// Read the next name from the set.
const char*
-Dwarf_pubnames_table::next_name()
+Dwarf_pubnames_table::next_name(uint8_t* flag_byte)
{
const unsigned char* pinfo = this->pinfo_;
- // Read the offset within the CU. If this is zero, we have reached
- // the end of the list.
- uint32_t offset;
- if (this->offset_size_ == 4)
- offset = this->dwinfo_->read_from_pointer<32>(&pinfo);
- else
- offset = this->dwinfo_->read_from_pointer<64>(&pinfo);
- if (offset == 0)
+ // Check for end of list. The table should be terminated by an
+ // entry containing nothing but a DIE offset of 0.
+ if (pinfo + this->offset_size_ >= this->end_of_table_)
return NULL;
+ // Skip the offset within the CU. If this is zero, but we're not
+ // at the end of the table, then we have a real pubnames entry
+ // whose DIE offset is 0 (likely to be a GCC bug). Since we
+ // don't actually use the DIE offset in building .gdb_index,
+ // it's harmless.
+ pinfo += this->offset_size_;
+
+ if (this->is_gnu_style_)
+ *flag_byte = *pinfo++;
+ else
+ *flag_byte = 0;
+
// Return a pointer to the string at the current location,
// and advance the pointer to the next entry.
const char* ret = reinterpret_cast<const char*>(pinfo);
// 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.
// 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);
for (unsigned int i = 1; i < this->object_->shnum(); ++i)
{
std::string name = object->section_name(i);
- if (name == ".debug_str")
+ if (name == ".debug_str" || name == ".zdebug_str")
{
string_shndx = i;
this->string_output_section_offset_ =
// 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