X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=sidebyside;f=gold%2Fdwarf_reader.cc;h=ac9fbad5482f997117a9f2b465e2b3502dacd884;hb=50838d1be72ddd30e0b5f081933482424ae5a6b0;hp=d0f059dada07bfa93baac69fd1cc8d5f8783368e;hpb=9fc236f3fd33165d017dee94798ed08db95e87a0;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc index d0f059dada..ac9fbad548 100644 --- a/gold/dwarf_reader.cc +++ b/gold/dwarf_reader.cc @@ -1,6 +1,6 @@ // dwarf_reader.cc -- parse dwarf2/3 debug information -// Copyright 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +// Copyright (C) 2007-2020 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -23,6 +23,7 @@ #include "gold.h" #include +#include #include #include "elfcpp_swap.h" @@ -57,7 +58,7 @@ Sized_elf_reloc_mapper::symbol_section( unsigned int symndx, Address* value, bool* is_ordinary) { const int symsize = elfcpp::Elf_sizes::sym_size; - gold_assert((symndx + 1) * symsize <= this->symtab_size_); + gold_assert(static_cast((symndx + 1) * symsize) <= this->symtab_size_); elfcpp::Sym elfsym(this->symtab_ + symndx * symsize); *value = elfsym.get_st_value(); return this->object_->adjust_sym_shndx(symndx, elfsym.get_st_shndx(), @@ -180,7 +181,7 @@ Dwarf_abbrev_table::do_read_abbrevs( 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 @@ -317,7 +318,7 @@ Dwarf_ranges_table::read_ranges_table( 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); @@ -374,6 +375,7 @@ Dwarf_ranges_table::read_ranges_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; } @@ -412,13 +414,17 @@ Dwarf_ranges_table::read_range_list( // 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. @@ -426,11 +432,8 @@ Dwarf_ranges_table::read_range_list( 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. @@ -456,34 +459,63 @@ Dwarf_ranges_table::read_range_list( 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, @@ -491,6 +523,30 @@ Dwarf_pubnames_table::read_section(Relobj* object, unsigned int shndx) 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; } @@ -499,10 +555,8 @@ Dwarf_pubnames_table::read_section(Relobj* object, unsigned int shndx) 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; @@ -510,23 +564,37 @@ Dwarf_pubnames_table::read_header(off_t offset) 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; + } + 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 = 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_; @@ -540,20 +608,27 @@ Dwarf_pubnames_table::read_header(off_t offset) // 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 = read_from_pointer<32>(&pinfo); - else - offset = 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(pinfo); @@ -638,9 +713,9 @@ Dwarf_die::read_attributes() { 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; @@ -651,9 +726,9 @@ Dwarf_die::read_attributes() { 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; @@ -662,13 +737,26 @@ Dwarf_die::read_attributes() break; } case elfcpp::DW_FORM_addr: - case elfcpp::DW_FORM_ref_addr: { 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 = this->dwinfo_->read_from_pointer<64>(&pattr); + unsigned int shndx = + this->dwinfo_->lookup_reloc(attr_off, &sec_off); + attr_value.aux.shndx = shndx; + attr_value.val.refval = sec_off; + ref_form = true; + break; + } + case elfcpp::DW_FORM_ref_addr: + { + off_t sec_off; + if (this->dwinfo_->ref_addr_size() == 4) + 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; @@ -682,12 +770,14 @@ Dwarf_die::read_attributes() 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; @@ -706,16 +796,18 @@ Dwarf_die::read_attributes() 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; @@ -725,7 +817,7 @@ Dwarf_die::read_attributes() 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; @@ -736,7 +828,7 @@ Dwarf_die::read_attributes() 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; @@ -744,12 +836,13 @@ Dwarf_die::read_attributes() 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; @@ -867,23 +960,25 @@ Dwarf_die::skip_attributes() pattr += this->dwinfo_->offset_size(); break; case elfcpp::DW_FORM_addr: - case elfcpp::DW_FORM_ref_addr: pattr += this->dwinfo_->address_size(); break; + case elfcpp::DW_FORM_ref_addr: + pattr += this->dwinfo_->ref_addr_size(); + break; case elfcpp::DW_FORM_block1: pattr += 1 + *pattr; break; 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; } @@ -1132,21 +1227,6 @@ Dwarf_die::sibling_offset() // 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. @@ -1195,7 +1275,7 @@ Dwarf_info_reader::do_parse() 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_) @@ -1291,7 +1371,8 @@ Dwarf_info_reader::do_parse() // 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); @@ -1322,7 +1403,7 @@ Dwarf_info_reader::do_read_string_table(unsigned int string_shndx) 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_ = @@ -1352,6 +1433,33 @@ Dwarf_info_reader::do_read_string_table(unsigned int string_shndx) return true; } +// Read a possibly unaligned integer of SIZE. +template +inline typename elfcpp::Valtype_base::Valtype +Dwarf_info_reader::read_from_pointer(const unsigned char* source) +{ + typename elfcpp::Valtype_base::Valtype return_value; + if (this->object_->is_big_endian()) + return_value = elfcpp::Swap_unaligned::readval(source); + else + return_value = elfcpp::Swap_unaligned::readval(source); + return return_value; +} + +// Read a possibly unaligned integer of SIZE. Update SOURCE after read. +template +inline typename elfcpp::Valtype_base::Valtype +Dwarf_info_reader::read_from_pointer(const unsigned char** source) +{ + typename elfcpp::Valtype_base::Valtype return_value; + if (this->object_->is_big_endian()) + return_value = elfcpp::Swap_unaligned::readval(*source); + else + return_value = elfcpp::Swap_unaligned::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. @@ -1407,10 +1515,20 @@ Dwarf_info_reader::visit_compilation_unit(off_t, off_t, Dwarf_die*) // 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 struct LineStateMachine @@ -1549,6 +1667,17 @@ Sized_dwarf_line_info::read_header_prolog( header_.min_insn_length = *lineptr; lineptr += 1; + if (header_.version < 4) + header_.max_ops_per_insn = 1; + else + { + // DWARF 4 added the maximum_operations_per_instruction field. + header_.max_ops_per_insn = *lineptr; + lineptr += 1; + // TODO: Add support for values other than 1. + gold_assert(header_.max_ops_per_insn == 1); + } + header_.default_is_stmt = *lineptr; lineptr += 1; @@ -2102,13 +2231,33 @@ Sized_dwarf_line_info::do_addr2line( return ""; std::string result = this->format_file_lineno(*it); + gold_debug(DEBUG_LOCATION, "do_addr2line: canonical result: %s", + result.c_str()); if (other_lines != NULL) - for (++it; it != offsets->end() && it->offset == offset; ++it) - { - if (it->line_num == -1) - continue; // The end of a previous function. - other_lines->push_back(this->format_file_lineno(*it)); - } + { + unsigned int last_file_num = it->file_num; + int last_line_num = it->line_num; + // Return up to 4 more locations from the beginning of the function + // for fuzzy matching. + for (++it; it != offsets->end(); ++it) + { + if (it->offset == offset && it->line_num == -1) + continue; // The end of a previous function. + if (it->line_num == -1) + break; // The end of the current function. + if (it->file_num != last_file_num || it->line_num != last_line_num) + { + other_lines->push_back(this->format_file_lineno(*it)); + gold_debug(DEBUG_LOCATION, "do_addr2line: other: %s", + other_lines->back().c_str()); + last_file_num = it->file_num; + last_line_num = it->line_num; + } + if (it->offset > offset && other_lines->size() >= 4) + break; + } + } + return result; }