C++程序  |  262行  |  7.61 KB

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

#include "mcld/Config/Config.h"
#include "mcld/Fragment/RegionFragment.h"
#include "mcld/LD/SectionData.h"
#include "mcld/Support/Allocators.h"
#include "mcld/Support/Compiler.h"

#include <llvm/ADT/StringRef.h>

#include <list>
#include <map>
#include <vector>

namespace mcld {

class Input;
class LDSection;
class Relocation;

/** \class EhFrame
 *  \brief EhFrame represents .eh_frame section
 */
class EhFrame {
 private:
  friend class Chunk<EhFrame, MCLD_SECTIONS_PER_INPUT>;

  EhFrame();
  explicit EhFrame(LDSection& pSection);

  ~EhFrame();

 public:
  enum RecordType { RECORD_UNKNOWN, RECORD_INPUT, RECORD_GENERATED };

  class CIE;
  class FDE;

  typedef std::vector<CIE*> CIEList;
  typedef CIEList::iterator cie_iterator;
  typedef CIEList::const_iterator const_cie_iterator;

  typedef std::list<FDE*> FDEList;
  typedef FDEList::iterator fde_iterator;
  typedef FDEList::const_iterator const_fde_iterator;

  typedef std::map</*offset*/ size_t, CIE*> CIEMap;

  // A super class of CIE and FDE, containing the same part
  class Record : public RegionFragment {
   public:
    explicit Record(llvm::StringRef pRegion);
    virtual ~Record();

    const llvm::StringRef getRegion() const {
      return RegionFragment::getRegion();
    }
    llvm::StringRef getRegion() { return RegionFragment::getRegion(); }
    virtual RecordType getRecordType() const { return RECORD_UNKNOWN; }

   private:
    DISALLOW_COPY_AND_ASSIGN(Record);
  };

  /** \class CIE
   *  \brief Common Information Entry.
   *  The CIE structure refers to LSB Core Spec 4.1, chap.10.6. Exception
   * Frames.
   */
  class CIE : public Record {
   public:
    explicit CIE(llvm::StringRef pRegion);
    ~CIE();

    virtual RecordType getRecordType() const { return RECORD_INPUT; }

    void setFDEEncode(uint8_t pEncode) { m_FDEEncode = pEncode; }
    uint8_t getFDEEncode() const { return m_FDEEncode; }

    void setMergeable(bool pVal = true) { m_Mergeable = pVal; }
    virtual bool getMergeable() const { return m_Mergeable; }

    void setRelocation(const Relocation& pReloc) { m_pReloc = &pReloc; }
    const Relocation* getRelocation() const { return m_pReloc; }

    void setPersonalityOffset(uint64_t pOffset) {
      m_PersonalityOffset = pOffset;
    }
    uint64_t getPersonalityOffset() const { return m_PersonalityOffset; }

    void setPersonalityName(const std::string& pStr) {
      m_PersonalityName = pStr;
    }
    const std::string& getPersonalityName() const { return m_PersonalityName; }

    void setAugmentationData(const std::string& pStr) {
      m_AugmentationData = pStr;
    }
    const std::string& getAugmentationData() const {
      return m_AugmentationData;
    }

    void add(FDE& pFDE) { m_FDEs.push_back(&pFDE); }
    void remove(FDE& pFDE) { m_FDEs.remove(&pFDE); }
    void clearFDEs() { m_FDEs.clear(); }
    size_t numOfFDEs() const { return m_FDEs.size(); }

    const_fde_iterator begin() const { return m_FDEs.begin(); }
    fde_iterator begin() { return m_FDEs.begin(); }
    const_fde_iterator end() const { return m_FDEs.end(); }
    fde_iterator end() { return m_FDEs.end(); }

   private:
    uint8_t m_FDEEncode;
    bool m_Mergeable;
    const Relocation* m_pReloc;
    uint64_t m_PersonalityOffset;
    std::string m_PersonalityName;
    std::string m_AugmentationData;
    FDEList m_FDEs;
  };

  /** \class FDE
   *  \brief Frame Description Entry
   *  The FDE structure refers to LSB Core Spec 4.1, chap.10.6. Exception
   * Frames.
   */
  class FDE : public Record {
   public:
    FDE(llvm::StringRef pRegion, CIE& pCIE);
    ~FDE();

