// 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)
