diff options
-rw-r--r-- | gold/ChangeLog | 19 | ||||
-rw-r--r-- | gold/Makefile.am | 4 | ||||
-rw-r--r-- | gold/Makefile.in | 27 | ||||
-rw-r--r-- | gold/attributes.cc | 458 | ||||
-rw-r--r-- | gold/attributes.h | 406 | ||||
-rw-r--r-- | gold/dwarf_reader.cc | 69 | ||||
-rw-r--r-- | gold/dwarf_reader.h | 6 | ||||
-rw-r--r-- | gold/int_encoding.cc | 131 | ||||
-rw-r--r-- | gold/int_encoding.h | 112 | ||||
-rw-r--r-- | gold/reduced_debug_output.cc | 60 |
10 files changed, 1149 insertions, 143 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 41153bed9eb..63336d8c063 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,22 @@ +2009-12-08 Doug Kwan <dougkwan@google.com> + + * Makefile.am (CCFILES): Add attributes.cc and int_encoding.cc. + (HFILES): Add attributes.h and int_encoding.h. + * Makefile.in: Regenerate. + * dwarf_reader.cc (read_unsigned_LEB_128, read_signed_LEB_128): Move + function definitions to int_encoding.cc + * dwarf_reader.h (read_unsigned_LEB_128, read_signed_LEB_128): Move + prototypes to int_encoding.h + * reduced_debug_output.cc (int_encoding.h): New include. + (write_unsigned_LEB_128, get_length_as_unsigned_LEB_128): Move + function definitions to int_encoding.cc + (insert_into_vector, read_from_pointer): Move template definitions to + int_encoding.h + * attributes.cc: New file. + * attributes.h: New file. + * int_encoding.cc: New file. + * int_encoding.h: New file. + 2009-12-07 Rafael Avila de Espindola <espindola@google.com> PR gold/11055 diff --git a/gold/Makefile.am b/gold/Makefile.am index 8f47d639d4e..6afca178b44 100644 --- a/gold/Makefile.am +++ b/gold/Makefile.am @@ -39,6 +39,7 @@ noinst_LIBRARIES = libgold.a CCFILES = \ archive.cc \ + attributes.cc \ binary.cc \ common.cc \ compressed_output.cc \ @@ -58,6 +59,7 @@ CCFILES = \ gold-threads.cc \ icf.cc \ incremental.cc \ + int_encoding.cc \ layout.cc \ mapfile.cc \ merge.cc \ @@ -82,6 +84,7 @@ CCFILES = \ HFILES = \ archive.h \ + attributes.h \ binary.h \ common.h \ compressed_output.h \ @@ -100,6 +103,7 @@ HFILES = \ gold.h \ gold-threads.h \ icf.h \ + int_encoding.h \ layout.h \ mapfile.h \ merge.h \ diff --git a/gold/Makefile.in b/gold/Makefile.in index cd10edd57b6..38bd887fbe3 100644 --- a/gold/Makefile.in +++ b/gold/Makefile.in @@ -73,16 +73,17 @@ AR = ar ARFLAGS = cru libgold_a_AR = $(AR) $(ARFLAGS) libgold_a_DEPENDENCIES = $(LIBOBJS) -am__objects_1 = archive.$(OBJEXT) binary.$(OBJEXT) common.$(OBJEXT) \ - compressed_output.$(OBJEXT) copy-relocs.$(OBJEXT) \ - cref.$(OBJEXT) defstd.$(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) \ - layout.$(OBJEXT) mapfile.$(OBJEXT) merge.$(OBJEXT) \ - object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \ - parameters.$(OBJEXT) plugin.$(OBJEXT) readsyms.$(OBJEXT) \ +am__objects_1 = archive.$(OBJEXT) attributes.$(OBJEXT) \ + binary.$(OBJEXT) common.$(OBJEXT) compressed_output.$(OBJEXT) \ + copy-relocs.$(OBJEXT) cref.$(OBJEXT) defstd.$(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) \ reduced_debug_output.$(OBJEXT) reloc.$(OBJEXT) \ resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \ stringpool.$(OBJEXT) symtab.$(OBJEXT) target.$(OBJEXT) \ @@ -352,6 +353,7 @@ am__skipyacc = noinst_LIBRARIES = libgold.a CCFILES = \ archive.cc \ + attributes.cc \ binary.cc \ common.cc \ compressed_output.cc \ @@ -371,6 +373,7 @@ CCFILES = \ gold-threads.cc \ icf.cc \ incremental.cc \ + int_encoding.cc \ layout.cc \ mapfile.cc \ merge.cc \ @@ -395,6 +398,7 @@ CCFILES = \ HFILES = \ archive.h \ + attributes.h \ binary.h \ common.h \ compressed_output.h \ @@ -413,6 +417,7 @@ HFILES = \ gold.h \ gold-threads.h \ icf.h \ + int_encoding.h \ layout.h \ mapfile.h \ merge.h \ @@ -592,6 +597,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attributes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compressed_output.Po@am__quote@ @@ -613,6 +619,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental-dump.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/int_encoding.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mapfile.Po@am__quote@ diff --git a/gold/attributes.cc b/gold/attributes.cc new file mode 100644 index 00000000000..6b2260d7b94 --- /dev/null +++ b/gold/attributes.cc @@ -0,0 +1,458 @@ +// attributes.cc -- object attributes for gold + +// Copyright 2009 Free Software Foundation, Inc. +// Written by Doug Kwan <dougkwan@google.com>. +// This file contains code adapted from BFD. + +// 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 "gold.h" + +#include <limits> + +#include "attributes.h" +#include "elfcpp.h" +#include "target.h" +#include "parameters.h" +#include "int_encoding.h" + +namespace gold +{ + +// Object_attribute methods. + +// Return size of attribute encode in ULEB128. + +size_t +Object_attribute::size(int tag) const +{ + // Attributes with default values are not written out. + if (this->is_default_attribute()) + return 0; + + size_t size = get_length_as_unsigned_LEB_128(tag); + if (Object_attribute::attribute_type_has_int_value(this->type_)) + size += get_length_as_unsigned_LEB_128(this->int_value_); + if (Object_attribute::attribute_type_has_string_value(this->type_)) + size += this->string_value_.size() + 1; + return size; +} + +// Whether this has the default value (0/""). + +bool +Object_attribute::is_default_attribute() const +{ + if (Object_attribute::attribute_type_has_int_value(this->type_) + && this->int_value_ != 0) + return false; + if (Object_attribute::attribute_type_has_string_value(this->type_) + && !this->string_value_.empty()) + return false; + if (Object_attribute::attribute_type_has_no_default(this->type_)) + return false; + + return true; +} + +// Whether this matches another Object_attribute OA in merging. +// Two Object_attributes match if they have the same values. + +bool +Object_attribute::matches(const Object_attribute& oa) const +{ + return ((this->int_value_ != oa.int_value_) + && (this->string_value_ == oa.string_value_)); +} + +// Write this with TAG to a BUFFER. + +void +Object_attribute::write( + int tag, + std::vector<unsigned char>* buffer) const +{ + // No need to write default attributes. + if (this->is_default_attribute()) + return; + + // Write tag. + write_unsigned_LEB_128(buffer, convert_types<uint64_t, int>(tag)); + + // Write integer value. + if (Object_attribute::attribute_type_has_int_value(this->type_)) + write_unsigned_LEB_128(buffer, + convert_types<uint64_t, int>(this->int_value_)); + + // Write string value. + if (Object_attribute::attribute_type_has_string_value(this->type_)) + { + const unsigned char* start = + reinterpret_cast<const unsigned char*>(this->string_value_.c_str()); + const unsigned char* end = start + this->string_value_.size() + 1; + buffer->insert(buffer->end(), start, end); + } +} + +// Vendor_object_attributes methods. + +// Copying constructor. + +Vendor_object_attributes::Vendor_object_attributes( + const Vendor_object_attributes& voa) +{ + this->vendor_ = voa.vendor_; + + for (int i = 0; i < NUM_KNOWN_ATTRIBUTES; ++i) + this->known_attributes_[i] = voa.known_attributes_[i]; + + // We do not handle attribute deletion. So this must be empty. + gold_assert(this->other_attributes_.empty()); + + for (Other_attributes::const_iterator p = voa.other_attributes_.begin(); + p != voa.other_attributes_.end(); + ++p) + this->other_attributes_[p->first] = new Object_attribute(*(p->second)); +} + +// Size of this in number of bytes. + +size_t +Vendor_object_attributes::size() const +{ + if (this->name() == NULL) + return 0; + + size_t data_size = 0; + for (int i = 4; i < NUM_KNOWN_ATTRIBUTES; ++i) + data_size += this->known_attributes_[i].size(i); + + for (Other_attributes::const_iterator p = this->other_attributes_.begin(); + p != this->other_attributes_.end(); + ++p) + data_size += p->second->size(p->first); + + // <size> <vendor_name> NUL 0x1 <size> + return ((data_size != 0 + || this->vendor_ == Object_attribute::OBJ_ATTR_PROC) + ? data_size + strlen(this->name()) + 2 + 2 * 4 + : 0); +} + +// Return a new attribute associated with TAG. + +Object_attribute* +Vendor_object_attributes::new_attribute(int tag) +{ + int type = Object_attribute::arg_type(this->vendor_, tag); + + if (tag < NUM_KNOWN_ATTRIBUTES) + { + this->known_attributes_[tag].set_type(type); + return &this->known_attributes_[tag]; + } + else + { + Object_attribute* attr = new Object_attribute(); + + // This should be the first time we insert this. + std::pair<Other_attributes::iterator, bool> ins = + this->other_attributes_.insert(std::make_pair(tag, attr)); + gold_assert(ins.second); + + attr->set_type(type); + return attr; + } +} + +// Return an attribute associated with TAG. + +Object_attribute* +Vendor_object_attributes::get_attribute(int tag) +{ + if (tag < NUM_KNOWN_ATTRIBUTES) + return &this->known_attributes_[tag]; + else + { + Other_attributes::iterator p = + this->other_attributes_.find(tag); + return p != this->other_attributes_.end() ? p->second : NULL; + } +} + +const Object_attribute* +Vendor_object_attributes::get_attribute(int tag) const +{ + if (tag < NUM_KNOWN_ATTRIBUTES) + return &this->known_attributes_[tag]; + else + { + Other_attributes::const_iterator p = + this->other_attributes_.find(tag); + return p != this->other_attributes_.end() ? p->second : NULL; + } +} + +// Write attributes to BUFFER. + +void +Vendor_object_attributes::write(std::vector<unsigned char>* buffer) const +{ + // Write subsection size. + size_t voa_size = this->size(); + uint32_t voa_size_as_u32 = convert_types<uint32_t, size_t>(voa_size); + insert_into_vector<32>(buffer, voa_size_as_u32); + + // Write vendor name. + const unsigned char* vendor_start = + reinterpret_cast<const unsigned char*>(this->name()); + size_t vendor_length = strlen(this->name()) + 1; + const unsigned char* vendor_end = vendor_start + vendor_length; + buffer->insert(buffer->end(), vendor_start, vendor_end); + + // Write file tag. + buffer->push_back(Object_attribute::Tag_File); + + // Write attributes size. + uint32_t attributes_size_as_u32 = + convert_types<uint32_t, size_t>(voa_size - 4 - vendor_length); + insert_into_vector<32>(buffer, attributes_size_as_u32); + + // Write known attributes, skipping any defaults. + for (int i = 4; i < NUM_KNOWN_ATTRIBUTES; ++i) + { + // A target may write known attributes in a special order. + // Call target hook to remap tags. Attributes_order is the identity + // function if no re-ordering is required. + int tag = parameters->target().attributes_order(i); + this->known_attributes_[tag].write(tag, buffer); + } + + // Write other attributes. + for (Other_attributes::const_iterator q = this->other_attributes_.begin(); + q != this->other_attributes_.end(); + ++q) + q->second->write(q->first, buffer); +} + +// Attributes_section_data methods. + +// Compute encoded size of this. + +size_t +Attributes_section_data::size() const +{ + size_t data_size = 0; + for(int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) + data_size += this->vendor_object_attributes_[vendor]->size(); + + // 'A' <sections for each vendor> + return data_size != 0 ? data_size + 1 : 0; +} + +// Construct an Attributes_section_data object by parsing section contents +// specified by VIEW and SIZE. + +Attributes_section_data::Attributes_section_data( + const unsigned char* view, + section_size_type size) +{ + for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) + this->vendor_object_attributes_[vendor] = + new Vendor_object_attributes(vendor); + + const unsigned char *p = view; + p = view; + if (*(p++) == 'A') + { + size--; + while (size > 0) + { + // Size of vendor attributes section. + section_size_type section_size = + convert_to_section_size_type(read_from_pointer<32>(&p)); + + if (section_size > size) + section_size = size; + size -= section_size; + + const char* section_name = reinterpret_cast<const char*>(p); + section_size_type section_name_size = strlen(section_name) + 1; + section_size -= section_name_size + 4; + + int vendor; + const char *std_section = parameters->target().attributes_vendor(); + if (std_section != NULL && strcmp(section_name, std_section) == 0) + vendor = Object_attribute::OBJ_ATTR_PROC; + else if (strcmp(section_name, "gnu") == 0) + vendor = Object_attribute::OBJ_ATTR_GNU; + else + { + // Other vendor section. Ignore it. + p += section_name_size + section_size; + continue; + } + p += section_name_size; + + while (section_size > 0) + { + const unsigned char* subsection_start = p; + + // Read vendor subsection index and size. + size_t uleb128_len; + uint64_t val = read_unsigned_LEB_128(p, &uleb128_len); + p += uleb128_len; + + int tag = convert_types<int, uint64_t>(val); + section_size_type subsection_size = + convert_to_section_size_type(read_from_pointer<32>(&p)); + section_size -= subsection_size; + subsection_size -= (p - subsection_start); + + const unsigned char* end = p + subsection_size; + switch (tag) + { + case Object_attribute::Tag_File: + while (p < end) + { + val = read_unsigned_LEB_128(p, &uleb128_len); + p += uleb128_len; + tag = convert_types<int, uint64_t>(val); + Vendor_object_attributes* pvoa = + this->vendor_object_attributes_[vendor]; + Object_attribute* attr = pvoa->new_attribute(tag); + const char* string_arg; + unsigned int int_arg; + + int type = Object_attribute::arg_type(vendor, tag); + switch (type + & (Object_attribute::ATTR_TYPE_FLAG_INT_VAL + | Object_attribute::ATTR_TYPE_FLAG_STR_VAL)) + { + case (Object_attribute::ATTR_TYPE_FLAG_INT_VAL + | Object_attribute::ATTR_TYPE_FLAG_STR_VAL): + val = read_unsigned_LEB_128(p, &uleb128_len); + p += uleb128_len; + int_arg = convert_types<unsigned int, uint64_t>(val); + string_arg = reinterpret_cast<const char *>(p); + attr->set_int_value(int_arg); + p += strlen(string_arg) + 1; + break; + case Object_attribute::ATTR_TYPE_FLAG_STR_VAL: + string_arg = reinterpret_cast<const char *>(p); + attr->set_string_value(string_arg); + p += strlen(string_arg) + 1; + break; + case Object_attribute::ATTR_TYPE_FLAG_INT_VAL: + val = read_unsigned_LEB_128(p, &uleb128_len); + p += uleb128_len; + int_arg = convert_types<unsigned int, uint64_t>(val); + attr->set_int_value(int_arg); + break; + default: + gold_unreachable(); + } + } + break; + case Object_attribute::Tag_Section: + case Object_attribute::Tag_Symbol: + // Don't have anywhere convenient to attach these. + // Fall through for now. + default: + // Ignore things we don't know about. + p += subsection_size; + subsection_size = 0; + break; + } + } + } + } +} + +// Merge target-independent attributes from another Attribute_section_data +// ASD from an object called NAME into this. + +void +Attributes_section_data::merge( + const char* name, + const Attributes_section_data* pasd) +{ + // The only common attribute is currently Tag_compatibility, + // accepted in both processor and "gnu" sections. + for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) + { + // Handle Tag_compatibility. The tags are only compatible if the flags + // are identical and, if the flags are '1', the strings are identical. + // If the flags are non-zero, then we can only use the string "gnu". + const Object_attribute* in_attr = + &pasd->known_attributes(vendor)[Object_attribute::Tag_compatibility]; + Object_attribute* out_attr = + &this->known_attributes(vendor)[Object_attribute::Tag_compatibility]; + + if (in_attr->int_value() > 0 + && in_attr->string_value() != "gnu") + { + gold_error(_("%s: must be processed by '%s' toolchain"), + name, in_attr->string_value().c_str()); + return; + } + + if (in_attr->int_value() != out_attr->int_value() + || in_attr->string_value() != out_attr->string_value()) + { + gold_error(_("%s: object tag '%d, %s' is " + "incompatible with tag '%d, %s'"), + name, in_attr->int_value(), + in_attr->string_value().c_str(), + out_attr->int_value(), + out_attr->string_value().c_str()); + } + } +} + +// Write to a buffer. + +void +Attributes_section_data::write(std::vector<unsigned char>* buffer) const +{ + buffer->push_back('A'); + for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) + if (this->vendor_object_attributes_[vendor]->size() != 0) + this->vendor_object_attributes_[vendor]->write(buffer); +} + +// Methods for Output_attributes_section_data. + +// Write attributes section data to file OF. + +void +Output_attributes_section_data::do_write(Output_file* of) +{ + off_t offset = this->offset(); + const section_size_type oview_size = + convert_to_section_size_type(this->data_size()); + unsigned char* const oview = of->get_output_view(offset, oview_size); + + std::vector<unsigned char> buffer; + this->attributes_section_data_.write(&buffer); + gold_assert(convert_to_section_size_type(buffer.size()) == oview_size); + memcpy(oview, buffer.data(), buffer.size()); + of->write_output_view(this->offset(), oview_size, oview); +} + +} // End namespace gold. diff --git a/gold/attributes.h b/gold/attributes.h new file mode 100644 index 00000000000..7c4baf4b950 --- /dev/null +++ b/gold/attributes.h @@ -0,0 +1,406 @@ +// attributes.h -- object attributes for gold -*- C++ -*- + +// Copyright 2009 Free Software Foundation, Inc. +// Written by Doug Kwan <dougkwan@google.com>. +// This file contains code adapted from BFD. + +// 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. + +// Handle object attributes. + +#ifndef GOLD_ATTRIBUTES_H +#define GOLD_ATTRIBUTES_H + +#include <map> + +#include "parameters.h" +#include "target.h" +#include "output.h" +#include "reduced_debug_output.h" + +namespace gold +{ + +// Object attribute values. The attribute tag is not stored in this object. + +class Object_attribute +{ + public: + // The value of an object attribute. The type indicates whether the + // attribute holds and integer, a string, or both. It can also indicate that + // there can be no default (i.e. all values must be written to file, even + // zero). + enum + { + ATTR_TYPE_FLAG_INT_VAL = (1 << 0), + ATTR_TYPE_FLAG_STR_VAL = (1 << 1), + ATTR_TYPE_FLAG_NO_DEFAULT = (1 << 2) + }; + + // Object attributes may either be defined by the processor ABI, index + // OBJ_ATTR_PROC in the *_obj_attributes arrays, or be GNU-specific + // (and possibly also processor-specific), index OBJ_ATTR_GNU. + enum + { + OBJ_ATTR_PROC, + OBJ_ATTR_GNU, + OBJ_ATTR_FIRST = OBJ_ATTR_PROC, + OBJ_ATTR_LAST = OBJ_ATTR_GNU + }; + + // The following object attribute tags are taken as generic, for all + // targets and for "gnu" where there is no target standard. + enum + { + Tag_NULL = 0, + Tag_File = 1, + Tag_Section = 2, + Tag_Symbol = 3, + Tag_compatibility = 32 + }; + + Object_attribute() + : type_(0), int_value_(0), string_value_() + { } + + // Copying constructor. We need to implement this to copy the string value. + Object_attribute(const Object_attribute& oa) + : type_(oa.type_), int_value_(oa.int_value_), string_value_(oa.string_value_) + { } + + ~Object_attribute() + { } + + // Assignment operator. We need to implement this to copy the string value. + Object_attribute& + operator=(const Object_attribute& source) + { + this->type_ = source.type_; + this->int_value_ = source.int_value_; + this->string_value_ = source.string_value_; + return *this; + } + + // Return attribute type. + int + type() const + { return this->type_; } + + // Set attribute type. + void + set_type(int type) + { this->type_ = type; } + + // Return integer value. + unsigned int + int_value() const + { return this->int_value_; } + + // Set integer value. + void + set_int_value(unsigned int i) + { this->int_value_ = i; } + + // Return string value. + const std::string& + string_value() const + { return this->string_value_; } + + // Set string value. + void + set_string_value(const std::string& s) + { this->string_value_ = s; } + + void + set_string_value(const char* s) + { this->string_value_ = s; } + + // Whether attribute type has integer value. + static bool + attribute_type_has_int_value(int type) + { return (type & ATTR_TYPE_FLAG_INT_VAL) != 0; } + + // Whether attribute type has string value. + static bool + attribute_type_has_string_value(int type) + { return (type & ATTR_TYPE_FLAG_STR_VAL) != 0; } + + // Whether attribute type has no default value. + static bool + attribute_type_has_no_default(int type) + { return (type & ATTR_TYPE_FLAG_NO_DEFAULT) != 0; } + + // Whether this has default value (0/""). + bool + is_default_attribute() const; + + // Return ULEB128 encoded size of tag and attribute. + size_t + size(int tag) const; + + // Whether this matches another object attribute in merging. + bool + matches(const Object_attribute& oa) const; + + // Write to attribute with tag to BUFFER. + void + write(int tag, std::vector<unsigned char>* buffer) const; + + // Determine what arguments an attribute tag takes. + static int + arg_type (int vendor, int tag) + { + switch (vendor) + { + case OBJ_ATTR_PROC: + return parameters->target().attribute_arg_type(tag); + case OBJ_ATTR_GNU: + return Object_attribute::gnu_arg_type(tag); + default: + gold_unreachable(); + } + } + + private: + // Determine whether a GNU object attribute tag takes an integer, a + // string or both. */ + static int + gnu_arg_type (int tag) + { + // Except for Tag_compatibility, for GNU attributes we follow the + // same rule ARM ones > 32 follow: odd-numbered tags take strings + // and even-numbered tags take integers. In addition, tag & 2 is + // nonzero for architecture-independent tags and zero for + // architecture-dependent ones. + if (tag == Object_attribute::Tag_compatibility) + return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL; + else + return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL; + } + + // Attribute type. + int type_; + // Integer value. + int int_value_; + // String value. + std::string string_value_; +}; + +// This class contains attributes of a particular vendor. + +class Vendor_object_attributes +{ + public: + // The maximum number of known object attributes for any target. + static const int NUM_KNOWN_ATTRIBUTES = 71; + + Vendor_object_attributes(int vendor) + : vendor_(vendor), other_attributes_() + { } + + // Copying constructor. + Vendor_object_attributes(const Vendor_object_attributes&); + + ~Vendor_object_attributes() + { + for (Other_attributes::iterator p = this->other_attributes_.begin(); + p != this->other_attributes_.end(); + ++p) + delete p->second; + } + + // Size of this in number of bytes. + size_t + size() const; + + // Name of this written vendor subsection. + const char* + name() const + { + return (this->vendor_ == Object_attribute::OBJ_ATTR_PROC + ? parameters->target().attributes_vendor() + : "gnu"); + } + + // Return an array of known attributes. + Object_attribute* + known_attributes() + { return &this->known_attributes_[0]; } + + const Object_attribute* + known_attributes() const + { return &this->known_attributes_[0]; } + + typedef std::map<int, Object_attribute*> Other_attributes; + + // Return attributes other than the known ones. + Other_attributes* + other_attributes() + { return &this->other_attributes_; } + + const Other_attributes* + other_attributes() const + { return &this->other_attributes_; } + + // Return a new attribute asssociated with TAG. + Object_attribute* + new_attribute(int tag); + + // Get an attribute + Object_attribute* + get_attribute(int tag); + + const Object_attribute* + get_attribute(int tag) const; + + // Write to BUFFER. + void + write(std::vector<unsigned char>* buffer) const; + + private: + // Vendor of the object attributes. + int vendor_; + // Attributes with known tags. There are store in an array for fast + // access. + Object_attribute known_attributes_[NUM_KNOWN_ATTRIBUTES]; + // Attributes with known tags. There are stored in a sorted container. + Other_attributes other_attributes_; +}; + +// This class contains contents of an attributes section. + +class Attributes_section_data +{ + public: + // Construct an Attributes_section_data object by parsing section contents + // in VIEW of SIZE. + Attributes_section_data(const unsigned char* view, section_size_type size); + + // Copying constructor. + Attributes_section_data(const Attributes_section_data& asd) + { + for (int vendor = Object_attribute::OBJ_ATTR_FIRST; + vendor <= Object_attribute::OBJ_ATTR_LAST; + ++vendor) + this->vendor_object_attributes_[vendor] = + new Vendor_object_attributes(*asd.vendor_object_attributes_[vendor]); + } + + ~Attributes_section_data() + { + for (int vendor = Object_attribute::OBJ_ATTR_FIRST; + vendor <= Object_attribute::OBJ_ATTR_LAST; + ++vendor) + delete this->vendor_object_attributes_[vendor]; + } + + // Return the size of this as number of bytes. + size_t + size() const; + + // Return an array of known attributes. + Object_attribute* + known_attributes(int vendor) + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->known_attributes(); + } + + const Object_attribute* + known_attributes(int vendor) const + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->known_attributes(); + } + + // Return the other attributes. + Vendor_object_attributes::Other_attributes* + other_attributes(int vendor) + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->other_attributes(); + } + + // Return the other attributes. + const Vendor_object_attributes::Other_attributes* + other_attributes(int vendor) const + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->other_attributes(); + } + + // Return an attribute. + Object_attribute* + get_attribute(int vendor, int tag) + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->get_attribute(tag); + } + + const Object_attribute* + get_attribute(int vendor, int tag) const + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->get_attribute(tag); + } + + // Merge target-independent attributes from another Attributes_section_data + // of an object called NAME. + void + merge(const char* name, const Attributes_section_data* pasd); + + // Write to byte stream in an unsigned char vector. + void + write(std::vector<unsigned char>*) const; + + private: + // For convenience. + static const int OBJ_ATTR_FIRST = Object_attribute::OBJ_ATTR_FIRST; + static const int OBJ_ATTR_LAST = Object_attribute::OBJ_ATTR_LAST; + + // Vendor object attributes. + Vendor_object_attributes* vendor_object_attributes_[OBJ_ATTR_LAST+1]; +}; + +// This class is used for writing out an Attribute_section_data. + +class Output_attributes_section_data : public Output_section_data +{ + public: + Output_attributes_section_data(const Attributes_section_data& asd) + : Output_section_data(1), attributes_section_data_(asd) + { } + + protected: + // Write the data to the output file. + void + do_write(Output_file*); + + // Set final data size. + void + set_final_data_size() + { this->set_data_size(attributes_section_data_.size()); } + + private: + // Attributes_section_data corresponding to this. + const Attributes_section_data& attributes_section_data_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_ATTRIBUTES_H) diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc index d142586a607..4062fe67c31 100644 --- a/gold/dwarf_reader.cc +++ b/gold/dwarf_reader.cc @@ -31,77 +31,10 @@ #include "parameters.h" #include "reloc.h" #include "dwarf_reader.h" +#include "int_encoding.h" namespace gold { -// Read an unsigned LEB128 number. Each byte contains 7 bits of -// information, plus one bit saying whether the number continues or -// not. - -uint64_t -read_unsigned_LEB_128(const unsigned char* buffer, size_t* len) -{ - uint64_t result = 0; - size_t num_read = 0; - unsigned int shift = 0; - unsigned char byte; - - do - { - if (num_read >= 64 / 7) - { - gold_warning(_("Unusually large LEB128 decoded, " - "debug information may be corrupted")); - break; - } - byte = *buffer++; - num_read++; - result |= (static_cast<uint64_t>(byte & 0x7f)) << shift; - shift += 7; - } - while (byte & 0x80); - - *len = num_read; - - return result; -} - -// Read a signed LEB128 number. These are like regular LEB128 -// numbers, except the last byte may have a sign bit set. - -int64_t -read_signed_LEB_128(const unsigned char* buffer, size_t* len) -{ - int64_t result = 0; - int shift = 0; - size_t num_read = 0; - unsigned char byte; - - do - { - if (num_read >= 64 / 7) - { - gold_warning(_("Unusually large LEB128 decoded, " - "debug information may be corrupted")); - break; - } - byte = *buffer++; - num_read++; - result |= (static_cast<uint64_t>(byte & 0x7f) << shift); - shift += 7; - } - while (byte & 0x80); - - if ((shift < 8 * static_cast<int>(sizeof(result))) && (byte & 0x40)) - result |= -((static_cast<int64_t>(1)) << shift); - *len = num_read; - return result; -} - -// This is the format of a DWARF2/3 line state machine that we process -// opcodes using. There is no need for anything outside the lineinfo -// processor to know how this works. - struct LineStateMachine { int file_num; diff --git a/gold/dwarf_reader.h b/gold/dwarf_reader.h index c18ed8951b0..e2b8aa0e3ce 100644 --- a/gold/dwarf_reader.h +++ b/gold/dwarf_reader.h @@ -38,12 +38,6 @@ template<int size, bool big_endian> class Track_relocs; struct LineStateMachine; -uint64_t -read_unsigned_LEB_128(const unsigned char* buffer, size_t* len); - -int64_t -read_signed_LEB_128(const unsigned char* buffer, size_t* len); - // 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 diff --git a/gold/int_encoding.cc b/gold/int_encoding.cc new file mode 100644 index 00000000000..ef58749ae85 --- /dev/null +++ b/gold/int_encoding.cc @@ -0,0 +1,131 @@ +// varint.cc -- variable length and unaligned integer encoding support. + +// Copyright 2009 Free Software Foundation, Inc. +// Written by Doug Kwan <dougkwan@google.com> by refactoring scattered +// contents from other files in gold. Original code written by Ian +// Lance Taylor <iant@google.com> and Caleb Howe <cshowe@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 "gold.h" + +#include <vector> + +#include "int_encoding.h" + +namespace gold { + +// Read an unsigned LEB128 number. Each byte contains 7 bits of +// information, plus one bit saying whether the number continues or +// not. + +uint64_t +read_unsigned_LEB_128(const unsigned char* buffer, size_t* len) +{ + uint64_t result = 0; + size_t num_read = 0; + unsigned int shift = 0; + unsigned char byte; + + do + { + if (num_read >= 64 / 7) + { + gold_warning(_("Unusually large LEB128 decoded, " + "debug information may be corrupted")); + break; + } + byte = *buffer++; + num_read++; + result |= (static_cast<uint64_t>(byte & 0x7f)) << shift; + shift += 7; + } + while (byte & 0x80); + + *len = num_read; + + return result; +} + +// Read a signed LEB128 number. These are like regular LEB128 +// numbers, except the last byte may have a sign bit set. + +int64_t +read_signed_LEB_128(const unsigned char* buffer, size_t* len) +{ + int64_t result = 0; + int shift = 0; + size_t num_read = 0; + unsigned char byte; + + do + { + if (num_read >= 64 / 7) + { + gold_warning(_("Unusually large LEB128 decoded, " + "debug information may be corrupted")); + break; + } + byte = *buffer++; + num_read++; + result |= (static_cast<uint64_t>(byte & 0x7f) << shift); + shift += 7; + } + while (byte & 0x80); + + if ((shift < 8 * static_cast<int>(sizeof(result))) && (byte & 0x40)) + result |= -((static_cast<int64_t>(1)) << shift); + *len = num_read; + return result; +} + +void +write_unsigned_LEB_128(std::vector<unsigned char>* buffer, uint64_t value) +{ + do + { + unsigned char current_byte = value & 0x7f; + value >>= 7; + if (value != 0) + { + current_byte |= 0x80; + } + buffer->push_back(current_byte); + } + while (value != 0); +} + +size_t +get_length_as_unsigned_LEB_128(uint64_t value) +{ + size_t length = 0; + do + { + unsigned char current_byte = value & 0x7f; + value >>= 7; + if (value != 0) + { + current_byte |= 0x80; + } + length++; + } + while (value != 0); + return length; +} + +} // End namespace gold. diff --git a/gold/int_encoding.h b/gold/int_encoding.h new file mode 100644 index 00000000000..b60e969f8d5 --- /dev/null +++ b/gold/int_encoding.h @@ -0,0 +1,112 @@ +// int_encoding.h -- variable length and unaligned integers -*- C++ -*- + +// Copyright 2009 Free Software Foundation, Inc. +// Written by Doug Kwan <dougkwan@google.com> by refactoring scattered +// contents from other files in gold. Original code written by Ian +// Lance Taylor <iant@google.com> and Caleb Howe <cshowe@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. + +#ifndef GOLD_INT_ENCODING_H +#define GOLD_INT_ENCODING_H + +#include <vector> +#include "elfcpp.h" +#include "target.h" +#include "parameters.h" + +namespace gold +{ + +// +// LEB 128 encoding support. +// + +// Read a ULEB 128 encoded integer from BUFFER. Return the length of the +// encoded integer at the location PLEN. + +uint64_t +read_unsigned_LEB_128(const unsigned char* buffer, size_t* plen); + +// Read an SLEB 128 encoded integer from BUFFER. Return the length of the +// encoded integer at the location PLEN. + +int64_t +read_signed_LEB_128(const unsigned char* buffer, size_t* plen); + +// Write a ULEB 128 encoded VALUE to BUFFER. + +void +write_unsigned_LEB_128(std::vector<unsigned char>* buffer, uint64_t value); + +// Return the ULEB 128 encoded size of VALUE. + +size_t +get_length_as_unsigned_LEB_128(uint64_t value); + +// +// Unaligned integer encoding support. +// + +// Insert VALSIZE-bit integer VALUE into DESTINATION. + +template <int valsize> +void insert_into_vector(std::vector<unsigned char>* destination, + typename elfcpp::Valtype_base<valsize>::Valtype value) +{ + unsigned char buffer[valsize / 8]; + if (parameters->target().is_big_endian()) + elfcpp::Swap_unaligned<valsize, true>::writeval(buffer, value); + else + elfcpp::Swap_unaligned<valsize, false>::writeval(buffer, value); + destination->insert(destination->end(), buffer, buffer + valsize / 8); +} + +// Read a possibly unaligned integer of SIZE. Update SOURCE after read. + +template <int valsize> +typename elfcpp::Valtype_base<valsize>::Valtype +read_from_pointer(unsigned char** source) +{ + typename elfcpp::Valtype_base<valsize>::Valtype return_value; + if (parameters->target().is_big_endian()) + return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source); + else + return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source); + *source += valsize / 8; + return return_value; +} + +// Same as the above except for use with const unsigned char data. + +template <int valsize> +typename elfcpp::Valtype_base<valsize>::Valtype +read_from_pointer(const unsigned char** source) +{ + typename elfcpp::Valtype_base<valsize>::Valtype return_value; + if (parameters->target().is_big_endian()) + return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source); + else + return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source); + *source += valsize / 8; + return return_value; +} + +} // End namespace gold. + +#endif // !defined(GOLD_INT_ENCODING_H) diff --git a/gold/reduced_debug_output.cc b/gold/reduced_debug_output.cc index 48346943dd5..5bc8053f978 100644 --- a/gold/reduced_debug_output.cc +++ b/gold/reduced_debug_output.cc @@ -27,71 +27,13 @@ #include "dwarf.h" #include "dwarf_reader.h" #include "reduced_debug_output.h" +#include "int_encoding.h" #include <vector> namespace gold { -void -write_unsigned_LEB_128(std::vector<unsigned char>* buffer, uint64_t value) -{ - do - { - unsigned char current_byte = value & 0x7f; - value >>= 7; - if (value != 0) - { - current_byte |= 0x80; - } - buffer->push_back(current_byte); - } - while (value != 0); -} - -size_t -get_length_as_unsigned_LEB_128(uint64_t value) -{ - size_t length = 0; - do - { - unsigned char current_byte = value & 0x7f; - value >>= 7; - if (value != 0) - { - current_byte |= 0x80; - } - length++; - } - while (value != 0); - return length; -} - -template <int valsize> -void insert_into_vector(std::vector<unsigned char>* destination, - typename elfcpp::Valtype_base<valsize>::Valtype value) -{ - unsigned char buffer[valsize / 8]; - if (parameters->target().is_big_endian()) - elfcpp::Swap_unaligned<valsize, true>::writeval(buffer, value); - else - elfcpp::Swap_unaligned<valsize, false>::writeval(buffer, value); - destination->insert(destination->end(), buffer, buffer + valsize / 8); -} - -template <int valsize> -typename elfcpp::Valtype_base<valsize>::Valtype -read_from_pointer(unsigned char** source) -{ - typename elfcpp::Valtype_base<valsize>::Valtype return_value; - if (parameters->target().is_big_endian()) - return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source); - else - return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source); - *source += valsize / 8; - return return_value; -} - // Given a pointer to the beginning of a die and the beginning of the associated // abbreviation fills in die_end with the end of the information entry. If // successful returns true. Get_die_end also takes a pointer to the end of the |