    void setCIE(CIE& pCIE);
    const CIE& getCIE() const { return *m_pCIE; }
    CIE& getCIE() { return *m_pCIE; }

   private:
    CIE* m_pCIE;  // Referenced CIE may change when merging.
  };

  // These are created for PLT
  class GeneratedCIE : public CIE {
   public:
    explicit GeneratedCIE(llvm::StringRef pRegion);
    ~GeneratedCIE();

    virtual RecordType getRecordType() const { return RECORD_GENERATED; }
    virtual bool getMergeable() const { return true; }
  };

  class GeneratedFDE : public FDE {
   public:
    GeneratedFDE(llvm::StringRef pRegion, CIE& pCIE);
    ~GeneratedFDE();

    virtual RecordType getRecordType() const { return RECORD_GENERATED; }
  };

 public:
  static EhFrame* Create(LDSection& pSection);

  static void Destroy(EhFrame*& pSection);

  static void Clear();

  /// merge - move all data from pOther to this object.
  EhFrame& merge(const Input& pInput, EhFrame& pInFrame);

  const LDSection& getSection() const;
  LDSection& getSection();

  const SectionData* getSectionData() const { return m_pSectionData; }
  SectionData* getSectionData() { return m_pSectionData; }

  // -----  fragment  ----- //
  void addFragment(Fragment& pFrag);

  /// addCIE - add a CIE entry in EhFrame
  void addCIE(CIE& pCIE, bool pAlsoAddFragment = true);

  /// addFDE - add a FDE entry in EhFrame
  void addFDE(FDE& pFDE, bool pAlsoAddFragment = true);

  // -----  CIE  ----- //
  const_cie_iterator cie_begin() const { return m_CIEs.begin(); }
  cie_iterator cie_begin() { return m_CIEs.begin(); }
  const_cie_iterator cie_end() const { return m_CIEs.end(); }
  cie_iterator cie_end() { return m_CIEs.end(); }

  const CIE& cie_front() const { return *m_CIEs.front(); }
  CIE& cie_front() { return *m_CIEs.front(); }
  const CIE& cie_back() const { return *m_CIEs.back(); }
  CIE& cie_back() { return *m_CIEs.back(); }

  bool emptyCIEs() const { return m_CIEs.empty(); }
  size_t numOfCIEs() const { return m_CIEs.size(); }
  size_t numOfFDEs() const;

  const CIEMap& getCIEMap() const { return m_FoundCIEs; }
  CIEMap& getCIEMap() { return m_FoundCIEs; }

 public:
  size_t computeOffsetSize();

  /// getDataStartOffset - Get the offset after length and ID field.
  /// The offset is 8byte for 32b, and 16byte for 64b.
  /// We can just use "BITCLASS/4" to represent offset.
  template <size_t BITCLASS>
  static size_t getDataStartOffset() {
    return BITCLASS / 4;
  }

 private:
  // We needs to check if it is mergeable and check personality name
  // before merging them. The important note is we must do this after
  // ALL readSections done, that is the reason why we don't check this
  // immediately when reading.
  void setupAttributes(const LDSection* reloc_sect);
  void removeDiscardedFDE(CIE& pCIE, const LDSection* pRelocEhFrameSect);

 private:
  void removeAndUpdateCIEForFDE(EhFrame& pInFrame,
                                CIE& pInCIE,
                                CIE& pOutCIE,
                                const LDSection* reloc_sect);
  void moveInputFragments(EhFrame& pInFrame);
  void moveInputFragments(EhFrame& pInFrame, CIE& pInCIE, CIE* pOutCIE = 0);

 private:
  LDSection* m_pSection;
  SectionData* m_pSectionData;

  // Each eh_frame has a list of CIE, and each CIE has a list of FDE
  // pointing to the CIE itself. This is used by management when we are
  // processing eh_frame merge.
  // However, don't forget we need to handle the Fragments inside SectionData
  // correctly since they are truly used when output emission.
  CIEList m_CIEs;

  // We need this map to find the corresponding CIE for FDE. Not all FDE point
  // to the nearest CIE.
  CIEMap m_FoundCIEs;

 private:
  DISALLOW_COPY_AND_ASSIGN(EhFrame);
};

bool operator==(const EhFrame::CIE&, const EhFrame::CIE&);

}  // namespace mcld

#endif  // MCLD_LD_EHFRAME_H_