// attributes.h -- object attributes for gold   -*- C++ -*-

// Copyright (C) 2009-2024 Free Software Foundation, Inc.
// Written by Doug Kwan <[email protected]>.
// 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)