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:
Cary Coutant 2012-03-21 19:02:22 +00:00
parent bd0b9f9e12
commit c1027032c2
24 changed files with 4486 additions and 168 deletions

View File

@ -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.

View File

@ -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 \

View File

@ -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@

File diff suppressed because it is too large Load Diff

View File

@ -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_;

View File

@ -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

File diff suppressed because it is too large Load Diff

213
gold/gdb-index.h Normal file
View 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)

View File

@ -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();
}

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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();
}

View File

@ -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)
{

View File

@ -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();

View File

@ -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"));

View File

@ -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.

View File

@ -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

View File

@ -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_;

View File

@ -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.

View File

@ -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.

View 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;
}

View 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

View 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