X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fdwarf_reader.cc;h=83a0114ed39f7077250050c19157d04c9a8fd4cb;hb=1f1fb219fdc4f96fd967e6173e9090c4c4917e96;hp=d0f059dada07bfa93baac69fd1cc8d5f8783368e;hpb=9fc236f3fd33165d017dee94798ed08db95e87a0;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc index d0f059dada..83a0114ed3 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-2021 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -23,8 +23,10 @@ #include "gold.h" #include +#include #include +#include "debug.h" #include "elfcpp_swap.h" #include "dwarf.h" #include "object.h" @@ -57,7 +59,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 +182,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 @@ -274,6 +276,14 @@ Dwarf_abbrev_table::do_get_abbrev(unsigned int code) uint64_t form = read_unsigned_LEB_128(this->buffer_pos_, &len); this->buffer_pos_ += len; + // For DW_FORM_implicit_const, read the constant. + int64_t implicit_const = 0; + if (form == elfcpp::DW_FORM_implicit_const) + { + implicit_const = read_signed_LEB_128(this->buffer_pos_, &len); + this->buffer_pos_ += len; + } + // A (0,0) pair terminates the list. if (attr == 0 && form == 0) break; @@ -281,7 +291,7 @@ Dwarf_abbrev_table::do_get_abbrev(unsigned int code) if (attr == elfcpp::DW_AT_sibling) entry->has_sibling_attribute = true; - entry->add_attribute(attr, form); + entry->add_attribute(attr, form, implicit_const); } this->store_abbrev(nextcode, entry); @@ -301,8 +311,16 @@ Dwarf_ranges_table::read_ranges_table( Relobj* object, const unsigned char* symtab, off_t symtab_size, - unsigned int ranges_shndx) + unsigned int ranges_shndx, + unsigned int version) { + const std::string section_name(version < 5 + ? ".debug_ranges" + : ".debug_rnglists"); + const std::string compressed_section_name(version < 5 + ? ".zdebug_ranges" + : ".zdebug_rnglists"); + // If we've already read this abbrev table, return immediately. if (this->ranges_shndx_ > 0 && this->ranges_shndx_ == ranges_shndx) @@ -317,7 +335,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 == section_name || name == compressed_section_name) { ranges_shndx = i; this->output_section_offset_ = object->output_section_offset(i); @@ -374,6 +392,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; } @@ -391,7 +410,7 @@ Dwarf_ranges_table::read_range_list( { Dwarf_range_list* ranges; - if (!this->read_ranges_table(object, symtab, symtab_size, ranges_shndx)) + if (!this->read_ranges_table(object, symtab, symtab_size, ranges_shndx, 4)) return NULL; // Correct the offset. For incremental update links, we have a @@ -412,13 +431,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 +449,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 +476,182 @@ Dwarf_ranges_table::read_range_list( return ranges; } +// Read a DWARF 5 range list from section RANGES_SHNDX at offset RANGES_OFFSET. + +Dwarf_range_list* +Dwarf_ranges_table::read_range_list_v5( + Relobj* object, + const unsigned char* symtab, + off_t symtab_size, + unsigned int addr_size, + unsigned int ranges_shndx, + off_t offset) +{ + Dwarf_range_list* ranges; + + if (!this->read_ranges_table(object, symtab, symtab_size, ranges_shndx, 5)) + return NULL; + + ranges = new Dwarf_range_list(); + off_t base = 0; + unsigned int shndx0 = 0; + + // 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_; + + // Read the range list at OFFSET. + const unsigned char* prle = this->ranges_buffer_ + offset; + while (prle < this->ranges_buffer_end_) + { + off_t start; + off_t end; + unsigned int shndx1 = 0; + unsigned int shndx2 = 0; + size_t len; + + // Read the entry type. + unsigned int rle_type = *prle++; + offset += 1; + + if (rle_type == elfcpp::DW_RLE_end_of_list) + break; + + switch (rle_type) + { + case elfcpp::DW_RLE_base_address: + if (addr_size == 4) + base = this->dwinfo_->read_from_pointer<32>(prle); + else + base = this->dwinfo_->read_from_pointer<64>(prle); + if (this->ranges_reloc_mapper_ != NULL) + shndx0 = this->lookup_reloc(offset, &base); + prle += addr_size; + offset += addr_size; + break; + + case elfcpp::DW_RLE_offset_pair: + start = read_unsigned_LEB_128(prle, &len); + prle += len; + offset += len; + end = read_unsigned_LEB_128(prle, &len); + prle += len; + offset += len; + if (shndx0 == 0 || object->is_section_included(shndx0)) + ranges->add(shndx0, base + start, base + end); + break; + + case elfcpp::DW_RLE_start_end: + if (addr_size == 4) + { + start = this->dwinfo_->read_from_pointer<32>(prle); + end = this->dwinfo_->read_from_pointer<32>(prle + 4); + } + else + { + start = this->dwinfo_->read_from_pointer<64>(prle); + end = this->dwinfo_->read_from_pointer<64>(prle + 8); + } + if (this->ranges_reloc_mapper_ != NULL) + { + shndx1 = this->lookup_reloc(offset, &start); + shndx2 = this->lookup_reloc(offset + addr_size, &end); + if (shndx1 != shndx2) + gold_warning(_("%s: DWARF info may be corrupt; offsets in a " + "range list entry are in different sections"), + object->name().c_str()); + } + prle += addr_size * 2; + offset += addr_size * 2; + if (shndx1 == 0 || object->is_section_included(shndx1)) + ranges->add(shndx1, start, end); + break; + + case elfcpp::DW_RLE_start_length: + if (addr_size == 4) + start = this->dwinfo_->read_from_pointer<32>(prle); + else + start = this->dwinfo_->read_from_pointer<64>(prle); + if (this->ranges_reloc_mapper_ != NULL) + shndx1 = this->lookup_reloc(offset, &start); + prle += addr_size; + offset += addr_size; + end = start + read_unsigned_LEB_128(prle, &len); + prle += len; + offset += len; + if (shndx1 == 0 || object->is_section_included(shndx1)) + ranges->add(shndx1, start, end); + break; + + default: + gold_warning(_("%s: DWARF range list contains " + "unsupported entry type (%d)"), + object->name().c_str(), rle_type); + break; + } + } + + 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 +659,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 +691,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 +700,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 +744,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); @@ -634,26 +845,52 @@ Dwarf_die::read_attributes() case elfcpp::DW_FORM_flag_present: attr_value.val.intval = 1; break; + case elfcpp::DW_FORM_implicit_const: + attr_value.val.intval = + this->abbrev_code_->attributes[i].implicit_const; + break; case elfcpp::DW_FORM_strp: + case elfcpp::DW_FORM_strp_sup: + case elfcpp::DW_FORM_line_strp: { 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; attr_value.val.refval = str_off; break; } + case elfcpp::DW_FORM_strx: + case elfcpp::DW_FORM_GNU_str_index: + attr_value.val.uintval = read_unsigned_LEB_128(pattr, &len); + pattr += len; + break; + case elfcpp::DW_FORM_strx1: + attr_value.val.uintval = *pattr++; + break; + case elfcpp::DW_FORM_strx2: + attr_value.val.uintval = + this->dwinfo_->read_from_pointer<16>(&pattr); + break; + case elfcpp::DW_FORM_strx3: + attr_value.val.uintval = + this->dwinfo_->read_3bytes_from_pointer(&pattr); + break; + case elfcpp::DW_FORM_strx4: + attr_value.val.uintval = + this->dwinfo_->read_from_pointer<32>(&pattr); + break; case elfcpp::DW_FORM_sec_offset: { 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 +899,25 @@ 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 = 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; + attr_value.val.refval = sec_off; + 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 = 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 +931,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 +957,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; @@ -723,9 +976,10 @@ Dwarf_die::read_attributes() break; } case elfcpp::DW_FORM_ref4: + case elfcpp::DW_FORM_ref_sup4: { 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,20 +990,30 @@ 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; attr_value.val.intval = sec_off; break; } + case elfcpp::DW_FORM_data16: + { + // For now, treat this as a 16-byte block. + attr_value.val.blockval = pattr; + attr_value.aux.blocklen = 16; + pattr += 16; + 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: + case elfcpp::DW_FORM_ref_sup8: { 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; @@ -763,11 +1027,29 @@ Dwarf_die::read_attributes() pattr += len; break; case elfcpp::DW_FORM_udata: + attr_value.val.uintval = read_unsigned_LEB_128(pattr, &len); + pattr += len; + break; + case elfcpp::DW_FORM_addrx: 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; + case elfcpp::DW_FORM_addrx1: + attr_value.val.uintval = *pattr++; + break; + case elfcpp::DW_FORM_addrx2: + attr_value.val.uintval = + this->dwinfo_->read_from_pointer<16>(&pattr); + break; + case elfcpp::DW_FORM_addrx3: + attr_value.val.uintval = + this->dwinfo_->read_3bytes_from_pointer(&pattr); + break; + case elfcpp::DW_FORM_addrx4: + attr_value.val.uintval = + this->dwinfo_->read_from_pointer<32>(&pattr); + break; case elfcpp::DW_FORM_sdata: attr_value.val.intval = read_signed_LEB_128(pattr, &len); pattr += len; @@ -777,6 +1059,11 @@ Dwarf_die::read_attributes() len = strlen(attr_value.val.stringval); pattr += len + 1; break; + case elfcpp::DW_FORM_loclistx: + case elfcpp::DW_FORM_rnglistx: + attr_value.val.uintval = read_unsigned_LEB_128(pattr, &len); + pattr += len; + break; default: return false; } @@ -861,29 +1148,34 @@ Dwarf_die::skip_attributes() switch(form) { case elfcpp::DW_FORM_flag_present: + case elfcpp::DW_FORM_implicit_const: break; case elfcpp::DW_FORM_strp: case elfcpp::DW_FORM_sec_offset: + case elfcpp::DW_FORM_strp_sup: + case elfcpp::DW_FORM_line_strp: 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; } @@ -898,23 +1190,42 @@ Dwarf_die::skip_attributes() case elfcpp::DW_FORM_data1: case elfcpp::DW_FORM_ref1: case elfcpp::DW_FORM_flag: + case elfcpp::DW_FORM_strx1: + case elfcpp::DW_FORM_addrx1: pattr += 1; break; case elfcpp::DW_FORM_data2: case elfcpp::DW_FORM_ref2: + case elfcpp::DW_FORM_strx2: + case elfcpp::DW_FORM_addrx2: pattr += 2; break; + case elfcpp::DW_FORM_strx3: + case elfcpp::DW_FORM_addrx3: + pattr += 3; + break; case elfcpp::DW_FORM_data4: case elfcpp::DW_FORM_ref4: + case elfcpp::DW_FORM_ref_sup4: + case elfcpp::DW_FORM_strx4: + case elfcpp::DW_FORM_addrx4: pattr += 4; break; case elfcpp::DW_FORM_data8: case elfcpp::DW_FORM_ref8: case elfcpp::DW_FORM_ref_sig8: + case elfcpp::DW_FORM_ref_sup8: pattr += 8; break; + case elfcpp::DW_FORM_data16: + pattr += 16; + break; case elfcpp::DW_FORM_ref_udata: case elfcpp::DW_FORM_udata: + case elfcpp::DW_FORM_addrx: + case elfcpp::DW_FORM_strx: + case elfcpp::DW_FORM_loclistx: + case elfcpp::DW_FORM_rnglistx: case elfcpp::DW_FORM_GNU_addr_index: case elfcpp::DW_FORM_GNU_str_index: read_unsigned_LEB_128(pattr, &len); @@ -1132,21 +1443,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 +1491,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_) @@ -1233,6 +1529,13 @@ Dwarf_info_reader::do_parse() elfcpp::Swap_unaligned<16, big_endian>::readval(pinfo); pinfo += 2; + // DWARF 5: Read the unit type (1 byte) and address size (1 byte). + if (this->cu_version_ >= 5) + { + this->unit_type_ = *pinfo++; + this->address_size_ = *pinfo++; + } + // Read debug_abbrev_offset (4 or 8 bytes). if (this->offset_size_ == 4) abbrev_offset = elfcpp::Swap_unaligned<32, big_endian>::readval(pinfo); @@ -1253,13 +1556,14 @@ Dwarf_info_reader::do_parse() } pinfo += this->offset_size_; - // Read address_size (1 byte). - this->address_size_ = *pinfo++; + // DWARF 2-4: Read address_size (1 byte). + if (this->cu_version_ < 5) + 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()) { if (!this->check_buffer(pinfo + 8 + this->offset_size_)) break; @@ -1289,9 +1593,10 @@ Dwarf_info_reader::do_parse() if (root_die.tag() != 0) { // Visit the CU or TU. - if (this->is_type_unit_) + 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 +1627,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 +1657,46 @@ 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; +} + +// Read a 3-byte integer. Update SOURCE after read. +inline typename elfcpp::Valtype_base<32>::Valtype +Dwarf_info_reader::read_3bytes_from_pointer(const unsigned char** source) +{ + typename elfcpp::Valtype_base<32>::Valtype return_value; + if (this->object_->is_big_endian()) + return_value = ((*source)[0] << 16) | ((*source)[1] << 8) | (*source)[2]; + else + return_value = ((*source)[2] << 16) | ((*source)[1] << 8) | (*source)[0]; + *source += 3; + 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 +1752,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 @@ -1443,27 +1798,40 @@ Sized_dwarf_line_info::Sized_dwarf_line_info( Object* object, unsigned int read_shndx) : data_valid_(false), buffer_(NULL), buffer_start_(NULL), + str_buffer_(NULL), str_buffer_start_(NULL), reloc_mapper_(NULL), symtab_buffer_(NULL), directories_(), files_(), - current_header_index_(-1) + current_header_index_(-1), reloc_map_(), line_number_map_() { - unsigned int debug_shndx; + unsigned int debug_line_shndx = 0; + unsigned int debug_line_str_shndx = 0; - for (debug_shndx = 1; debug_shndx < object->shnum(); ++debug_shndx) + for (unsigned int i = 1; i < object->shnum(); ++i) { + section_size_type buffer_size; + bool is_new = false; + // FIXME: do this more efficiently: section_name() isn't super-fast - std::string name = object->section_name(debug_shndx); + std::string name = object->section_name(i); if (name == ".debug_line" || name == ".zdebug_line") { - section_size_type buffer_size; - bool is_new = false; - this->buffer_ = object->decompressed_section_contents(debug_shndx, - &buffer_size, - &is_new); + this->buffer_ = + object->decompressed_section_contents(i, &buffer_size, &is_new); if (is_new) this->buffer_start_ = this->buffer_; this->buffer_end_ = this->buffer_ + buffer_size; - break; + debug_line_shndx = i; } + else if (name == ".debug_line_str" || name == ".zdebug_line_str") + { + this->str_buffer_ = + object->decompressed_section_contents(i, &buffer_size, &is_new); + if (is_new) + this->str_buffer_start_ = this->str_buffer_; + this->str_buffer_end_ = this->str_buffer_ + buffer_size; + debug_line_str_shndx = i; + } + if (debug_line_shndx > 0 && debug_line_str_shndx > 0) + break; } if (this->buffer_ == NULL) return; @@ -1476,7 +1844,7 @@ Sized_dwarf_line_info::Sized_dwarf_line_info( unsigned int reloc_sh_type = object->section_type(i); if ((reloc_sh_type == elfcpp::SHT_REL || reloc_sh_type == elfcpp::SHT_RELA) - && object->section_info(i) == debug_shndx) + && object->section_info(i) == debug_line_shndx) { reloc_shndx = i; this->track_relocs_type_ = reloc_sh_type; @@ -1522,50 +1890,80 @@ Sized_dwarf_line_info::read_header_prolog( uint32_t initial_length = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); lineptr += 4; - // In DWARF2/3, if the initial length is all 1 bits, then the offset + // In DWARF, if the initial length is all 1 bits, then the offset // size is 8 and we need to read the next 8 bytes for the real length. if (initial_length == 0xffffffff) { - header_.offset_size = 8; + this->header_.offset_size = 8; initial_length = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); lineptr += 8; } else - header_.offset_size = 4; + this->header_.offset_size = 4; - header_.total_length = initial_length; + this->header_.total_length = initial_length; - gold_assert(lineptr + header_.total_length <= buffer_end_); + this->end_of_unit_ = lineptr + initial_length; + gold_assert(this->end_of_unit_ <= buffer_end_); - header_.version = elfcpp::Swap_unaligned<16, big_endian>::readval(lineptr); + this->header_.version = + elfcpp::Swap_unaligned<16, big_endian>::readval(lineptr); lineptr += 2; - if (header_.offset_size == 4) - header_.prologue_length = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); + // We can only read versions 2-5 of the DWARF line number table. + // For other versions, just skip the entire line number table. + if (this->header_.version < 2 || this->header_.version > 5) + return this->end_of_unit_; + + // DWARF 5 only: address size and segment selector. + if (this->header_.version >= 5) + { + this->header_.address_size = *lineptr; + // We ignore the segment selector. + lineptr += 2; + } + + if (this->header_.offset_size == 4) + this->header_.prologue_length = + elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); else - header_.prologue_length = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); - lineptr += header_.offset_size; + this->header_.prologue_length = + elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); + lineptr += this->header_.offset_size; + + this->end_of_header_length_ = lineptr; - header_.min_insn_length = *lineptr; + this->header_.min_insn_length = *lineptr; lineptr += 1; - header_.default_is_stmt = *lineptr; + if (this->header_.version < 4) + this->header_.max_ops_per_insn = 1; + else + { + // DWARF 4 added the maximum_operations_per_instruction field. + this->header_.max_ops_per_insn = *lineptr; + lineptr += 1; + // TODO: Add support for values other than 1. + gold_assert(this->header_.max_ops_per_insn == 1); + } + + this->header_.default_is_stmt = *lineptr; lineptr += 1; - header_.line_base = *reinterpret_cast(lineptr); + this->header_.line_base = *reinterpret_cast(lineptr); lineptr += 1; - header_.line_range = *lineptr; + this->header_.line_range = *lineptr; lineptr += 1; - header_.opcode_base = *lineptr; + this->header_.opcode_base = *lineptr; lineptr += 1; - header_.std_opcode_lengths.resize(header_.opcode_base + 1); - header_.std_opcode_lengths[0] = 0; - for (int i = 1; i < header_.opcode_base; i++) + this->header_.std_opcode_lengths.resize(this->header_.opcode_base + 1); + this->header_.std_opcode_lengths[0] = 0; + for (int i = 1; i < this->header_.opcode_base; i++) { - header_.std_opcode_lengths[i] = *lineptr; + this->header_.std_opcode_lengths[i] = *lineptr; lineptr += 1; } @@ -1574,10 +1972,11 @@ Sized_dwarf_line_info::read_header_prolog( // The header for a debug_line section is mildly complicated, because // the line info is very tightly encoded. +// This routine is for DWARF versions 2, 3, and 4. template const unsigned char* -Sized_dwarf_line_info::read_header_tables( +Sized_dwarf_line_info::read_header_tables_v2( const unsigned char* lineptr) { ++this->current_header_index_; @@ -1642,6 +2041,169 @@ Sized_dwarf_line_info::read_header_tables( return lineptr; } +// This routine is for DWARF version 5. + +template +const unsigned char* +Sized_dwarf_line_info::read_header_tables_v5( + const unsigned char* lineptr) +{ + size_t len; + + ++this->current_header_index_; + + gold_assert(static_cast(this->directories_.size()) + == this->current_header_index_); + gold_assert(static_cast(this->files_.size()) + == this->current_header_index_); + + // Read the directory list. + unsigned int format_count = *lineptr; + lineptr += 1; + + unsigned int *types = new unsigned int[format_count]; + unsigned int *forms = new unsigned int[format_count]; + + for (unsigned int i = 0; i < format_count; i++) + { + types[i] = read_unsigned_LEB_128(lineptr, &len); + lineptr += len; + forms[i] = read_unsigned_LEB_128(lineptr, &len); + lineptr += len; + } + + uint64_t entry_count = read_unsigned_LEB_128(lineptr, &len); + lineptr += len; + this->directories_.push_back(std::vector(0)); + std::vector& dir_list = this->directories_.back(); + + for (unsigned int j = 0; j < entry_count; j++) + { + std::string dirname; + + for (unsigned int i = 0; i < format_count; i++) + { + if (types[i] == elfcpp::DW_LNCT_path) + { + if (forms[i] == elfcpp::DW_FORM_string) + { + dirname = reinterpret_cast(lineptr); + lineptr += dirname.size() + 1; + } + else if (forms[i] == elfcpp::DW_FORM_line_strp) + { + uint64_t offset; + if (this->header_.offset_size == 4) + offset = + elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); + else + offset = + elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); + typename Reloc_map::const_iterator it + = this->reloc_map_.find(lineptr - this->buffer_); + if (it != reloc_map_.end()) + { + if (this->track_relocs_type_ == elfcpp::SHT_RELA) + offset = 0; + offset += it->second.second; + } + lineptr += this->header_.offset_size; + dirname = reinterpret_cast(this->str_buffer_ + + offset); + } + else + return lineptr; + } + else + return lineptr; + } + dir_list.push_back(dirname); + } + + delete[] types; + delete[] forms; + + // Read the filenames list. + format_count = *lineptr; + lineptr += 1; + + types = new unsigned int[format_count]; + forms = new unsigned int[format_count]; + + for (unsigned int i = 0; i < format_count; i++) + { + types[i] = read_unsigned_LEB_128(lineptr, &len); + lineptr += len; + forms[i] = read_unsigned_LEB_128(lineptr, &len); + lineptr += len; + } + + entry_count = read_unsigned_LEB_128(lineptr, &len); + lineptr += len; + this->files_.push_back( + std::vector >(0)); + std::vector >& file_list = this->files_.back(); + + for (unsigned int j = 0; j < entry_count; j++) + { + const char* path = NULL; + int dirindex = 0; + + for (unsigned int i = 0; i < format_count; i++) + { + if (types[i] == elfcpp::DW_LNCT_path) + { + if (forms[i] == elfcpp::DW_FORM_string) + { + path = reinterpret_cast(lineptr); + lineptr += strlen(path) + 1; + } + else if (forms[i] == elfcpp::DW_FORM_line_strp) + { + uint64_t offset; + if (this->header_.offset_size == 4) + offset = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); + else + offset = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); + typename Reloc_map::const_iterator it + = this->reloc_map_.find(lineptr - this->buffer_); + if (it != reloc_map_.end()) + { + if (this->track_relocs_type_ == elfcpp::SHT_RELA) + offset = 0; + offset += it->second.second; + } + lineptr += this->header_.offset_size; + path = reinterpret_cast(this->str_buffer_ + + offset); + } + else + return lineptr; + } + else if (types[i] == elfcpp::DW_LNCT_directory_index) + { + if (forms[i] == elfcpp::DW_FORM_udata) + { + dirindex = read_unsigned_LEB_128(lineptr, &len); + lineptr += len; + } + else + return lineptr; + } + else + return lineptr; + } + gold_debug(DEBUG_LOCATION, "File %3d: %s", + static_cast(file_list.size()), path); + file_list.push_back(std::make_pair(dirindex, path)); + } + + delete[] types; + delete[] forms; + + return lineptr; +} + // Process a single opcode in the .debug.line structure. template @@ -1657,15 +2219,15 @@ Sized_dwarf_line_info::process_one_opcode( // If the opcode is great than the opcode_base, it is a special // opcode. Most line programs consist mainly of special opcodes. - if (opcode >= header_.opcode_base) + if (opcode >= this->header_.opcode_base) { - opcode -= header_.opcode_base; - const int advance_address = ((opcode / header_.line_range) - * header_.min_insn_length); + opcode -= this->header_.opcode_base; + const int advance_address = ((opcode / this->header_.line_range) + * this->header_.min_insn_length); lsm->address += advance_address; - const int advance_line = ((opcode % header_.line_range) - + header_.line_base); + const int advance_line = ((opcode % this->header_.line_range) + + this->header_.line_base); lsm->line_num += advance_line; lsm->basic_block = true; *len = oplen; @@ -1685,13 +2247,13 @@ Sized_dwarf_line_info::process_one_opcode( const uint64_t advance_address = read_unsigned_LEB_128(start, &templen); oplen += templen; - lsm->address += header_.min_insn_length * advance_address; + lsm->address += this->header_.min_insn_length * advance_address; } break; case elfcpp::DW_LNS_advance_line: { - const uint64_t advance_line = read_signed_LEB_128(start, &templen); + const int64_t advance_line = read_signed_LEB_128(start, &templen); oplen += templen; lsm->line_num += advance_line; } @@ -1732,9 +2294,9 @@ Sized_dwarf_line_info::process_one_opcode( case elfcpp::DW_LNS_const_add_pc: { - const int advance_address = (header_.min_insn_length - * ((255 - header_.opcode_base) - / header_.line_range)); + const int advance_address = (this->header_.min_insn_length + * ((255 - this->header_.opcode_base) + / this->header_.line_range)); lsm->address += advance_address; } break; @@ -1817,7 +2379,7 @@ Sized_dwarf_line_info::process_one_opcode( default: { // Ignore unknown opcode silently - for (int i = 0; i < header_.std_opcode_lengths[opcode]; i++) + for (int i = 0; i < this->header_.std_opcode_lengths[opcode]; i++) { size_t templen; read_unsigned_LEB_128(start, &templen); @@ -1837,28 +2399,24 @@ Sized_dwarf_line_info::process_one_opcode( template unsigned const char* Sized_dwarf_line_info::read_lines(unsigned const char* lineptr, + unsigned const char* endptr, unsigned int shndx) { struct LineStateMachine lsm; - // LENGTHSTART is the place the length field is based on. It is the - // point in the header after the initial length field. - const unsigned char* lengthstart = buffer_; - - // In 64 bit dwarf, the initial length is 12 bytes, because of the - // 0xffffffff at the start. - if (header_.offset_size == 8) - lengthstart += 12; - else - lengthstart += 4; - - while (lineptr < lengthstart + header_.total_length) + while (lineptr < endptr) { - ResetLineStateMachine(&lsm, header_.default_is_stmt); + ResetLineStateMachine(&lsm, this->header_.default_is_stmt); while (!lsm.end_sequence) { size_t oplength; + + if (lineptr >= endptr) + break; + bool add_line = this->process_one_opcode(lineptr, &lsm, &oplength); + lineptr += oplength; + if (add_line && (shndx == -1U || lsm.shndx == -1U || shndx == lsm.shndx)) { @@ -1879,11 +2437,10 @@ Sized_dwarf_line_info::read_lines(unsigned const char* lineptr map.back().last_line_for_offset = false; map.push_back(entry); } - lineptr += oplength; } } - return lengthstart + header_.total_length; + return endptr; } // Read the relocations into a Reloc_map. @@ -1924,9 +2481,17 @@ Sized_dwarf_line_info::read_line_mappings(unsigned int shndx) { const unsigned char* lineptr = this->buffer_; lineptr = this->read_header_prolog(lineptr); - lineptr = this->read_header_tables(lineptr); - lineptr = this->read_lines(lineptr, shndx); - this->buffer_ = lineptr; + if (this->header_.version >= 2 && this->header_.version <= 4) + { + lineptr = this->read_header_tables_v2(lineptr); + lineptr = this->read_lines(lineptr, this->end_of_unit_, shndx); + } + else if (this->header_.version == 5) + { + lineptr = this->read_header_tables_v5(lineptr); + lineptr = this->read_lines(lineptr, this->end_of_unit_, shndx); + } + this->buffer_ = this->end_of_unit_; } // Sort the lines numbers, so addr2line can use binary search. @@ -2082,6 +2647,9 @@ Sized_dwarf_line_info::do_addr2line( off_t offset, std::vector* other_lines) { + gold_debug(DEBUG_LOCATION, "do_addr2line: shndx %u offset %08x", + shndx, static_cast(offset)); + if (this->data_valid_ == false) return ""; @@ -2102,13 +2670,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; }