//===- LDSection.h --------------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MCLD_LD_LDSECTION_H_
#define MCLD_LD_LDSECTION_H_

#include "mcld/Config/Config.h"
#include "mcld/LD/LDFileFormat.h"
#include "mcld/Support/Allocators.h"

#include <llvm/Support/DataTypes.h>

#include <string>

namespace mcld {

class DebugString;
class EhFrame;
class RelocData;
class SectionData;

/** \class LDSection
 *  \brief LDSection represents a section header entry. It is a unified
 *  abstraction of a section header entry for various file formats.
 */
class LDSection {
 private:
  friend class Chunk<LDSection, MCLD_SECTIONS_PER_INPUT>;

  LDSection();

  LDSection(const std::string& pName,
            LDFileFormat::Kind pKind,
            uint32_t pType,
            uint32_t pFlag,
            uint64_t pSize = 0,
            uint64_t pAddr = 0);

 public:
  ~LDSection();

  static LDSection* Create(const std::string& pName,
                           LDFileFormat::Kind pKind,
                           uint32_t pType,
                           uint32_t pFlag,
                           uint64_t pSize = 0,
                           uint64_t pAddr = 0);

  static void Destroy(LDSection*& pSection);

  static void Clear();

  bool hasOffset() const;

  /// name - the name of this section.
  const std::string& name() const { return m_Name; }

  /// kind - the kind of this section, such as Text, BSS, GOT, and so on.
  /// from LDFileFormat::Kind
  LDFileFormat::Kind kind() const { return m_Kind; }

  /// type - The categorizes the section's contents and semantics. It's
  /// different from llvm::SectionKind. Type is format-dependent, but
  /// llvm::SectionKind is format independent and is used for bit-code.
  ///   In ELF, it is sh_type
  ///   In MachO, it's type field of struct section::flags
  uint32_t type() const { return m_Type; }

  /// flag - An integer describes miscellaneous attributes.
  ///   In ELF, it is sh_flags.
  ///   In MachO, it's attribute field of struct section::flags
  uint32_t flag() const { return m_Flag; }

  /// size - An integer specifying the size in bytes of the virtual memory
  /// occupied by this section.
  ///   In ELF, if the type() is SHT_NOBITS, this function return zero.
  ///   Before layouting, output's LDSection::size() should return zero.
  uint64_t size() const { return m_Size; }

  /// offset - An integer specifying the offset of this section in the file.
  ///   Before layouting, output's LDSection::offset() should return zero.
  uint64_t offset() const { return m_Offset; }

  /// addr - An integer specifying the virtual address of this section in the
  /// virtual image.
  ///   Before layouting, output's LDSection::offset() should return zero.
  ///   ELF uses sh_addralign to set alignment constraints. In LLVM, alignment
  ///   constraint is set in SectionData::setAlignment. addr() contains the
  ///   original ELF::sh_addr. Modulo sh_addr by sh_addralign is not necessary.
  ///   MachO uses the same scenario.
  ///
  ///   Because addr() in output is changing during linking, MCLinker does not
  ///   store the address of the output here. The address is in Layout
  uint64_t addr() const { return m_Addr; }

  /// align - An integer specifying the align of this section in the file.
  ///   Before layouting, output's LDSection::align() should return zero.
  uint32_t align() const { return m_Align; }

  size_t index() const { return m_Index; }

  /// getLink - return the Link. When a section A needs the other section B
  /// during linking or loading, we say B is A's Link section.
  /// In ELF, InfoLink section control the ElfNN_Shdr::sh_link and sh_info.
  ///
  /// @return if the section needs no other sections, return NULL
  LDSection* getLink() { return m_pLink; }

  const LDSection* getLink() const { return m_pLink; }

  size_t getInfo() const { return m_Info; }

  void setKind(LDFileFormat::Kind pKind) { m_Kind = pKind; }

  void setSize(uint64_t size) { m_Size = size; }

  void setOffset(uint64_t Offset) { m_Offset = Offset; }

  void setAddr(uint64_t addr) { m_Addr = addr; }

  void setAlign(uint32_t align) { m_Align = align; }

  void setFlag(uint32_t flag) { m_Flag = flag; }

  void setType(uint32_t type) { m_Type = type; }

  // -----  SectionData  ----- //
  const SectionData* getSectionData() const { return m_Data.sect_data; }
  SectionData* getSectionData() { return m_Data.sect_data; }

  void setSectionData(SectionData* pSD) { m_Data.sect_data = pSD; }

  bool hasSectionData() const;

  // ------  RelocData  ------ //
  const RelocData* getRelocData() const { return m_Data.reloc_data; }
  RelocData* getRelocData() { return m_Data.reloc_data; }

  void setRelocData(RelocData* pRD) { m_Data.reloc_data = pRD; }

  bool hasRelocData() const;

  // ------  EhFrame  ------ //
  const EhFrame* getEhFrame() const { return m_Data.eh_frame; }
  EhFrame* getEhFrame() { return m_Data.eh_frame; }

  void setEhFrame(EhFrame* pEhFrame) { m_Data.eh_frame = pEhFrame; }

  bool hasEhFrame() const;

  // ------  DebugString  ------ //
  const DebugString* getDebugString() const { return m_Data.debug_string; }
  DebugString*       getDebugString()       { return m_Data.debug_string; }

  void setDebugString(DebugString* pDebugString)
  { m_Data.debug_string = pDebugString; }

  bool hasDebugString() const;

  /// setLink - set the sections should link with.
  /// if pLink is NULL, no Link section is set.
  void setLink(LDSection* pLink) { m_pLink = pLink; }

  void setInfo(size_t pInfo) { m_Info = pInfo; }

  void setIndex(size_t pIndex) { m_Index = pIndex; }

 private:
  union Data {
    SectionData* sect_data;
    RelocData*   reloc_data;
    EhFrame*     eh_frame;
    DebugString* debug_string;
  };

 private:
  std::string m_Name;

  LDFileFormat::Kind m_Kind;
  uint32_t m_Type;
  uint32_t m_Flag;

  uint64_t m_Size;
  uint64_t m_Offset;
  uint64_t m_Addr;
  uint32_t m_Align;

  size_t m_Info;
  LDSection* m_pLink;

  /// m_Data - the SectionData or RelocData of this section
  Data m_Data;

  /// m_Index - the index of the file
  size_t m_Index;
};  // end of LDSection

}  // namespace mcld

#endif  // MCLD_LD_LDSECTION_H_