mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:54:41 +08:00
2012-03-21 Cary Coutant <ccoutant@google.com>
* Makefile.am: Add gdb-index.cc, gdb-index.h. * Makefile.in: Regenerate. * dwarf_reader.cc (Sized_elf_reloc_mapper::do_initialize): New function. (Sized_elf_reloc_mapper::symbol_section): New function. (Sized_elf_reloc_mapper::do_get_reloc_target): New function. (make_elf_reloc_mapper): New function. (Dwarf_abbrev_table::clear_abbrev_codes): New function. (Dwarf_abbrev_table::do_read_abbrevs): New function. (Dwarf_abbrev_table::do_get_abbrev): New function. (Dwarf_ranges_table::read_ranges_table): New function. (Dwarf_ranges_table::read_range_list): New function. (Dwarf_pubnames_table::read_section): New function. (Dwarf_pubnames_table::read_header): New function. (Dwarf_pubnames_table::next_name): New function. (Dwarf_die::Dwarf_die): New function. (Dwarf_die::read_attributes): New function. (Dwarf_die::skip_attributes): New function. (Dwarf_die::set_name): New function. (Dwarf_die::set_linkage_name): New function. (Dwarf_die::attribute): New function. (Dwarf_die::string_attribute): New function. (Dwarf_die::int_attribute): New function. (Dwarf_die::uint_attribute): New function. (Dwarf_die::ref_attribute): New function. (Dwarf_die::child_offset): New function. (Dwarf_die::sibling_offset): New function. (Dwarf_info_reader::check_buffer): New function. (Dwarf_info_reader::parse): New function. (Dwarf_info_reader::do_parse): New function. (Dwarf_info_reader::do_read_string_table): New function. (Dwarf_info_reader::lookup_reloc): New function. (Dwarf_info_reader::get_string): New function. (Dwarf_info_reader::visit_compilation_unit): New function. (Dwarf_info_reader::visit_type_unit): New function. (Sized_dwarf_line_info::Sized_dwarf_line_info): Use Sized_elf_reloc_mapper. (Sized_dwarf_line_info::symbol_section): Remove function. (Sized_dwarf_line_info::read_relocs): Use Sized_elf_reloc_mapper. (Sized_dwarf_line_info::read_line_mappings): Remove object parameter, adjust callers. (Sized_dwarf_line_info::format_file_lineno): Fix type of cast. * dwarf_reader.h: Include <sys/types.h>. (class Track_relocs): Remove forward declaration. (class Elf_reloc_mapper): New class. (class Sized_elf_reloc_mapper): New class. (class Dwarf_abbrev_table): New class. (class Dwarf_range_list): New class. (class Dwarf_ranges_table): New class. (class Dwarf_pubnames_table): New class. (class Dwarf_die): New class. (class Dwarf_info_reader): New class. (Sized_dwarf_line_info::read_line_mappings): Remove object parameter. (Sized_dwarf_line_info::symbol_section): Remove member function. * dynobj.h (Sized_dynobj::do_section_contents): Refactor code from base class. * gdb-index.cc: New source file. * gdb-index.h: New source file. * incremental.cc (Sized_relobj_incr::do_layout): Track .debug_info and .debug_types sections, call Layout::add_to_gdb_index. (Sized_relobj_incr::do_section_name): Implement. (Sized_relobj_incr::do_section_contents): Adjust parameter list and return type; Implement. (Sized_incr_dynobj::do_section_contents): Adjust parameter list and return type. * incremental.h (Sized_relobj_incr::do_section_contents): Adjust parameter list and return type. (Sized_incr_dynobj::do_section_contents): Likewise. * layout.cc: Include gdb-index.h. (Layout::Layout): Initialize gdb_index_data_. (Layout::init_fixed_output_section): Check for .gdb_index section. (Layout::add_to_gdb_index): New function. Instantiate. * layout.h: Add forward declaration for class Gdb_index. (Layout::add_to_gdb_index): New member function. (Layout::gdb_index_data_): New data member. * main.cc: Include gdb-index.h. (main): Print statistics for gdb index. * object.cc (Object::section_contents): Move code into do_section_contents. (need_decompressed_section): Check for sections needed when building gdb index. (build_compressed_section_map): Likewise. (Sized_relobj_file::do_read_symbols): Need local symbols when building gdb index. (Sized_relobj_file::do_layout): Track .debug_info and .debug_types sections; call Layout::add_to_gdb_index. (Sized_relobj_file::do_decompressed_section_contents): Call do_section_contents directly. * object.h (Object::do_section_contents): Adjust parameter list and return type. (Object::do_decompressed_section_contents): Call do_section_contents directly. (Sized_relobj_file::do_section_contents): Adjust parameter list and return type. * options.h (class General_options): Add --gdb-index option. * plugin.cc (Sized_pluginobj::do_section_contents): Adjust parameter list and return type. * plugin.h (Sized_pluginobj::do_section_contents): Likewise. * reloc.h (Track_relocs::checkpoint): New function. (Track_relocs::reset): New function. * testsuite/Makefile.am (gdb_index_test_1.sh, gdb_index_test_2.sh): New test cases. * testsuite/Makefile.in: Regenerate. * testsuite/gdb_index_test.cc: New test source file. * testsuite/gdb_index_test_1.sh: New test source file. * testsuite/gdb_index_test_2.sh: New test source file.
This commit is contained in:
parent
bd0b9f9e12
commit
c1027032c2
109
gold/ChangeLog
109
gold/ChangeLog
@ -1,3 +1,112 @@
|
||||
2012-03-21 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
* Makefile.am: Add gdb-index.cc, gdb-index.h.
|
||||
* Makefile.in: Regenerate.
|
||||
* dwarf_reader.cc (Sized_elf_reloc_mapper::do_initialize): New function.
|
||||
(Sized_elf_reloc_mapper::symbol_section): New function.
|
||||
(Sized_elf_reloc_mapper::do_get_reloc_target): New function.
|
||||
(make_elf_reloc_mapper): New function.
|
||||
(Dwarf_abbrev_table::clear_abbrev_codes): New function.
|
||||
(Dwarf_abbrev_table::do_read_abbrevs): New function.
|
||||
(Dwarf_abbrev_table::do_get_abbrev): New function.
|
||||
(Dwarf_ranges_table::read_ranges_table): New function.
|
||||
(Dwarf_ranges_table::read_range_list): New function.
|
||||
(Dwarf_pubnames_table::read_section): New function.
|
||||
(Dwarf_pubnames_table::read_header): New function.
|
||||
(Dwarf_pubnames_table::next_name): New function.
|
||||
(Dwarf_die::Dwarf_die): New function.
|
||||
(Dwarf_die::read_attributes): New function.
|
||||
(Dwarf_die::skip_attributes): New function.
|
||||
(Dwarf_die::set_name): New function.
|
||||
(Dwarf_die::set_linkage_name): New function.
|
||||
(Dwarf_die::attribute): New function.
|
||||
(Dwarf_die::string_attribute): New function.
|
||||
(Dwarf_die::int_attribute): New function.
|
||||
(Dwarf_die::uint_attribute): New function.
|
||||
(Dwarf_die::ref_attribute): New function.
|
||||
(Dwarf_die::child_offset): New function.
|
||||
(Dwarf_die::sibling_offset): New function.
|
||||
(Dwarf_info_reader::check_buffer): New function.
|
||||
(Dwarf_info_reader::parse): New function.
|
||||
(Dwarf_info_reader::do_parse): New function.
|
||||
(Dwarf_info_reader::do_read_string_table): New function.
|
||||
(Dwarf_info_reader::lookup_reloc): New function.
|
||||
(Dwarf_info_reader::get_string): New function.
|
||||
(Dwarf_info_reader::visit_compilation_unit): New function.
|
||||
(Dwarf_info_reader::visit_type_unit): New function.
|
||||
(Sized_dwarf_line_info::Sized_dwarf_line_info): Use
|
||||
Sized_elf_reloc_mapper.
|
||||
(Sized_dwarf_line_info::symbol_section): Remove function.
|
||||
(Sized_dwarf_line_info::read_relocs): Use Sized_elf_reloc_mapper.
|
||||
(Sized_dwarf_line_info::read_line_mappings): Remove object
|
||||
parameter, adjust callers.
|
||||
(Sized_dwarf_line_info::format_file_lineno): Fix type of cast.
|
||||
* dwarf_reader.h: Include <sys/types.h>.
|
||||
(class Track_relocs): Remove forward declaration.
|
||||
(class Elf_reloc_mapper): New class.
|
||||
(class Sized_elf_reloc_mapper): New class.
|
||||
(class Dwarf_abbrev_table): New class.
|
||||
(class Dwarf_range_list): New class.
|
||||
(class Dwarf_ranges_table): New class.
|
||||
(class Dwarf_pubnames_table): New class.
|
||||
(class Dwarf_die): New class.
|
||||
(class Dwarf_info_reader): New class.
|
||||
(Sized_dwarf_line_info::read_line_mappings): Remove object parameter.
|
||||
(Sized_dwarf_line_info::symbol_section): Remove member function.
|
||||
* dynobj.h (Sized_dynobj::do_section_contents): Refactor code from
|
||||
base class.
|
||||
* gdb-index.cc: New source file.
|
||||
* gdb-index.h: New source file.
|
||||
* incremental.cc (Sized_relobj_incr::do_layout): Track .debug_info
|
||||
and .debug_types sections, call Layout::add_to_gdb_index.
|
||||
(Sized_relobj_incr::do_section_name): Implement.
|
||||
(Sized_relobj_incr::do_section_contents): Adjust parameter list and
|
||||
return type; Implement.
|
||||
(Sized_incr_dynobj::do_section_contents): Adjust parameter list and
|
||||
return type.
|
||||
* incremental.h (Sized_relobj_incr::do_section_contents): Adjust
|
||||
parameter list and return type.
|
||||
(Sized_incr_dynobj::do_section_contents): Likewise.
|
||||
* layout.cc: Include gdb-index.h.
|
||||
(Layout::Layout): Initialize gdb_index_data_.
|
||||
(Layout::init_fixed_output_section): Check for .gdb_index section.
|
||||
(Layout::add_to_gdb_index): New function. Instantiate.
|
||||
* layout.h: Add forward declaration for class Gdb_index.
|
||||
(Layout::add_to_gdb_index): New member function.
|
||||
(Layout::gdb_index_data_): New data member.
|
||||
* main.cc: Include gdb-index.h.
|
||||
(main): Print statistics for gdb index.
|
||||
* object.cc (Object::section_contents): Move code into
|
||||
do_section_contents.
|
||||
(need_decompressed_section): Check for sections needed when building
|
||||
gdb index.
|
||||
(build_compressed_section_map): Likewise.
|
||||
(Sized_relobj_file::do_read_symbols): Need local symbols when building
|
||||
gdb index.
|
||||
(Sized_relobj_file::do_layout): Track .debug_info and .debug_types
|
||||
sections; call Layout::add_to_gdb_index.
|
||||
(Sized_relobj_file::do_decompressed_section_contents): Call
|
||||
do_section_contents directly.
|
||||
* object.h (Object::do_section_contents): Adjust parameter list and
|
||||
return type.
|
||||
(Object::do_decompressed_section_contents): Call do_section_contents
|
||||
directly.
|
||||
(Sized_relobj_file::do_section_contents): Adjust parameter list and
|
||||
return type.
|
||||
* options.h (class General_options): Add --gdb-index option.
|
||||
* plugin.cc (Sized_pluginobj::do_section_contents): Adjust parameter
|
||||
list and return type.
|
||||
* plugin.h (Sized_pluginobj::do_section_contents): Likewise.
|
||||
* reloc.h (Track_relocs::checkpoint): New function.
|
||||
(Track_relocs::reset): New function.
|
||||
|
||||
* testsuite/Makefile.am (gdb_index_test_1.sh, gdb_index_test_2.sh):
|
||||
New test cases.
|
||||
* testsuite/Makefile.in: Regenerate.
|
||||
* testsuite/gdb_index_test.cc: New test source file.
|
||||
* testsuite/gdb_index_test_1.sh: New test source file.
|
||||
* testsuite/gdb_index_test_2.sh: New test source file.
|
||||
|
||||
2012-03-19 Doug Kwan <dougkwan@google.com>
|
||||
|
||||
* arm.cc (Target_arm::do_define_standard_symbols): New method.
|
||||
|
@ -55,6 +55,7 @@ CCFILES = \
|
||||
expression.cc \
|
||||
fileread.cc \
|
||||
gc.cc \
|
||||
gdb-index.cc \
|
||||
gold.cc \
|
||||
gold-threads.cc \
|
||||
icf.cc \
|
||||
@ -102,6 +103,7 @@ HFILES = \
|
||||
fileread.h \
|
||||
freebsd.h \
|
||||
gc.h \
|
||||
gdb-index.h \
|
||||
gold.h \
|
||||
gold-threads.h \
|
||||
icf.h \
|
||||
|
@ -77,11 +77,11 @@ am__objects_1 = archive.$(OBJEXT) attributes.$(OBJEXT) \
|
||||
descriptors.$(OBJEXT) dirsearch.$(OBJEXT) dynobj.$(OBJEXT) \
|
||||
dwarf_reader.$(OBJEXT) ehframe.$(OBJEXT) errors.$(OBJEXT) \
|
||||
expression.$(OBJEXT) fileread.$(OBJEXT) gc.$(OBJEXT) \
|
||||
gold.$(OBJEXT) gold-threads.$(OBJEXT) icf.$(OBJEXT) \
|
||||
incremental.$(OBJEXT) int_encoding.$(OBJEXT) layout.$(OBJEXT) \
|
||||
mapfile.$(OBJEXT) merge.$(OBJEXT) object.$(OBJEXT) \
|
||||
options.$(OBJEXT) output.$(OBJEXT) parameters.$(OBJEXT) \
|
||||
plugin.$(OBJEXT) readsyms.$(OBJEXT) \
|
||||
gdb-index.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
|
||||
icf.$(OBJEXT) incremental.$(OBJEXT) int_encoding.$(OBJEXT) \
|
||||
layout.$(OBJEXT) mapfile.$(OBJEXT) merge.$(OBJEXT) \
|
||||
object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \
|
||||
parameters.$(OBJEXT) plugin.$(OBJEXT) readsyms.$(OBJEXT) \
|
||||
reduced_debug_output.$(OBJEXT) reloc.$(OBJEXT) \
|
||||
resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \
|
||||
stringpool.$(OBJEXT) symtab.$(OBJEXT) target.$(OBJEXT) \
|
||||
@ -399,6 +399,7 @@ CCFILES = \
|
||||
expression.cc \
|
||||
fileread.cc \
|
||||
gc.cc \
|
||||
gdb-index.cc \
|
||||
gold.cc \
|
||||
gold-threads.cc \
|
||||
icf.cc \
|
||||
@ -446,6 +447,7 @@ HFILES = \
|
||||
fileread.h \
|
||||
freebsd.h \
|
||||
gc.h \
|
||||
gdb-index.h \
|
||||
gold.h \
|
||||
gold-threads.h \
|
||||
icf.h \
|
||||
@ -650,6 +652,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expression.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gc.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdb-index.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386.Po@am__quote@
|
||||
|
1440
gold/dwarf_reader.cc
1440
gold/dwarf_reader.cc
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
// dwarf_reader.h -- parse dwarf2/3 debug information for gold -*- C++ -*-
|
||||
|
||||
// Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
// Copyright 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
|
||||
// Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
@ -26,6 +26,7 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "elfcpp_swap.h"
|
||||
@ -35,10 +36,815 @@
|
||||
namespace gold
|
||||
{
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Track_relocs;
|
||||
class Dwarf_info_reader;
|
||||
struct LineStateMachine;
|
||||
|
||||
// This class is used to extract the section index and offset of
|
||||
// the target of a relocation for a given offset within the section.
|
||||
|
||||
class Elf_reloc_mapper
|
||||
{
|
||||
public:
|
||||
Elf_reloc_mapper()
|
||||
{ }
|
||||
|
||||
virtual
|
||||
~Elf_reloc_mapper()
|
||||
{ }
|
||||
|
||||
// Initialize the relocation tracker for section RELOC_SHNDX.
|
||||
bool
|
||||
initialize(unsigned int reloc_shndx, unsigned int reloc_type)
|
||||
{ return this->do_initialize(reloc_shndx, reloc_type); }
|
||||
|
||||
// Return the next reloc_offset.
|
||||
off_t
|
||||
next_offset()
|
||||
{ return this->do_next_offset(); }
|
||||
|
||||
// Advance to the next relocation past OFFSET.
|
||||
void
|
||||
advance(off_t offset)
|
||||
{ this->do_advance(offset); }
|
||||
|
||||
// Return the section index and offset within the section of the target
|
||||
// of the relocation for RELOC_OFFSET in the referring section.
|
||||
unsigned int
|
||||
get_reloc_target(off_t reloc_offset, off_t* target_offset)
|
||||
{ return this->do_get_reloc_target(reloc_offset, target_offset); }
|
||||
|
||||
// Checkpoint the current position in the reloc section.
|
||||
uint64_t
|
||||
checkpoint() const
|
||||
{ return this->do_checkpoint(); }
|
||||
|
||||
// Reset the current position to the CHECKPOINT.
|
||||
void
|
||||
reset(uint64_t checkpoint)
|
||||
{ this->do_reset(checkpoint); }
|
||||
|
||||
protected:
|
||||
virtual bool
|
||||
do_initialize(unsigned int, unsigned int) = 0;
|
||||
|
||||
// Return the next reloc_offset.
|
||||
virtual off_t
|
||||
do_next_offset() = 0;
|
||||
|
||||
// Advance to the next relocation past OFFSET.
|
||||
virtual void
|
||||
do_advance(off_t offset) = 0;
|
||||
|
||||
virtual unsigned int
|
||||
do_get_reloc_target(off_t reloc_offset, off_t* target_offset) = 0;
|
||||
|
||||
// Checkpoint the current position in the reloc section.
|
||||
virtual uint64_t
|
||||
do_checkpoint() const = 0;
|
||||
|
||||
// Reset the current position to the CHECKPOINT.
|
||||
virtual void
|
||||
do_reset(uint64_t checkpoint) = 0;
|
||||
};
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Sized_elf_reloc_mapper : public Elf_reloc_mapper
|
||||
{
|
||||
public:
|
||||
Sized_elf_reloc_mapper(Object* object, const unsigned char* symtab,
|
||||
off_t symtab_size)
|
||||
: object_(object), symtab_(symtab), symtab_size_(symtab_size),
|
||||
reloc_type_(0), track_relocs_()
|
||||
{ }
|
||||
|
||||
protected:
|
||||
bool
|
||||
do_initialize(unsigned int reloc_shndx, unsigned int reloc_type);
|
||||
|
||||
// Return the next reloc_offset.
|
||||
virtual off_t
|
||||
do_next_offset()
|
||||
{ return this->track_relocs_.next_offset(); }
|
||||
|
||||
// Advance to the next relocation past OFFSET.
|
||||
virtual void
|
||||
do_advance(off_t offset)
|
||||
{ this->track_relocs_.advance(offset); }
|
||||
|
||||
unsigned int
|
||||
do_get_reloc_target(off_t reloc_offset, off_t* target_offset);
|
||||
|
||||
// Checkpoint the current position in the reloc section.
|
||||
uint64_t
|
||||
do_checkpoint() const
|
||||
{ return this->track_relocs_.checkpoint(); }
|
||||
|
||||
// Reset the current position to the CHECKPOINT.
|
||||
void
|
||||
do_reset(uint64_t checkpoint)
|
||||
{ this->track_relocs_.reset(checkpoint); }
|
||||
|
||||
private:
|
||||
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
|
||||
|
||||
// Return the section index of symbol SYMNDX, and copy its value to *VALUE.
|
||||
// Set *IS_ORDINARY true if the section index is an ordinary section index.
|
||||
unsigned int
|
||||
symbol_section(unsigned int symndx, Address* value, bool* is_ordinary);
|
||||
|
||||
// The object file.
|
||||
Object* object_;
|
||||
// The ELF symbol table.
|
||||
const unsigned char* symtab_;
|
||||
// The size of the ELF symbol table.
|
||||
off_t symtab_size_;
|
||||
// Type of the relocation section (SHT_REL or SHT_RELA).
|
||||
unsigned int reloc_type_;
|
||||
// Relocations for the referring section.
|
||||
Track_relocs<size, big_endian> track_relocs_;
|
||||
};
|
||||
|
||||
// This class is used to read the abbreviations table from the
|
||||
// .debug_abbrev section of the object file.
|
||||
|
||||
class Dwarf_abbrev_table
|
||||
{
|
||||
public:
|
||||
// An attribute list entry.
|
||||
struct Attribute
|
||||
{
|
||||
Attribute(unsigned int a, unsigned int f)
|
||||
: attr(a), form(f)
|
||||
{ }
|
||||
unsigned int attr;
|
||||
unsigned int form;
|
||||
};
|
||||
|
||||
// An abbrev code entry.
|
||||
struct Abbrev_code
|
||||
{
|
||||
Abbrev_code(unsigned int t, bool hc)
|
||||
: tag(t), has_children(hc), has_sibling_attribute(false), attributes()
|
||||
{
|
||||
this->attributes.reserve(10);
|
||||
}
|
||||
|
||||
void
|
||||
add_attribute(unsigned int attr, unsigned int form)
|
||||
{
|
||||
this->attributes.push_back(Attribute(attr, form));
|
||||
}
|
||||
|
||||
// The DWARF tag.
|
||||
unsigned int tag;
|
||||
// True if the DIE has children.
|
||||
bool has_children : 1;
|
||||
// True if the DIE has a sibling attribute.
|
||||
bool has_sibling_attribute : 1;
|
||||
// The list of attributes and forms.
|
||||
std::vector<Attribute> attributes;
|
||||
};
|
||||
|
||||
Dwarf_abbrev_table()
|
||||
: abbrev_shndx_(0), abbrev_offset_(0), buffer_(NULL), buffer_end_(NULL),
|
||||
owns_buffer_(false), buffer_pos_(NULL), high_abbrev_codes_()
|
||||
{
|
||||
memset(this->low_abbrev_codes_, 0, sizeof(this->low_abbrev_codes_));
|
||||
}
|
||||
|
||||
~Dwarf_abbrev_table()
|
||||
{
|
||||
if (this->owns_buffer_ && this->buffer_ != NULL)
|
||||
delete[] this->buffer_;
|
||||
this->clear_abbrev_codes();
|
||||
}
|
||||
|
||||
// Read the abbrev table from an object file.
|
||||
bool
|
||||
read_abbrevs(Relobj* object,
|
||||
unsigned int abbrev_shndx,
|
||||
off_t abbrev_offset)
|
||||
{
|
||||
// If we've already read this abbrev table, return immediately.
|
||||
if (this->abbrev_shndx_ > 0
|
||||
&& this->abbrev_shndx_ == abbrev_shndx
|
||||
&& this->abbrev_offset_ == abbrev_offset)
|
||||
return true;
|
||||
return this->do_read_abbrevs(object, abbrev_shndx, abbrev_offset);
|
||||
}
|
||||
|
||||
// Return the abbrev code entry for CODE. This is a fast path for
|
||||
// abbrev codes that are in the direct lookup table. If not found
|
||||
// there, we call do_get_abbrev() to do the hard work.
|
||||
const Abbrev_code*
|
||||
get_abbrev(unsigned int code)
|
||||
{
|
||||
if (code < this->low_abbrev_code_max_
|
||||
&& this->low_abbrev_codes_[code] != NULL)
|
||||
return this->low_abbrev_codes_[code];
|
||||
return this->do_get_abbrev(code);
|
||||
}
|
||||
|
||||
private:
|
||||
// Read the abbrev table from an object file.
|
||||
bool
|
||||
do_read_abbrevs(Relobj* object,
|
||||
unsigned int abbrev_shndx,
|
||||
off_t abbrev_offset);
|
||||
|
||||
// Lookup the abbrev code entry for CODE.
|
||||
const Abbrev_code*
|
||||
do_get_abbrev(unsigned int code);
|
||||
|
||||
// Store an abbrev code entry for CODE.
|
||||
void
|
||||
store_abbrev(unsigned int code, const Abbrev_code* entry)
|
||||
{
|
||||
if (code < this->low_abbrev_code_max_)
|
||||
this->low_abbrev_codes_[code] = entry;
|
||||
else
|
||||
this->high_abbrev_codes_[code] = entry;
|
||||
}
|
||||
|
||||
// Clear the abbrev code table and release the memory it uses.
|
||||
void
|
||||
clear_abbrev_codes();
|
||||
|
||||
typedef Unordered_map<unsigned int, const Abbrev_code*> Abbrev_code_table;
|
||||
|
||||
// The section index of the current abbrev table.
|
||||
unsigned int abbrev_shndx_;
|
||||
// The offset within the section of the current abbrev table.
|
||||
off_t abbrev_offset_;
|
||||
// The buffer containing the .debug_abbrev section.
|
||||
const unsigned char* buffer_;
|
||||
const unsigned char* buffer_end_;
|
||||
// True if this object owns the buffer and needs to delete it.
|
||||
bool owns_buffer_;
|
||||
// Pointer to the current position in the buffer.
|
||||
const unsigned char* buffer_pos_;
|
||||
// The table of abbrev codes.
|
||||
// We use a direct-lookup array for low abbrev codes,
|
||||
// and store the rest in a hash table.
|
||||
static const unsigned int low_abbrev_code_max_ = 256;
|
||||
const Abbrev_code* low_abbrev_codes_[low_abbrev_code_max_];
|
||||
Abbrev_code_table high_abbrev_codes_;
|
||||
};
|
||||
|
||||
// A DWARF range list. The start and end offsets are relative
|
||||
// to the input section SHNDX. Each range must lie entirely
|
||||
// within a single section.
|
||||
|
||||
class Dwarf_range_list
|
||||
{
|
||||
public:
|
||||
struct Range
|
||||
{
|
||||
Range(unsigned int a_shndx, off_t a_start, off_t a_end)
|
||||
: shndx(a_shndx), start(a_start), end(a_end)
|
||||
{ }
|
||||
|
||||
unsigned int shndx;
|
||||
off_t start;
|
||||
off_t end;
|
||||
};
|
||||
|
||||
Dwarf_range_list()
|
||||
: range_list_()
|
||||
{ }
|
||||
|
||||
void
|
||||
add(unsigned int shndx, off_t start, off_t end)
|
||||
{ this->range_list_.push_back(Range(shndx, start, end)); }
|
||||
|
||||
size_t
|
||||
size() const
|
||||
{ return this->range_list_.size(); }
|
||||
|
||||
const Range&
|
||||
operator[](off_t i) const
|
||||
{ return this->range_list_[i]; }
|
||||
|
||||
private:
|
||||
std::vector<Range> range_list_;
|
||||
};
|
||||
|
||||
// This class is used to read the ranges table from the
|
||||
// .debug_ranges section of the object file.
|
||||
|
||||
class Dwarf_ranges_table
|
||||
{
|
||||
public:
|
||||
Dwarf_ranges_table()
|
||||
: ranges_shndx_(0), ranges_buffer_(NULL), ranges_buffer_end_(NULL),
|
||||
owns_ranges_buffer_(false), ranges_reloc_mapper_(NULL),
|
||||
output_section_offset_(0)
|
||||
{ }
|
||||
|
||||
~Dwarf_ranges_table()
|
||||
{
|
||||
if (this->owns_ranges_buffer_ && this->ranges_buffer_ != NULL)
|
||||
delete[] this->ranges_buffer_;
|
||||
if (this->ranges_reloc_mapper_ != NULL)
|
||||
delete this->ranges_reloc_mapper_;
|
||||
}
|
||||
|
||||
// Read the ranges table from an object file.
|
||||
bool
|
||||
read_ranges_table(Relobj* object,
|
||||
const unsigned char* symtab,
|
||||
off_t symtab_size,
|
||||
unsigned int ranges_shndx);
|
||||
|
||||
// Read the range table from an object file.
|
||||
Dwarf_range_list*
|
||||
read_range_list(Relobj* object,
|
||||
const unsigned char* symtab,
|
||||
off_t symtab_size,
|
||||
unsigned int address_size,
|
||||
unsigned int ranges_shndx,
|
||||
off_t ranges_offset);
|
||||
|
||||
private:
|
||||
// The section index of the ranges table.
|
||||
unsigned int ranges_shndx_;
|
||||
// The buffer containing the .debug_ranges section.
|
||||
const unsigned char* ranges_buffer_;
|
||||
const unsigned char* ranges_buffer_end_;
|
||||
// True if this object owns the buffer and needs to delete it.
|
||||
bool owns_ranges_buffer_;
|
||||
// Relocation mapper for the .debug_ranges section.
|
||||
Elf_reloc_mapper* ranges_reloc_mapper_;
|
||||
// For incremental update links, this will hold the offset of the
|
||||
// input section within the output section. Offsets read from
|
||||
// relocated data will be relative to the output section, and need
|
||||
// to be corrected before reading data from the input section.
|
||||
uint64_t output_section_offset_;
|
||||
};
|
||||
|
||||
// This class is used to read the pubnames and pubtypes tables from the
|
||||
// .debug_pubnames and .debug_pubtypes sections of the object file.
|
||||
|
||||
class Dwarf_pubnames_table
|
||||
{
|
||||
public:
|
||||
Dwarf_pubnames_table(bool is_pubtypes)
|
||||
: buffer_(NULL), buffer_end_(NULL), owns_buffer_(false),
|
||||
offset_size_(0), pinfo_(NULL), is_pubtypes_(is_pubtypes),
|
||||
output_section_offset_(0)
|
||||
{ }
|
||||
|
||||
~Dwarf_pubnames_table()
|
||||
{
|
||||
if (this->owns_buffer_ && this->buffer_ != NULL)
|
||||
delete[] this->buffer_;
|
||||
}
|
||||
|
||||
// Read the pubnames section SHNDX from the object file.
|
||||
bool
|
||||
read_section(Relobj* object, unsigned int shndx);
|
||||
|
||||
// Read the header for the set at OFFSET.
|
||||
bool
|
||||
read_header(off_t offset);
|
||||
|
||||
// Read the next name from the set.
|
||||
const char*
|
||||
next_name();
|
||||
|
||||
private:
|
||||
// The buffer containing the .debug_ranges section.
|
||||
const unsigned char* buffer_;
|
||||
const unsigned char* buffer_end_;
|
||||
// True if this object owns the buffer and needs to delete it.
|
||||
bool owns_buffer_;
|
||||
// The size of a DWARF offset for the current set.
|
||||
unsigned int offset_size_;
|
||||
// The current position within the buffer.
|
||||
const unsigned char* pinfo_;
|
||||
// TRUE if this is a .debug_pubtypes section.
|
||||
bool is_pubtypes_;
|
||||
// For incremental update links, this will hold the offset of the
|
||||
// input section within the output section. Offsets read from
|
||||
// relocated data will be relative to the output section, and need
|
||||
// to be corrected before reading data from the input section.
|
||||
uint64_t output_section_offset_;
|
||||
};
|
||||
|
||||
// This class represents a DWARF Debug Info Entry (DIE).
|
||||
|
||||
class Dwarf_die
|
||||
{
|
||||
public:
|
||||
// An attribute value.
|
||||
struct Attribute_value
|
||||
{
|
||||
unsigned int attr;
|
||||
unsigned int form;
|
||||
union
|
||||
{
|
||||
int64_t intval;
|
||||
uint64_t uintval;
|
||||
const char* stringval;
|
||||
const unsigned char* blockval;
|
||||
off_t refval;
|
||||
} val;
|
||||
union
|
||||
{
|
||||
// Section index for reference forms.
|
||||
unsigned int shndx;
|
||||
// Block length for block forms.
|
||||
unsigned int blocklen;
|
||||
// Attribute offset for DW_FORM_strp.
|
||||
unsigned int attr_off;
|
||||
} aux;
|
||||
};
|
||||
|
||||
// A list of attribute values.
|
||||
typedef std::vector<Attribute_value> Attributes;
|
||||
|
||||
Dwarf_die(Dwarf_info_reader* dwinfo,
|
||||
off_t die_offset,
|
||||
Dwarf_die* parent);
|
||||
|
||||
// Return the DWARF tag for this DIE.
|
||||
unsigned int
|
||||
tag() const
|
||||
{
|
||||
if (this->abbrev_code_ == NULL)
|
||||
return 0;
|
||||
return this->abbrev_code_->tag;
|
||||
}
|
||||
|
||||
// Return true if this DIE has children.
|
||||
bool
|
||||
has_children() const
|
||||
{
|
||||
gold_assert(this->abbrev_code_ != NULL);
|
||||
return this->abbrev_code_->has_children;
|
||||
}
|
||||
|
||||
// Return true if this DIE has a sibling attribute.
|
||||
bool
|
||||
has_sibling_attribute() const
|
||||
{
|
||||
gold_assert(this->abbrev_code_ != NULL);
|
||||
return this->abbrev_code_->has_sibling_attribute;
|
||||
}
|
||||
|
||||
// Return the value of attribute ATTR.
|
||||
const Attribute_value*
|
||||
attribute(unsigned int attr);
|
||||
|
||||
// Return the value of the DW_AT_name attribute.
|
||||
const char*
|
||||
name()
|
||||
{
|
||||
if (this->name_ == NULL)
|
||||
this->set_name();
|
||||
return this->name_;
|
||||
}
|
||||
|
||||
// Return the value of the DW_AT_linkage_name
|
||||
// or DW_AT_MIPS_linkage_name attribute.
|
||||
const char*
|
||||
linkage_name()
|
||||
{
|
||||
if (this->linkage_name_ == NULL)
|
||||
this->set_linkage_name();
|
||||
return this->linkage_name_;
|
||||
}
|
||||
|
||||
// Return the value of the DW_AT_specification attribute.
|
||||
off_t
|
||||
specification()
|
||||
{
|
||||
if (!this->attributes_read_)
|
||||
this->read_attributes();
|
||||
return this->specification_;
|
||||
}
|
||||
|
||||
// Return the value of the DW_AT_abstract_origin attribute.
|
||||
off_t
|
||||
abstract_origin()
|
||||
{
|
||||
if (!this->attributes_read_)
|
||||
this->read_attributes();
|
||||
return this->abstract_origin_;
|
||||
}
|
||||
|
||||
// Return the value of attribute ATTR as a string.
|
||||
const char*
|
||||
string_attribute(unsigned int attr);
|
||||
|
||||
// Return the value of attribute ATTR as an integer.
|
||||
int64_t
|
||||
int_attribute(unsigned int attr);
|
||||
|
||||
// Return the value of attribute ATTR as an unsigned integer.
|
||||
uint64_t
|
||||
uint_attribute(unsigned int attr);
|
||||
|
||||
// Return the value of attribute ATTR as a reference.
|
||||
off_t
|
||||
ref_attribute(unsigned int attr,
|
||||
unsigned int* shndx);
|
||||
|
||||
// Return the value of attribute ATTR as a flag.
|
||||
bool
|
||||
flag_attribute(unsigned int attr)
|
||||
{ return this->int_attribute(attr) != 0; }
|
||||
|
||||
// Return true if this DIE is a declaration.
|
||||
bool
|
||||
is_declaration()
|
||||
{ return this->flag_attribute(elfcpp::DW_AT_declaration); }
|
||||
|
||||
// Return the parent of this DIE.
|
||||
Dwarf_die*
|
||||
parent() const
|
||||
{ return this->parent_; }
|
||||
|
||||
// Return the offset of this DIE.
|
||||
off_t
|
||||
offset() const
|
||||
{ return this->die_offset_; }
|
||||
|
||||
// Return the offset of this DIE's first child.
|
||||
off_t
|
||||
child_offset();
|
||||
|
||||
// Set the offset of this DIE's next sibling.
|
||||
void
|
||||
set_sibling_offset(off_t sibling_offset)
|
||||
{ this->sibling_offset_ = sibling_offset; }
|
||||
|
||||
// Return the offset of this DIE's next sibling.
|
||||
off_t
|
||||
sibling_offset();
|
||||
|
||||
private:
|
||||
typedef Dwarf_abbrev_table::Abbrev_code Abbrev_code;
|
||||
|
||||
// Read all the attributes of the DIE.
|
||||
bool
|
||||
read_attributes();
|
||||
|
||||
// Set the name of the DIE if present.
|
||||
void
|
||||
set_name();
|
||||
|
||||
// Set the linkage name if present.
|
||||
void
|
||||
set_linkage_name();
|
||||
|
||||
// Skip all the attributes of the DIE and return the offset
|
||||
// of the next DIE.
|
||||
off_t
|
||||
skip_attributes();
|
||||
|
||||
// The Dwarf_info_reader, for reading attributes.
|
||||
Dwarf_info_reader* dwinfo_;
|
||||
// The parent of this DIE.
|
||||
Dwarf_die* parent_;
|
||||
// Offset of this DIE within its compilation unit.
|
||||
off_t die_offset_;
|
||||
// Offset of the first attribute, relative to the beginning of the DIE.
|
||||
off_t attr_offset_;
|
||||
// Offset of the first child, relative to the compilation unit.
|
||||
off_t child_offset_;
|
||||
// Offset of the next sibling, relative to the compilation unit.
|
||||
off_t sibling_offset_;
|
||||
// The abbreviation table entry.
|
||||
const Abbrev_code* abbrev_code_;
|
||||
// The list of attributes.
|
||||
Attributes attributes_;
|
||||
// True if the attributes have been read.
|
||||
bool attributes_read_;
|
||||
// The following fields hold common attributes to avoid a linear
|
||||
// search through the attribute list.
|
||||
// The DIE name (DW_AT_name).
|
||||
const char* name_;
|
||||
// Offset of the name in the string table (for DW_FORM_strp).
|
||||
off_t name_off_;
|
||||
// The linkage name (DW_AT_linkage_name or DW_AT_MIPS_linkage_name).
|
||||
const char* linkage_name_;
|
||||
// Offset of the linkage name in the string table (for DW_FORM_strp).
|
||||
off_t linkage_name_off_;
|
||||
// Section index of the string table (for DW_FORM_strp).
|
||||
unsigned int string_shndx_;
|
||||
// The value of a DW_AT_specification attribute.
|
||||
off_t specification_;
|
||||
// The value of a DW_AT_abstract_origin attribute.
|
||||
off_t abstract_origin_;
|
||||
};
|
||||
|
||||
// This class is used to read the debug info from the .debug_info
|
||||
// or .debug_types sections. This is a base class that implements
|
||||
// the generic parsing of the compilation unit header and DIE
|
||||
// structure. The parse() method parses the entire section, and
|
||||
// calls the various visit_xxx() methods for each header. Clients
|
||||
// should derive a new class from this one and implement the
|
||||
// visit_compilation_unit() and visit_type_unit() functions.
|
||||
|
||||
class Dwarf_info_reader
|
||||
{
|
||||
public:
|
||||
Dwarf_info_reader(bool is_type_unit,
|
||||
Relobj* object,
|
||||
const unsigned char* symtab,
|
||||
off_t symtab_size,
|
||||
unsigned int shndx,
|
||||
unsigned int reloc_shndx,
|
||||
unsigned int reloc_type)
|
||||
: is_type_unit_(is_type_unit), object_(object), symtab_(symtab),
|
||||
symtab_size_(symtab_size), shndx_(shndx), reloc_shndx_(reloc_shndx),
|
||||
reloc_type_(reloc_type), string_shndx_(0), buffer_(NULL),
|
||||
buffer_end_(NULL), cu_offset_(0), cu_length_(0), offset_size_(0),
|
||||
address_size_(0), cu_version_(0), type_signature_(0), type_offset_(0),
|
||||
abbrev_table_(), reloc_mapper_(NULL), string_buffer_(NULL),
|
||||
string_buffer_end_(NULL), owns_string_buffer_(false),
|
||||
string_output_section_offset_(0)
|
||||
{ }
|
||||
|
||||
virtual
|
||||
~Dwarf_info_reader()
|
||||
{
|
||||
if (this->reloc_mapper_ != NULL)
|
||||
delete this->reloc_mapper_;
|
||||
if (this->owns_string_buffer_ && this->string_buffer_ != NULL)
|
||||
delete[] this->string_buffer_;
|
||||
}
|
||||
|
||||
// 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
|
||||
parse();
|
||||
|
||||
// Return the abbrev code entry for a CODE.
|
||||
const Dwarf_abbrev_table::Abbrev_code*
|
||||
get_abbrev(unsigned int code)
|
||||
{ return this->abbrev_table_.get_abbrev(code); }
|
||||
|
||||
// Return a pointer to the DWARF info buffer at OFFSET.
|
||||
const unsigned char*
|
||||
buffer_at_offset(off_t offset) const
|
||||
{
|
||||
const unsigned char* p = this->buffer_ + this->cu_offset_ + offset;
|
||||
if (this->check_buffer(p + 1))
|
||||
return p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Look for a relocation at offset ATTR_OFF in the dwarf info,
|
||||
// and return the section index and offset of the target.
|
||||
unsigned int
|
||||
lookup_reloc(off_t attr_off, off_t* target_off);
|
||||
|
||||
// Return a string from the DWARF string table.
|
||||
const char*
|
||||
get_string(off_t str_off, unsigned int string_shndx);
|
||||
|
||||
// Return the size of a DWARF offset.
|
||||
unsigned int
|
||||
offset_size() const
|
||||
{ return this->offset_size_; }
|
||||
|
||||
// Return the size of an address.
|
||||
unsigned int
|
||||
address_size() const
|
||||
{ return this->address_size_; }
|
||||
|
||||
protected:
|
||||
// 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.
|
||||
template<bool big_endian>
|
||||
void
|
||||
do_parse();
|
||||
|
||||
// The following methods are hooks that are meant to be implemented
|
||||
// by a derived class. A default, do-nothing, implementation of
|
||||
// each is provided for this base class.
|
||||
|
||||
// Visit a compilation unit.
|
||||
virtual void
|
||||
visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die* root_die);
|
||||
|
||||
// Visit a type unit.
|
||||
virtual void
|
||||
visit_type_unit(off_t tu_offset, off_t type_offset, uint64_t signature,
|
||||
Dwarf_die* root_die);
|
||||
|
||||
// Read the range table.
|
||||
Dwarf_range_list*
|
||||
read_range_list(unsigned int ranges_shndx, off_t ranges_offset)
|
||||
{
|
||||
return this->ranges_table_.read_range_list(this->object_,
|
||||
this->symtab_,
|
||||
this->symtab_size_,
|
||||
this->address_size_,
|
||||
ranges_shndx,
|
||||
ranges_offset);
|
||||
}
|
||||
|
||||
// Return the object.
|
||||
Relobj*
|
||||
object() const
|
||||
{ return this->object_; }
|
||||
|
||||
// Return a pointer to the object file's ELF symbol table.
|
||||
const unsigned char*
|
||||
symtab() const
|
||||
{ return this->symtab_; }
|
||||
|
||||
// Return the size of the object file's ELF symbol table.
|
||||
off_t
|
||||
symtab_size() const
|
||||
{ return this->symtab_size_; }
|
||||
|
||||
// Checkpoint the relocation tracker.
|
||||
uint64_t
|
||||
get_reloc_checkpoint() const
|
||||
{ return this->reloc_mapper_->checkpoint(); }
|
||||
|
||||
// Reset the relocation tracker to the CHECKPOINT.
|
||||
void
|
||||
reset_relocs(uint64_t checkpoint)
|
||||
{ this->reloc_mapper_->reset(checkpoint); }
|
||||
|
||||
private:
|
||||
// Check that P is within the bounds of the current section.
|
||||
bool
|
||||
check_buffer(const unsigned char* p) const;
|
||||
|
||||
// Read the DWARF string table.
|
||||
bool
|
||||
read_string_table(unsigned int string_shndx)
|
||||
{
|
||||
// If we've already read this string table, return immediately.
|
||||
if (this->string_shndx_ > 0 && this->string_shndx_ == string_shndx)
|
||||
return true;
|
||||
if (string_shndx == 0 && this->string_shndx_ > 0)
|
||||
return true;
|
||||
return this->do_read_string_table(string_shndx);
|
||||
}
|
||||
|
||||
bool
|
||||
do_read_string_table(unsigned int string_shndx);
|
||||
|
||||
// True if this is a type unit; false for a compilation unit.
|
||||
bool is_type_unit_;
|
||||
// The object containing the .debug_info or .debug_types input section.
|
||||
Relobj* object_;
|
||||
// The ELF symbol table.
|
||||
const unsigned char* symtab_;
|
||||
// The size of the ELF symbol table.
|
||||
off_t symtab_size_;
|
||||
// Index of the .debug_info or .debug_types section.
|
||||
unsigned int shndx_;
|
||||
// Index of the relocation section.
|
||||
unsigned int reloc_shndx_;
|
||||
// Type of the relocation section (SHT_REL or SHT_RELA).
|
||||
unsigned int reloc_type_;
|
||||
// Index of the .debug_str section.
|
||||
unsigned int string_shndx_;
|
||||
// The buffer for the debug info.
|
||||
const unsigned char* buffer_;
|
||||
const unsigned char* buffer_end_;
|
||||
// Offset of the current compilation unit.
|
||||
off_t cu_offset_;
|
||||
// Length of the current compilation unit.
|
||||
off_t cu_length_;
|
||||
// Size of a DWARF offset for the current compilation unit.
|
||||
unsigned int offset_size_;
|
||||
// Size of an address for the target architecture.
|
||||
unsigned int address_size_;
|
||||
// Compilation unit version number.
|
||||
unsigned int cu_version_;
|
||||
// Type signature (for a type unit).
|
||||
uint64_t type_signature_;
|
||||
// Offset from the type unit header to the type DIE (for a type unit).
|
||||
off_t type_offset_;
|
||||
// Abbreviations table for current compilation unit.
|
||||
Dwarf_abbrev_table abbrev_table_;
|
||||
// Ranges table for the current compilation unit.
|
||||
Dwarf_ranges_table ranges_table_;
|
||||
// Relocation mapper for the section.
|
||||
Elf_reloc_mapper* reloc_mapper_;
|
||||
// The buffer for the debug string table.
|
||||
const char* string_buffer_;
|
||||
const char* string_buffer_end_;
|
||||
// True if this object owns the buffer and needs to delete it.
|
||||
bool owns_string_buffer_;
|
||||
// For incremental update links, this will hold the offset of the
|
||||
// input .debug_str section within the output section. Offsets read
|
||||
// from relocated data will be relative to the output section, and need
|
||||
// to be corrected before reading data from the input section.
|
||||
uint64_t string_output_section_offset_;
|
||||
};
|
||||
|
||||
// We can't do better than to keep the offsets in a sorted vector.
|
||||
// Here, offset is the key, and file_num/line_num is the value.
|
||||
struct Offset_to_lineno_entry
|
||||
@ -140,18 +946,12 @@ class Sized_dwarf_line_info : public Dwarf_line_info
|
||||
// If SHNDX is non-negative, only store debug information that
|
||||
// pertains to the specified section.
|
||||
void
|
||||
read_line_mappings(Object*, unsigned int shndx);
|
||||
read_line_mappings(unsigned int shndx);
|
||||
|
||||
// Reads the relocation section associated with .debug_line and
|
||||
// stores relocation information in reloc_map_.
|
||||
void
|
||||
read_relocs(Object*);
|
||||
|
||||
// Looks in the symtab to see what section a symbol is in.
|
||||
unsigned int
|
||||
symbol_section(Object*, unsigned int sym,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr* value,
|
||||
bool* is_ordinary);
|
||||
read_relocs();
|
||||
|
||||
// Reads the DWARF2/3 header for this line info. Each takes as input
|
||||
// a starting buffer position, and returns the ending position.
|
||||
@ -212,7 +1012,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info
|
||||
const unsigned char* buffer_start_;
|
||||
|
||||
// This has relocations that point into buffer.
|
||||
Track_relocs<size, big_endian> track_relocs_;
|
||||
Sized_elf_reloc_mapper<size, big_endian>* reloc_mapper_;
|
||||
// The type of the reloc section in track_relocs_--SHT_REL or SHT_RELA.
|
||||
unsigned int track_relocs_type_;
|
||||
|
||||
@ -232,9 +1032,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info
|
||||
|
||||
// A sorted map from offset of the relocation target to the shndx
|
||||
// and addend for the relocation.
|
||||
typedef std::map<typename elfcpp::Elf_types<size>::Elf_Addr,
|
||||
std::pair<unsigned int,
|
||||
typename elfcpp::Elf_types<size>::Elf_Swxword> >
|
||||
typedef std::map<off_t, std::pair<unsigned int, off_t> >
|
||||
Reloc_map;
|
||||
Reloc_map reloc_map_;
|
||||
|
||||
|
@ -208,9 +208,19 @@ class Sized_dynobj : public Dynobj
|
||||
|
||||
// Return a view of the contents of a section. Set *PLEN to the
|
||||
// size.
|
||||
Object::Location
|
||||
do_section_contents(unsigned int shndx)
|
||||
{ return this->elf_file_.section_contents(shndx); }
|
||||
const unsigned char*
|
||||
do_section_contents(unsigned int shndx, section_size_type* plen,
|
||||
bool cache)
|
||||
{
|
||||
Location loc(this->elf_file_.section_contents(shndx));
|
||||
*plen = convert_to_section_size_type(loc.data_size);
|
||||
if (*plen == 0)
|
||||
{
|
||||
static const unsigned char empty[1] = { '\0' };
|
||||
return empty;
|
||||
}
|
||||
return this->get_view(loc.file_offset, *plen, true, cache);
|
||||
}
|
||||
|
||||
// Return section flags.
|
||||
uint64_t
|
||||
|
1229
gold/gdb-index.cc
Normal file
1229
gold/gdb-index.cc
Normal file
File diff suppressed because it is too large
Load Diff
213
gold/gdb-index.h
Normal file
213
gold/gdb-index.h
Normal file
@ -0,0 +1,213 @@
|
||||
// gdb-index.h -- generate .gdb_index section for fast debug lookup -*- C++ -*-
|
||||
|
||||
// Copyright 2012 Free Software Foundation, Inc.
|
||||
// Written by Cary Coutant <ccoutant@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <vector>
|
||||
|
||||
#include "gold.h"
|
||||
#include "output.h"
|
||||
#include "mapfile.h"
|
||||
#include "stringpool.h"
|
||||
|
||||
#ifndef GOLD_GDB_INDEX_H
|
||||
#define GOLD_GDB_INDEX_H
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Output_section;
|
||||
class Output_file;
|
||||
class Mapfile;
|
||||
template<int size, bool big_endian>
|
||||
class Sized_relobj;
|
||||
class Dwarf_range_list;
|
||||
template <typename T>
|
||||
class Gdb_hashtab;
|
||||
|
||||
// This class manages the .gdb_index section, which is a fast
|
||||
// lookup table for DWARF information used by the gdb debugger.
|
||||
// The format of this section is described in gdb/doc/gdb.texinfo.
|
||||
|
||||
class Gdb_index : public Output_section_data
|
||||
{
|
||||
public:
|
||||
Gdb_index(Output_section* gdb_index_section);
|
||||
|
||||
~Gdb_index();
|
||||
|
||||
// Scan a .debug_info or .debug_types input section.
|
||||
void scan_debug_info(bool is_type_unit,
|
||||
Relobj* object,
|
||||
const unsigned char* symbols,
|
||||
off_t symbols_size,
|
||||
unsigned int shndx,
|
||||
unsigned int reloc_shndx,
|
||||
unsigned int reloc_type);
|
||||
|
||||
// Add a compilation unit.
|
||||
int
|
||||
add_comp_unit(off_t cu_offset, off_t cu_length)
|
||||
{
|
||||
this->comp_units_.push_back(Comp_unit(cu_offset, cu_length));
|
||||
return this->comp_units_.size() - 1;
|
||||
}
|
||||
|
||||
// Add a type unit.
|
||||
int
|
||||
add_type_unit(off_t tu_offset, off_t type_offset, uint64_t signature)
|
||||
{
|
||||
this->type_units_.push_back(Type_unit(tu_offset, type_offset, signature));
|
||||
return this->type_units_.size() - 1;
|
||||
}
|
||||
|
||||
// Add an address range.
|
||||
void
|
||||
add_address_range_list(Relobj* object, unsigned int cu_index,
|
||||
Dwarf_range_list* ranges)
|
||||
{
|
||||
this->ranges_.push_back(Per_cu_range_list(object, cu_index, ranges));
|
||||
}
|
||||
|
||||
// Add a symbol.
|
||||
void
|
||||
add_symbol(int cu_index, const char* sym_name);
|
||||
|
||||
// Return TRUE if we have already processed the pubnames set at
|
||||
// OFFSET in section SHNDX
|
||||
bool
|
||||
pubnames_read(unsigned int shndx, off_t offset);
|
||||
|
||||
// Return TRUE if we have already processed the pubtypes set at
|
||||
// OFFSET in section SHNDX
|
||||
bool
|
||||
pubtypes_read(unsigned int shndx, off_t offset);
|
||||
|
||||
// Print usage statistics.
|
||||
static void
|
||||
print_stats();
|
||||
|
||||
protected:
|
||||
// This is called to update the section size prior to assigning
|
||||
// the address and file offset.
|
||||
void
|
||||
update_data_size()
|
||||
{ this->set_final_data_size(); }
|
||||
|
||||
// Set the final data size.
|
||||
void
|
||||
set_final_data_size();
|
||||
|
||||
// Write the data to the file.
|
||||
void
|
||||
do_write(Output_file*);
|
||||
|
||||
// Write to a map file.
|
||||
void
|
||||
do_print_to_mapfile(Mapfile* mapfile) const
|
||||
{ mapfile->print_output_data(this, _("** gdb_index")); }
|
||||
|
||||
private:
|
||||
// An entry in the compilation unit list.
|
||||
struct Comp_unit
|
||||
{
|
||||
Comp_unit(off_t off, off_t len)
|
||||
: cu_offset(off), cu_length(len)
|
||||
{ }
|
||||
uint64_t cu_offset;
|
||||
uint64_t cu_length;
|
||||
};
|
||||
|
||||
// An entry in the type unit list.
|
||||
struct Type_unit
|
||||
{
|
||||
Type_unit(off_t off, off_t toff, uint64_t sig)
|
||||
: tu_offset(off), type_offset(toff), type_signature(sig)
|
||||
{ }
|
||||
uint64_t tu_offset;
|
||||
uint64_t type_offset;
|
||||
uint64_t type_signature;
|
||||
};
|
||||
|
||||
// An entry in the address range list.
|
||||
struct Per_cu_range_list
|
||||
{
|
||||
Per_cu_range_list(Relobj* obj, uint32_t index, Dwarf_range_list* r)
|
||||
: object(obj), cu_index(index), ranges(r)
|
||||
{ }
|
||||
Relobj* object;
|
||||
uint32_t cu_index;
|
||||
Dwarf_range_list* ranges;
|
||||
};
|
||||
|
||||
// A symbol table entry.
|
||||
struct Gdb_symbol
|
||||
{
|
||||
Stringpool::Key name_key;
|
||||
unsigned int hashval;
|
||||
unsigned int cu_vector_index;
|
||||
|
||||
// Return the hash value.
|
||||
unsigned int
|
||||
hash()
|
||||
{ return this->hashval; }
|
||||
|
||||
// Return true if this symbol is the same as SYMBOL.
|
||||
bool
|
||||
equal(Gdb_symbol* symbol)
|
||||
{ return this->name_key == symbol->name_key; }
|
||||
};
|
||||
|
||||
typedef std::vector<int> Cu_vector;
|
||||
|
||||
// The .gdb_index section.
|
||||
Output_section* gdb_index_section_;
|
||||
// The list of DWARF compilation units.
|
||||
std::vector<Comp_unit> comp_units_;
|
||||
// The list of DWARF type units.
|
||||
std::vector<Type_unit> type_units_;
|
||||
// The list of address ranges.
|
||||
std::vector<Per_cu_range_list> ranges_;
|
||||
// The symbol table.
|
||||
Gdb_hashtab<Gdb_symbol>* gdb_symtab_;
|
||||
// The CU vector portion of the constant pool.
|
||||
std::vector<Cu_vector*> cu_vector_list_;
|
||||
// An array to map from a CU vector index to an offset to the constant pool.
|
||||
off_t* cu_vector_offsets_;
|
||||
// The string portion of the constant pool.
|
||||
Stringpool stringpool_;
|
||||
// Offsets of the various pieces of the .gdb_index section.
|
||||
off_t tu_offset_;
|
||||
off_t addr_offset_;
|
||||
off_t symtab_offset_;
|
||||
off_t cu_pool_offset_;
|
||||
off_t stringpool_offset_;
|
||||
// Section index and offset of last read pubnames section.
|
||||
unsigned int pubnames_shndx_;
|
||||
off_t pubnames_offset_;
|
||||
// Section index and offset of last read pubtypes section.
|
||||
unsigned int pubtypes_shndx_;
|
||||
off_t pubtypes_offset_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_GDB_INDEX_H)
|
@ -2002,6 +2002,11 @@ Sized_relobj_incr<size, big_endian>::do_layout(
|
||||
Output_sections& out_sections(this->output_sections());
|
||||
out_sections.resize(shnum);
|
||||
this->section_offsets().resize(shnum);
|
||||
|
||||
// Keep track of .debug_info and .debug_types sections.
|
||||
std::vector<unsigned int> debug_info_sections;
|
||||
std::vector<unsigned int> debug_types_sections;
|
||||
|
||||
for (unsigned int i = 1; i < shnum; i++)
|
||||
{
|
||||
typename Input_entry_reader::Input_section_info sect =
|
||||
@ -2015,6 +2020,18 @@ Sized_relobj_incr<size, big_endian>::do_layout(
|
||||
gold_assert(os != NULL);
|
||||
out_sections[i] = os;
|
||||
this->section_offsets()[i] = static_cast<Address>(sect.sh_offset);
|
||||
|
||||
// When generating a .gdb_index section, we do additional
|
||||
// processing of .debug_info and .debug_types sections after all
|
||||
// the other sections.
|
||||
if (parameters->options().gdb_index())
|
||||
{
|
||||
const char* name = os->name();
|
||||
if (strcmp(name, ".debug_info") == 0)
|
||||
debug_info_sections.push_back(i);
|
||||
else if (strcmp(name, ".debug_types") == 0)
|
||||
debug_types_sections.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Process the COMDAT groups.
|
||||
@ -2032,6 +2049,25 @@ Sized_relobj_incr<size, big_endian>::do_layout(
|
||||
this->error(_("COMDAT group %s included twice in incremental link"),
|
||||
signature);
|
||||
}
|
||||
|
||||
// When building a .gdb_index section, scan the .debug_info and
|
||||
// .debug_types sections.
|
||||
for (std::vector<unsigned int>::const_iterator p
|
||||
= debug_info_sections.begin();
|
||||
p != debug_info_sections.end();
|
||||
++p)
|
||||
{
|
||||
unsigned int i = *p;
|
||||
layout->add_to_gdb_index(false, this, NULL, 0, i, 0, 0);
|
||||
}
|
||||
for (std::vector<unsigned int>::const_iterator p
|
||||
= debug_types_sections.begin();
|
||||
p != debug_types_sections.end();
|
||||
++p)
|
||||
{
|
||||
unsigned int i = *p;
|
||||
layout->add_to_gdb_index(true, this, 0, 0, i, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Layout sections whose layout was deferred while waiting for
|
||||
@ -2193,22 +2229,39 @@ Sized_relobj_incr<size, big_endian>::do_section_size(unsigned int)
|
||||
gold_unreachable();
|
||||
}
|
||||
|
||||
// Get the name of a section.
|
||||
// Get the name of a section. This returns the name of the output
|
||||
// section, because we don't usually track the names of the input
|
||||
// sections.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
std::string
|
||||
Sized_relobj_incr<size, big_endian>::do_section_name(unsigned int)
|
||||
Sized_relobj_incr<size, big_endian>::do_section_name(unsigned int shndx)
|
||||
{
|
||||
gold_unreachable();
|
||||
Output_sections& out_sections(this->output_sections());
|
||||
Output_section* os = out_sections[shndx];
|
||||
if (os == NULL)
|
||||
return NULL;
|
||||
return os->name();
|
||||
}
|
||||
|
||||
// Return a view of the contents of a section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Object::Location
|
||||
Sized_relobj_incr<size, big_endian>::do_section_contents(unsigned int)
|
||||
const unsigned char*
|
||||
Sized_relobj_incr<size, big_endian>::do_section_contents(
|
||||
unsigned int shndx,
|
||||
section_size_type* plen,
|
||||
bool)
|
||||
{
|
||||
gold_unreachable();
|
||||
Output_sections& out_sections(this->output_sections());
|
||||
Output_section* os = out_sections[shndx];
|
||||
gold_assert(os != NULL);
|
||||
off_t section_offset = os->offset();
|
||||
typename Input_entry_reader::Input_section_info sect =
|
||||
this->input_reader_.get_input_section(shndx - 1);
|
||||
section_offset += sect.sh_offset;
|
||||
*plen = sect.sh_size;
|
||||
return this->ibase_->view(section_offset, sect.sh_size).data();
|
||||
}
|
||||
|
||||
// Return section flags.
|
||||
@ -2780,8 +2833,11 @@ Sized_incr_dynobj<size, big_endian>::do_section_name(unsigned int)
|
||||
// Return a view of the contents of a section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Object::Location
|
||||
Sized_incr_dynobj<size, big_endian>::do_section_contents(unsigned int)
|
||||
const unsigned char*
|
||||
Sized_incr_dynobj<size, big_endian>::do_section_contents(
|
||||
unsigned int,
|
||||
section_size_type*,
|
||||
bool)
|
||||
{
|
||||
gold_unreachable();
|
||||
}
|
||||
|
@ -1880,8 +1880,9 @@ class Sized_relobj_incr : public Sized_relobj<size, big_endian>
|
||||
do_section_name(unsigned int shndx);
|
||||
|
||||
// Return a view of the contents of a section.
|
||||
Object::Location
|
||||
do_section_contents(unsigned int shndx);
|
||||
const unsigned char*
|
||||
do_section_contents(unsigned int shndx, section_size_type* plen,
|
||||
bool cache);
|
||||
|
||||
// Return section flags.
|
||||
uint64_t
|
||||
@ -2086,8 +2087,9 @@ class Sized_incr_dynobj : public Dynobj
|
||||
do_section_name(unsigned int shndx);
|
||||
|
||||
// Return a view of the contents of a section.
|
||||
Object::Location
|
||||
do_section_contents(unsigned int shndx);
|
||||
const unsigned char*
|
||||
do_section_contents(unsigned int shndx, section_size_type* plen,
|
||||
bool cache);
|
||||
|
||||
// Return section flags.
|
||||
uint64_t
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "symtab.h"
|
||||
#include "dynobj.h"
|
||||
#include "ehframe.h"
|
||||
#include "gdb-index.h"
|
||||
#include "compressed_output.h"
|
||||
#include "reduced_debug_output.h"
|
||||
#include "object.h"
|
||||
@ -390,6 +391,7 @@ Layout::Layout(int number_of_input_files, Script_options* script_options)
|
||||
eh_frame_data_(NULL),
|
||||
added_eh_frame_data_(false),
|
||||
eh_frame_hdr_section_(NULL),
|
||||
gdb_index_data_(NULL),
|
||||
build_id_note_(NULL),
|
||||
debug_abbrev_(NULL),
|
||||
debug_info_(NULL),
|
||||
@ -905,6 +907,13 @@ Layout::init_fixed_output_section(const char* name,
|
||||
if (!can_incremental_update(sh_type))
|
||||
return NULL;
|
||||
|
||||
// If we're generating a .gdb_index section, we need to regenerate
|
||||
// it from scratch.
|
||||
if (parameters->options().gdb_index()
|
||||
&& sh_type == elfcpp::SHT_PROGBITS
|
||||
&& strcmp(name, ".gdb_index") == 0)
|
||||
return NULL;
|
||||
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr sh_addr = shdr.get_sh_addr();
|
||||
typename elfcpp::Elf_types<size>::Elf_Off sh_offset = shdr.get_sh_offset();
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword sh_size = shdr.get_sh_size();
|
||||
@ -1292,6 +1301,38 @@ Layout::add_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
|
||||
}
|
||||
}
|
||||
|
||||
// Scan a .debug_info or .debug_types section, and add summary
|
||||
// information to the .gdb_index section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Layout::add_to_gdb_index(bool is_type_unit,
|
||||
Sized_relobj<size, big_endian>* object,
|
||||
const unsigned char* symbols,
|
||||
off_t symbols_size,
|
||||
unsigned int shndx,
|
||||
unsigned int reloc_shndx,
|
||||
unsigned int reloc_type)
|
||||
{
|
||||
if (this->gdb_index_data_ == NULL)
|
||||
{
|
||||
Output_section* os = this->choose_output_section(NULL, ".gdb_index",
|
||||
elfcpp::SHT_PROGBITS, 0,
|
||||
false, ORDER_INVALID,
|
||||
false);
|
||||
if (os == NULL)
|
||||
return;
|
||||
|
||||
this->gdb_index_data_ = new Gdb_index(os);
|
||||
os->add_output_section_data(this->gdb_index_data_);
|
||||
os->set_after_input_sections();
|
||||
}
|
||||
|
||||
this->gdb_index_data_->scan_debug_info(is_type_unit, object, symbols,
|
||||
symbols_size, shndx, reloc_shndx,
|
||||
reloc_type);
|
||||
}
|
||||
|
||||
// Add POSD to an output section using NAME, TYPE, and FLAGS. Return
|
||||
// the output section.
|
||||
|
||||
@ -5297,4 +5338,52 @@ Layout::layout_eh_frame<64, true>(Sized_relobj_file<64, true>* object,
|
||||
off_t* off);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
void
|
||||
Layout::add_to_gdb_index(bool is_type_unit,
|
||||
Sized_relobj<32, false>* object,
|
||||
const unsigned char* symbols,
|
||||
off_t symbols_size,
|
||||
unsigned int shndx,
|
||||
unsigned int reloc_shndx,
|
||||
unsigned int reloc_type);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
template
|
||||
void
|
||||
Layout::add_to_gdb_index(bool is_type_unit,
|
||||
Sized_relobj<32, true>* object,
|
||||
const unsigned char* symbols,
|
||||
off_t symbols_size,
|
||||
unsigned int shndx,
|
||||
unsigned int reloc_shndx,
|
||||
unsigned int reloc_type);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
template
|
||||
void
|
||||
Layout::add_to_gdb_index(bool is_type_unit,
|
||||
Sized_relobj<64, false>* object,
|
||||
const unsigned char* symbols,
|
||||
off_t symbols_size,
|
||||
unsigned int shndx,
|
||||
unsigned int reloc_shndx,
|
||||
unsigned int reloc_type);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
template
|
||||
void
|
||||
Layout::add_to_gdb_index(bool is_type_unit,
|
||||
Sized_relobj<64, true>* object,
|
||||
const unsigned char* symbols,
|
||||
off_t symbols_size,
|
||||
unsigned int shndx,
|
||||
unsigned int reloc_shndx,
|
||||
unsigned int reloc_type);
|
||||
#endif
|
||||
|
||||
} // End namespace gold.
|
||||
|
@ -58,6 +58,7 @@ class Output_symtab_xindex;
|
||||
class Output_reduced_debug_abbrev_section;
|
||||
class Output_reduced_debug_info_section;
|
||||
class Eh_frame;
|
||||
class Gdb_index;
|
||||
class Target;
|
||||
struct Timespec;
|
||||
|
||||
@ -601,6 +602,18 @@ class Layout
|
||||
size_t cie_length, const unsigned char* fde_data,
|
||||
size_t fde_length);
|
||||
|
||||
// Scan a .debug_info or .debug_types section, and add summary
|
||||
// information to the .gdb_index section.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
add_to_gdb_index(bool is_type_unit,
|
||||
Sized_relobj<size, big_endian>* object,
|
||||
const unsigned char* symbols,
|
||||
off_t symbols_size,
|
||||
unsigned int shndx,
|
||||
unsigned int reloc_shndx,
|
||||
unsigned int reloc_type);
|
||||
|
||||
// Handle a GNU stack note. This is called once per input object
|
||||
// file. SEEN_GNU_STACK is true if the object file has a
|
||||
// .note.GNU-stack section. GNU_STACK_FLAGS is the section flags
|
||||
@ -1281,6 +1294,8 @@ class Layout
|
||||
bool added_eh_frame_data_;
|
||||
// The exception frame header output section if there is one.
|
||||
Output_section* eh_frame_hdr_section_;
|
||||
// The data for the .gdb_index section.
|
||||
Gdb_index* gdb_index_data_;
|
||||
// The space for the build ID checksum if there is one.
|
||||
Output_section_data* build_id_note_;
|
||||
// The output section containing dwarf abbreviations
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "gc.h"
|
||||
#include "icf.h"
|
||||
#include "incremental.h"
|
||||
#include "gdb-index.h"
|
||||
#include "timer.h"
|
||||
|
||||
using namespace gold;
|
||||
@ -301,6 +302,7 @@ main(int argc, char** argv)
|
||||
program_name, static_cast<long long>(layout.output_file_size()));
|
||||
symtab.print_stats();
|
||||
layout.print_stats();
|
||||
Gdb_index::print_stats();
|
||||
Free_list::print_stats();
|
||||
}
|
||||
|
||||
|
158
gold/object.cc
158
gold/object.cc
@ -178,16 +178,7 @@ Object::error(const char* format, ...) const
|
||||
const unsigned char*
|
||||
Object::section_contents(unsigned int shndx, section_size_type* plen,
|
||||
bool cache)
|
||||
{
|
||||
Location loc(this->do_section_contents(shndx));
|
||||
*plen = convert_to_section_size_type(loc.data_size);
|
||||
if (*plen == 0)
|
||||
{
|
||||
static const unsigned char empty[1] = { '\0' };
|
||||
return empty;
|
||||
}
|
||||
return this->get_view(loc.file_offset, *plen, true, cache);
|
||||
}
|
||||
{ return this->do_section_contents(shndx, plen, cache); }
|
||||
|
||||
// Read the section data into SD. This is code common to Sized_relobj_file
|
||||
// and Sized_dynobj, so we put it into Object.
|
||||
@ -550,24 +541,55 @@ Sized_relobj_file<size, big_endian>::find_eh_frame(
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
|
||||
// Return TRUE if this is a section whose contents will be needed in the
|
||||
// Add_symbols task.
|
||||
// Add_symbols task. This function is only called for sections that have
|
||||
// already passed the test in is_compressed_debug_section(), so we know
|
||||
// that the section name begins with ".zdebug".
|
||||
|
||||
static bool
|
||||
need_decompressed_section(const char* name)
|
||||
{
|
||||
// We will need .zdebug_str if this is not an incremental link
|
||||
// (i.e., we are processing string merge sections).
|
||||
if (!parameters->incremental() && strcmp(name, ".zdebug_str") == 0)
|
||||
// Skip over the ".zdebug" and a quick check for the "_".
|
||||
name += 7;
|
||||
if (*name++ != '_')
|
||||
return false;
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
// Decompressing these sections now will help only if we're
|
||||
// multithreaded.
|
||||
if (parameters->options().threads())
|
||||
{
|
||||
// We will need .zdebug_str if this is not an incremental link
|
||||
// (i.e., we are processing string merge sections) or if we need
|
||||
// to build a gdb index.
|
||||
if ((!parameters->incremental() || parameters->options().gdb_index())
|
||||
&& strcmp(name, "str") == 0)
|
||||
return true;
|
||||
|
||||
// We will need these other sections when building a gdb index.
|
||||
if (parameters->options().gdb_index()
|
||||
&& (strcmp(name, "info") == 0
|
||||
|| strcmp(name, "types") == 0
|
||||
|| strcmp(name, "pubnames") == 0
|
||||
|| strcmp(name, "pubtypes") == 0
|
||||
|| strcmp(name, "ranges") == 0
|
||||
|| strcmp(name, "abbrev") == 0))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Even when single-threaded, we will need .zdebug_str if this is
|
||||
// not an incremental link and we are building a gdb index.
|
||||
// Otherwise, we would decompress the section twice: once for
|
||||
// string merge processing, and once for building the gdb index.
|
||||
if (!parameters->incremental()
|
||||
&& parameters->options().gdb_index()
|
||||
&& strcmp(name, "str") == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Build a table for any compressed debug sections, mapping each section index
|
||||
// to the uncompressed size and (if needed) the decompressed contents.
|
||||
|
||||
@ -604,33 +626,22 @@ build_compressed_section_map(
|
||||
const unsigned char* contents =
|
||||
obj->section_contents(i, &len, false);
|
||||
uint64_t uncompressed_size = get_uncompressed_size(contents, len);
|
||||
Compressed_section_info info;
|
||||
info.size = convert_to_section_size_type(uncompressed_size);
|
||||
info.contents = NULL;
|
||||
if (uncompressed_size != -1ULL)
|
||||
{
|
||||
Compressed_section_info info;
|
||||
info.size = convert_to_section_size_type(uncompressed_size);
|
||||
info.contents = NULL;
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
// If we're multi-threaded, it will help to decompress
|
||||
// any sections that will be needed during the Add_symbols
|
||||
// task, so that several decompressions can run in
|
||||
// parallel.
|
||||
if (parameters->options().threads())
|
||||
unsigned char* uncompressed_data = NULL;
|
||||
if (need_decompressed_section(name))
|
||||
{
|
||||
unsigned char* uncompressed_data = NULL;
|
||||
if (need_decompressed_section(name))
|
||||
{
|
||||
uncompressed_data = new unsigned char[uncompressed_size];
|
||||
if (decompress_input_section(contents, len,
|
||||
uncompressed_data,
|
||||
uncompressed_size))
|
||||
info.contents = uncompressed_data;
|
||||
else
|
||||
delete[] uncompressed_data;
|
||||
}
|
||||
uncompressed_data = new unsigned char[uncompressed_size];
|
||||
if (decompress_input_section(contents, len,
|
||||
uncompressed_data,
|
||||
uncompressed_size))
|
||||
info.contents = uncompressed_data;
|
||||
else
|
||||
delete[] uncompressed_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
(*uncompressed_map)[i] = info;
|
||||
}
|
||||
}
|
||||
@ -645,6 +656,8 @@ template<int size, bool big_endian>
|
||||
void
|
||||
Sized_relobj_file<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
|
||||
{
|
||||
bool need_local_symbols = false;
|
||||
|
||||
this->read_section_data(&this->elf_file_, sd);
|
||||
|
||||
const unsigned char* const pshdrs = sd->section_headers->data();
|
||||
@ -663,6 +676,14 @@ Sized_relobj_file<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
|
||||
build_compressed_section_map(pshdrs, this->shnum(), names,
|
||||
sd->section_names_size, this);
|
||||
|
||||
if (this->has_eh_frame_
|
||||
|| (!parameters->options().relocatable()
|
||||
&& parameters->options().gdb_index()
|
||||
&& (memmem(names, sd->section_names_size, "debug_info", 12) == 0
|
||||
|| memmem(names, sd->section_names_size, "debug_types",
|
||||
13) == 0)))
|
||||
need_local_symbols = true;
|
||||
|
||||
sd->symbols = NULL;
|
||||
sd->symbols_size = 0;
|
||||
sd->external_symbols_offset = 0;
|
||||
@ -680,7 +701,8 @@ Sized_relobj_file<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
|
||||
+ this->symtab_shndx_ * This::shdr_size);
|
||||
gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
|
||||
|
||||
// If this object has a .eh_frame section, we need all the symbols.
|
||||
// If this object has a .eh_frame section, or if building a .gdb_index
|
||||
// section and there is debug info, we need all the symbols.
|
||||
// Otherwise we only need the external symbols. While it would be
|
||||
// simpler to just always read all the symbols, I've seen object
|
||||
// files with well over 2000 local symbols, which for a 64-bit
|
||||
@ -698,8 +720,8 @@ Sized_relobj_file<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
|
||||
off_t extoff = dataoff + locsize;
|
||||
section_size_type extsize = datasize - locsize;
|
||||
|
||||
off_t readoff = this->has_eh_frame_ ? dataoff : extoff;
|
||||
section_size_type readsize = this->has_eh_frame_ ? datasize : extsize;
|
||||
off_t readoff = need_local_symbols ? dataoff : extoff;
|
||||
section_size_type readsize = need_local_symbols ? datasize : extsize;
|
||||
|
||||
if (readsize == 0)
|
||||
{
|
||||
@ -731,7 +753,7 @@ Sized_relobj_file<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
|
||||
|
||||
sd->symbols = fvsymtab;
|
||||
sd->symbols_size = readsize;
|
||||
sd->external_symbols_offset = this->has_eh_frame_ ? locsize : 0;
|
||||
sd->external_symbols_offset = need_local_symbols ? locsize : 0;
|
||||
sd->symbol_names = fvstrtab;
|
||||
sd->symbol_names_size =
|
||||
convert_to_section_size_type(strtabshdr.get_sh_size());
|
||||
@ -1318,6 +1340,10 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
|
||||
// Keep track of .eh_frame sections.
|
||||
std::vector<unsigned int> eh_frame_sections;
|
||||
|
||||
// Keep track of .debug_info and .debug_types sections.
|
||||
std::vector<unsigned int> debug_info_sections;
|
||||
std::vector<unsigned int> debug_types_sections;
|
||||
|
||||
// Skip the first, dummy, section.
|
||||
pshdrs = shdrs + This::shdr_size;
|
||||
for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
|
||||
@ -1558,6 +1584,21 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
|
||||
// only happens in the second call.
|
||||
this->layout_section(layout, i, name, shdr, reloc_shndx[i],
|
||||
reloc_type[i]);
|
||||
|
||||
// When generating a .gdb_index section, we do additional
|
||||
// processing of .debug_info and .debug_types sections after all
|
||||
// the other sections for the same reason as above.
|
||||
if (!relocatable
|
||||
&& parameters->options().gdb_index()
|
||||
&& !(shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
|
||||
{
|
||||
if (strcmp(name, ".debug_info") == 0
|
||||
|| strcmp(name, ".zdebug_info") == 0)
|
||||
debug_info_sections.push_back(i);
|
||||
else if (strcmp(name, ".debug_types") == 0
|
||||
|| strcmp(name, ".zdebug_types") == 0)
|
||||
debug_types_sections.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1638,6 +1679,29 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
|
||||
reloc_type[i]);
|
||||
}
|
||||
|
||||
// When building a .gdb_index section, scan the .debug_info and
|
||||
// .debug_types sections.
|
||||
gold_assert(!is_gc_pass_one
|
||||
|| (debug_info_sections.empty() && debug_types_sections.empty()));
|
||||
for (std::vector<unsigned int>::const_iterator p
|
||||
= debug_info_sections.begin();
|
||||
p != debug_info_sections.end();
|
||||
++p)
|
||||
{
|
||||
unsigned int i = *p;
|
||||
layout->add_to_gdb_index(false, this, symbols_data, symbols_size,
|
||||
i, reloc_shndx[i], reloc_type[i]);
|
||||
}
|
||||
for (std::vector<unsigned int>::const_iterator p
|
||||
= debug_types_sections.begin();
|
||||
p != debug_types_sections.end();
|
||||
++p)
|
||||
{
|
||||
unsigned int i = *p;
|
||||
layout->add_to_gdb_index(true, this, symbols_data, symbols_size,
|
||||
i, reloc_shndx[i], reloc_type[i]);
|
||||
}
|
||||
|
||||
if (is_gc_pass_two)
|
||||
{
|
||||
delete[] gc_sd->section_headers_data;
|
||||
@ -2614,8 +2678,8 @@ Sized_relobj_file<size, big_endian>::do_decompressed_section_contents(
|
||||
bool* is_new)
|
||||
{
|
||||
section_size_type buffer_size;
|
||||
const unsigned char* buffer = this->section_contents(shndx, &buffer_size,
|
||||
false);
|
||||
const unsigned char* buffer = this->do_section_contents(shndx, &buffer_size,
|
||||
false);
|
||||
|
||||
if (this->compressed_sections_ == NULL)
|
||||
{
|
||||
|
@ -725,7 +725,7 @@ class Object
|
||||
section_size_type* uncompressed_size) const
|
||||
{ return this->do_section_is_compressed(shndx, uncompressed_size); }
|
||||
|
||||
// Return a view of the uncompressed contents of a section. Set *PLEN
|
||||
// Return a view of the decompressed contents of a section. Set *PLEN
|
||||
// to the size. Set *IS_NEW to true if the contents need to be freed
|
||||
// by the caller.
|
||||
const unsigned char*
|
||||
@ -805,8 +805,9 @@ class Object
|
||||
|
||||
// Return the location of the contents of a section. Implemented by
|
||||
// child class.
|
||||
virtual Location
|
||||
do_section_contents(unsigned int shndx) = 0;
|
||||
virtual const unsigned char*
|
||||
do_section_contents(unsigned int shndx, section_size_type* plen,
|
||||
bool cache) = 0;
|
||||
|
||||
// Get the size of a section--implemented by child class.
|
||||
virtual uint64_t
|
||||
@ -918,7 +919,7 @@ class Object
|
||||
bool* is_new)
|
||||
{
|
||||
*is_new = false;
|
||||
return this->section_contents(shndx, plen, false);
|
||||
return this->do_section_contents(shndx, plen, false);
|
||||
}
|
||||
|
||||
// Discard any buffers of decompressed sections. This is done
|
||||
@ -2237,9 +2238,19 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
|
||||
{ return this->elf_file_.section_name(shndx); }
|
||||
|
||||
// Return the location of the contents of a section.
|
||||
Object::Location
|
||||
do_section_contents(unsigned int shndx)
|
||||
{ return this->elf_file_.section_contents(shndx); }
|
||||
const unsigned char*
|
||||
do_section_contents(unsigned int shndx, section_size_type* plen,
|
||||
bool cache)
|
||||
{
|
||||
Object::Location loc(this->elf_file_.section_contents(shndx));
|
||||
*plen = convert_to_section_size_type(loc.data_size);
|
||||
if (*plen == 0)
|
||||
{
|
||||
static const unsigned char empty[1] = { '\0' };
|
||||
return empty;
|
||||
}
|
||||
return this->get_view(loc.file_offset, *plen, true, cache);
|
||||
}
|
||||
|
||||
// Return section flags.
|
||||
uint64_t
|
||||
@ -2373,7 +2384,7 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
|
||||
section_size_type* plen,
|
||||
bool* is_new);
|
||||
|
||||
// Discard any buffers of uncompressed sections. This is done
|
||||
// Discard any buffers of decompressed sections. This is done
|
||||
// at the end of the Add_symbols task.
|
||||
void
|
||||
do_discard_decompressed_sections();
|
||||
|
@ -791,6 +791,10 @@ class General_options
|
||||
DEFINE_bool(g, options::EXACTLY_ONE_DASH, '\0', false,
|
||||
N_("Ignored"), NULL);
|
||||
|
||||
DEFINE_bool(gdb_index, options::TWO_DASHES, '\0', false,
|
||||
N_("Generate .gdb_index section"),
|
||||
N_("Do not generate .gdb_index section"));
|
||||
|
||||
DEFINE_bool(gnu_unique, options::TWO_DASHES, '\0', true,
|
||||
N_("Enable STB_GNU_UNIQUE symbol binding (default)"),
|
||||
N_("Disable STB_GNU_UNIQUE symbol binding"));
|
||||
|
@ -1159,13 +1159,14 @@ Sized_pluginobj<size, big_endian>::do_section_name(unsigned int)
|
||||
// Return a view of the contents of a section. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Object::Location
|
||||
Sized_pluginobj<size, big_endian>::do_section_contents(unsigned int)
|
||||
const unsigned char*
|
||||
Sized_pluginobj<size, big_endian>::do_section_contents(
|
||||
unsigned int,
|
||||
section_size_type*,
|
||||
bool)
|
||||
{
|
||||
Location loc(0, 0);
|
||||
|
||||
gold_unreachable();
|
||||
return loc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return section flags. Not used for plugin objects.
|
||||
|
@ -493,8 +493,9 @@ class Sized_pluginobj : public Pluginobj
|
||||
do_section_name(unsigned int shndx);
|
||||
|
||||
// Return a view of the contents of a section.
|
||||
Object::Location
|
||||
do_section_contents(unsigned int shndx);
|
||||
const unsigned char*
|
||||
do_section_contents(unsigned int shndx, section_size_type* plen,
|
||||
bool cache);
|
||||
|
||||
// Return section flags.
|
||||
uint64_t
|
||||
|
10
gold/reloc.h
10
gold/reloc.h
@ -873,6 +873,16 @@ class Track_relocs
|
||||
int
|
||||
advance(off_t offset);
|
||||
|
||||
// Checkpoint the current position in the reloc section.
|
||||
section_size_type
|
||||
checkpoint() const
|
||||
{ return this->pos_; }
|
||||
|
||||
// Reset the position to CHECKPOINT.
|
||||
void
|
||||
reset(section_size_type checkpoint)
|
||||
{ this->pos_ = checkpoint; }
|
||||
|
||||
private:
|
||||
// The contents of the input object's reloc section.
|
||||
const unsigned char* prelocs_;
|
||||
|
@ -1967,6 +1967,31 @@ memory_test: memory_test.o gcctestdir/ld $(srcdir)/memory_test.t
|
||||
memory_test.stdout: memory_test
|
||||
$(TEST_READELF) -lWS $< > $@
|
||||
|
||||
# Test that --gdb-index functions correctly.
|
||||
check_SCRIPTS += gdb_index_test_1.sh
|
||||
check_DATA += gdb_index_test_1.stdout
|
||||
MOSTLYCLEANFILES += gdb_index_test_1.stdout gdb_index_test_1
|
||||
gdb_index_test.o: gdb_index_test.cc
|
||||
$(CXXCOMPILE) -O0 -g -c -o $@ $<
|
||||
gdb_index_test_1: gdb_index_test.o gcctestdir/ld
|
||||
$(CXXLINK) -Bgcctestdir/ -Wl,--gdb-index $<
|
||||
gdb_index_test_1.stdout: gdb_index_test_1
|
||||
$(TEST_READELF) --debug-dump=gdb_index $< > $@
|
||||
|
||||
if HAVE_ZLIB
|
||||
|
||||
check_SCRIPTS += gdb_index_test_2.sh
|
||||
check_DATA += gdb_index_test_2.stdout
|
||||
MOSTLYCLEANFILES += gdb_index_test_2.stdout gdb_index_test_2
|
||||
gdb_index_test_cdebug.o: gdb_index_test.cc
|
||||
$(CXXCOMPILE) -Bgcctestdir/ -O0 -g -Wa,--compress-debug-sections -c -o $@ $<
|
||||
gdb_index_test_2: gdb_index_test_cdebug.o gcctestdir/ld
|
||||
$(CXXLINK) -Bgcctestdir/ -Wl,--gdb-index $<
|
||||
gdb_index_test_2.stdout: gdb_index_test_2
|
||||
$(TEST_READELF) --debug-dump=gdb_index $< > $@
|
||||
|
||||
endif HAVE_ZLIB
|
||||
|
||||
# End-to-end incremental linking tests.
|
||||
# Incremental linking is currently supported only on the x86_64 target.
|
||||
|
||||
|
@ -360,13 +360,16 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||
# weak reference in a DSO.
|
||||
|
||||
# Test that MEMORY region support works.
|
||||
|
||||
# Test that --gdb-index functions correctly.
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_38 = exclude_libs_test.sh \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.sh \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.sh \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.sh \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ no_version_test.sh \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def.sh \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.sh memory_test.sh
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.sh memory_test.sh \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gdb_index_test_1.sh
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_39 = exclude_libs_test.syms \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.syms \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_relocatable_test1.syms \
|
||||
@ -376,7 +379,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ no_version_test.stdout \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ strong_ref_weak_def.stdout \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.stdout \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.stdout
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.stdout \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gdb_index_test_1.stdout
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_40 = exclude_libs_test.syms \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_1.a \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_2.a \
|
||||
@ -402,7 +406,9 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref_2.so \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ dyn_weak_ref.stdout \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.stdout memory_test \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.o
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ memory_test.o \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gdb_index_test_1.stdout \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gdb_index_test_1
|
||||
@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__append_41 = large
|
||||
@GCC_FALSE@large_DEPENDENCIES =
|
||||
@MCMODEL_MEDIUM_FALSE@large_DEPENDENCIES =
|
||||
@ -477,10 +483,13 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||
|
||||
# Test that --start-lib and --end-lib function correctly.
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_53 = start_lib_test
|
||||
@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_54 = gdb_index_test_2.sh
|
||||
@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_55 = gdb_index_test_2.stdout
|
||||
@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_56 = gdb_index_test_2.stdout gdb_index_test_2
|
||||
|
||||
# Test the --incremental-unchanged flag with an archive library.
|
||||
# The second link should not update the library.
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_54 = incremental_test_2 \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_57 = incremental_test_2 \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_3 \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_4 \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_5 \
|
||||
@ -488,7 +497,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_copy_test \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_common_test_1 \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_comdat_test_1
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_55 = two_file_test_tmp_2.o \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_58 = two_file_test_tmp_2.o \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_tmp_3.o \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_4.base \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_tmp_4.o \
|
||||
@ -498,22 +507,22 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||
# These tests work with native and cross linkers.
|
||||
|
||||
# Test script section order.
|
||||
@NATIVE_OR_CROSS_LINKER_TRUE@am__append_56 = script_test_10.sh
|
||||
@NATIVE_OR_CROSS_LINKER_TRUE@am__append_57 = script_test_10.stdout
|
||||
@NATIVE_OR_CROSS_LINKER_TRUE@am__append_59 = script_test_10.sh
|
||||
@NATIVE_OR_CROSS_LINKER_TRUE@am__append_60 = script_test_10.stdout
|
||||
|
||||
# These tests work with cross linkers only.
|
||||
@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_58 = split_i386.sh
|
||||
@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_59 = split_i386_1.stdout split_i386_2.stdout \
|
||||
@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_61 = split_i386.sh
|
||||
@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_62 = split_i386_1.stdout split_i386_2.stdout \
|
||||
@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_i386_3.stdout split_i386_4.stdout split_i386_r.stdout
|
||||
|
||||
@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_60 = split_i386_1 split_i386_2 split_i386_3 \
|
||||
@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_63 = split_i386_1 split_i386_2 split_i386_3 \
|
||||
@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_i386_4 split_i386_r
|
||||
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_61 = split_x86_64.sh
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_62 = split_x86_64_1.stdout split_x86_64_2.stdout \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_64 = split_x86_64.sh
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_65 = split_x86_64_1.stdout split_x86_64_2.stdout \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_x86_64_3.stdout split_x86_64_4.stdout split_x86_64_r.stdout
|
||||
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_63 = split_x86_64_1 split_x86_64_2 split_x86_64_3 \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_66 = split_x86_64_1 split_x86_64_2 split_x86_64_3 \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_x86_64_4 split_x86_64_r
|
||||
|
||||
|
||||
@ -528,7 +537,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||
# Check Thumb to Thumb farcall veneers
|
||||
|
||||
# Check Thumb to ARM farcall veneers
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_64 = arm_abs_global.sh \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_67 = arm_abs_global.sh \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_branch_in_range.sh \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_branch_out_of_range.sh \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_v4bx.sh \
|
||||
@ -542,7 +551,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_arm_thumb.sh \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb.sh \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm.sh
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_65 = arm_abs_global.stdout \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_68 = arm_abs_global.stdout \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_in_range.stdout \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_out_of_range.stdout \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_bl_in_range.stdout \
|
||||
@ -587,7 +596,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb_6m.stdout \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm.stdout \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm_5t.stdout
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_66 = arm_abs_global \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_69 = arm_abs_global \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_in_range \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_out_of_range \
|
||||
@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_bl_in_range \
|
||||
@ -1997,18 +2006,19 @@ TEST_AS = $(top_builddir)/../gas/as-new
|
||||
MOSTLYCLEANFILES = *.so *.syms *.stdout $(am__append_4) \
|
||||
$(am__append_17) $(am__append_26) $(am__append_28) \
|
||||
$(am__append_30) $(am__append_36) $(am__append_40) \
|
||||
$(am__append_55) $(am__append_60) $(am__append_63) \
|
||||
$(am__append_66)
|
||||
$(am__append_56) $(am__append_58) $(am__append_63) \
|
||||
$(am__append_66) $(am__append_69)
|
||||
|
||||
# We will add to these later, for each individual test. Note
|
||||
# that we add each test under check_SCRIPTS or check_PROGRAMS;
|
||||
# the TESTS variable is automatically populated from these.
|
||||
check_SCRIPTS = $(am__append_2) $(am__append_34) $(am__append_38) \
|
||||
$(am__append_56) $(am__append_58) $(am__append_61) \
|
||||
$(am__append_64)
|
||||
$(am__append_54) $(am__append_59) $(am__append_61) \
|
||||
$(am__append_64) $(am__append_67)
|
||||
check_DATA = $(am__append_3) $(am__append_27) $(am__append_29) \
|
||||
$(am__append_35) $(am__append_39) $(am__append_57) \
|
||||
$(am__append_59) $(am__append_62) $(am__append_65)
|
||||
$(am__append_35) $(am__append_39) $(am__append_55) \
|
||||
$(am__append_60) $(am__append_62) $(am__append_65) \
|
||||
$(am__append_68)
|
||||
BUILT_SOURCES = $(am__append_25)
|
||||
TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
|
||||
|
||||
@ -3721,6 +3731,10 @@ dyn_weak_ref.sh.log: dyn_weak_ref.sh
|
||||
@p='dyn_weak_ref.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
memory_test.sh.log: memory_test.sh
|
||||
@p='memory_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
gdb_index_test_1.sh.log: gdb_index_test_1.sh
|
||||
@p='gdb_index_test_1.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
gdb_index_test_2.sh.log: gdb_index_test_2.sh
|
||||
@p='gdb_index_test_2.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
script_test_10.sh.log: script_test_10.sh
|
||||
@p='script_test_10.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
split_i386.sh.log: split_i386.sh
|
||||
@ -5042,6 +5056,18 @@ uninstall-am:
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -nostartfiles -nostdlib -T $(srcdir)/memory_test.t -o $@ memory_test.o
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@memory_test.stdout: memory_test
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -lWS $< > $@
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test.o: gdb_index_test.cc
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -o $@ $<
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_1: gdb_index_test.o gcctestdir/ld
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--gdb-index $<
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_1.stdout: gdb_index_test_1
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) --debug-dump=gdb_index $< > $@
|
||||
@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_cdebug.o: gdb_index_test.cc
|
||||
@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -Bgcctestdir/ -O0 -g -Wa,--compress-debug-sections -c -o $@ $<
|
||||
@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_2: gdb_index_test_cdebug.o gcctestdir/ld
|
||||
@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--gdb-index $<
|
||||
@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@gdb_index_test_2.stdout: gdb_index_test_2
|
||||
@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) --debug-dump=gdb_index $< > $@
|
||||
|
||||
# End-to-end incremental linking tests.
|
||||
# Incremental linking is currently supported only on the x86_64 target.
|
||||
|
138
gold/testsuite/gdb_index_test.cc
Normal file
138
gold/testsuite/gdb_index_test.cc
Normal file
@ -0,0 +1,138 @@
|
||||
// gdb_index_test.cc -- a test case for the --gdb-index option.
|
||||
|
||||
// Copyright 2012 Free Software Foundation, Inc.
|
||||
// Written by Cary Coutant <ccoutant@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
|
||||
// This source file defines a number of symbols of different forms
|
||||
// to exercise the DWARF scanner in gold.
|
||||
|
||||
namespace
|
||||
{
|
||||
int c1_count;
|
||||
int c2_count;
|
||||
};
|
||||
|
||||
namespace one
|
||||
{
|
||||
|
||||
enum G
|
||||
{
|
||||
G_A,
|
||||
G_B,
|
||||
G_C
|
||||
};
|
||||
|
||||
class c1
|
||||
{
|
||||
public:
|
||||
static int count;
|
||||
|
||||
c1()
|
||||
{ ++c1_count; }
|
||||
|
||||
~c1()
|
||||
{
|
||||
--c1_count;
|
||||
}
|
||||
|
||||
enum E
|
||||
{
|
||||
E_A,
|
||||
E_B,
|
||||
E_C,
|
||||
};
|
||||
|
||||
int
|
||||
val()
|
||||
{ return E_A; }
|
||||
};
|
||||
|
||||
c1 c1v;
|
||||
};
|
||||
|
||||
namespace two
|
||||
{
|
||||
const int ci = 3;
|
||||
|
||||
template <typename T>
|
||||
class c2
|
||||
{
|
||||
public:
|
||||
c2(T t)
|
||||
: t_(t)
|
||||
{
|
||||
++c2_count;
|
||||
}
|
||||
|
||||
~c2()
|
||||
{ --c2_count; }
|
||||
|
||||
T
|
||||
val()
|
||||
{ return this->t_; }
|
||||
|
||||
T t_;
|
||||
};
|
||||
|
||||
c2<int> c2v1(1);
|
||||
c2<double> c2v2(2.0);
|
||||
c2<int const*> c2v3(&ci);
|
||||
};
|
||||
|
||||
enum F
|
||||
{
|
||||
F_A,
|
||||
F_B,
|
||||
F_C
|
||||
};
|
||||
|
||||
template <class C>
|
||||
bool
|
||||
check(C* c)
|
||||
{ return c->val() == 0; }
|
||||
|
||||
bool
|
||||
check_enum(int i)
|
||||
{ return i > 0; }
|
||||
|
||||
struct anonymous_union_container {
|
||||
union {
|
||||
struct astruct {
|
||||
int a;
|
||||
};
|
||||
int b;
|
||||
} u;
|
||||
};
|
||||
|
||||
anonymous_union_container anonymous_union_var;
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
F f = F_A;
|
||||
one::G g = one::G_A;
|
||||
check_enum(f);
|
||||
check_enum(g);
|
||||
check(&one::c1v);
|
||||
check(&two::c2v1);
|
||||
check(&two::c2v2);
|
||||
check(&two::c2v3);
|
||||
return anonymous_union_var.u.b;
|
||||
}
|
84
gold/testsuite/gdb_index_test_1.sh
Executable file
84
gold/testsuite/gdb_index_test_1.sh
Executable file
@ -0,0 +1,84 @@
|
||||
#!/bin/sh
|
||||
|
||||
# gdb_index_test_1.sh -- a test case for the --gdb-index option.
|
||||
|
||||
# Copyright 2012 Free Software Foundation, Inc.
|
||||
# Written by Cary Coutant <ccoutant@google.com>.
|
||||
|
||||
# This file is part of gold.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
check()
|
||||
{
|
||||
if ! grep -q "$2" "$1"
|
||||
then
|
||||
echo "Did not find expected output:"
|
||||
echo " $2"
|
||||
echo ""
|
||||
echo "Actual error output below:"
|
||||
cat "$1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
STDOUT=gdb_index_test_1.stdout
|
||||
|
||||
check $STDOUT "^Version [45]"
|
||||
|
||||
# Look for the symbols we know should be in the symbol table.
|
||||
|
||||
check $STDOUT "^\[ *[0-9]*\] (anonymous namespace): "
|
||||
check $STDOUT "^\[ *[0-9]*\] (anonymous namespace)::c1_count: "
|
||||
check $STDOUT "^\[ *[0-9]*\] (anonymous namespace)::c2_count: "
|
||||
check $STDOUT "^\[ *[0-9]*\] bool: "
|
||||
check $STDOUT "^\[ *[0-9]*\] check<one::c1>: "
|
||||
check $STDOUT "^\[ *[0-9]*\] check<two::c2<double> >: "
|
||||
check $STDOUT "^\[ *[0-9]*\] check<two::c2<int> >: "
|
||||
# check $STDOUT "^\[ *[0-9]*\] check<two::c2<int const\*> >: "
|
||||
check $STDOUT "^\[ *[0-9]*\] double: "
|
||||
check $STDOUT "^\[ *[0-9]*\] F_A: "
|
||||
check $STDOUT "^\[ *[0-9]*\] F_B: "
|
||||
check $STDOUT "^\[ *[0-9]*\] F_C: "
|
||||
check $STDOUT "^\[ *[0-9]*\] int: "
|
||||
check $STDOUT "^\[ *[0-9]*\] main: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::c1: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::c1::~c1: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::c1::c1: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::c1::val: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::c1v: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::G_A: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::G_B: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::G_B: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<double>::~c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<double>::c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<double>::val: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<double>: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>::~c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>::c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>::val: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int>::~c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int>::c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int>::val: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int>: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2v1: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2v2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] anonymous_union_var: "
|
||||
|
||||
exit 0
|
84
gold/testsuite/gdb_index_test_2.sh
Executable file
84
gold/testsuite/gdb_index_test_2.sh
Executable file
@ -0,0 +1,84 @@
|
||||
#!/bin/sh
|
||||
|
||||
# gdb_index_test_2.sh -- a test case for the --gdb-index option.
|
||||
|
||||
# Copyright 2012 Free Software Foundation, Inc.
|
||||
# Written by Cary Coutant <ccoutant@google.com>.
|
||||
|
||||
# This file is part of gold.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
check()
|
||||
{
|
||||
if ! grep -q "$2" "$1"
|
||||
then
|
||||
echo "Did not find expected output:"
|
||||
echo " $2"
|
||||
echo ""
|
||||
echo "Actual error output below:"
|
||||
cat "$1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
STDOUT=gdb_index_test_2.stdout
|
||||
|
||||
check $STDOUT "^Version [45]"
|
||||
|
||||
# Look for the symbols we know should be in the symbol table.
|
||||
|
||||
check $STDOUT "^\[ *[0-9]*\] (anonymous namespace): "
|
||||
check $STDOUT "^\[ *[0-9]*\] (anonymous namespace)::c1_count: "
|
||||
check $STDOUT "^\[ *[0-9]*\] (anonymous namespace)::c2_count: "
|
||||
check $STDOUT "^\[ *[0-9]*\] bool: "
|
||||
check $STDOUT "^\[ *[0-9]*\] check<one::c1>: "
|
||||
check $STDOUT "^\[ *[0-9]*\] check<two::c2<double> >: "
|
||||
check $STDOUT "^\[ *[0-9]*\] check<two::c2<int> >: "
|
||||
# check $STDOUT "^\[ *[0-9]*\] check<two::c2<int const\*> >: "
|
||||
check $STDOUT "^\[ *[0-9]*\] double: "
|
||||
check $STDOUT "^\[ *[0-9]*\] F_A: "
|
||||
check $STDOUT "^\[ *[0-9]*\] F_B: "
|
||||
check $STDOUT "^\[ *[0-9]*\] F_C: "
|
||||
check $STDOUT "^\[ *[0-9]*\] int: "
|
||||
check $STDOUT "^\[ *[0-9]*\] main: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::c1: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::c1::~c1: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::c1::c1: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::c1::val: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::c1v: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::G_A: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::G_B: "
|
||||
check $STDOUT "^\[ *[0-9]*\] one::G_B: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<double>::~c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<double>::c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<double>::val: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<double>: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>::~c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>::c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int const\*>::val: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int>::~c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int>::c2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int>::val: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2<int>: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2v1: "
|
||||
check $STDOUT "^\[ *[0-9]*\] two::c2v2: "
|
||||
check $STDOUT "^\[ *[0-9]*\] anonymous_union_var: "
|
||||
|
||||
exit 0
|
Loading…
Reference in New Issue
Block a user