text: // attributes.h -- object attributes for gold   -*- C++ -*-
  
  // Copyright (C) 2009-2021 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 associated 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 to a map file.
    void
    do_print_to_mapfile(Mapfile* mapfile) const
    { mapfile->print_output_data(this, _("** attributes")); }
  
    // 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)
  