Home | History | Annotate | Download | only in Core
      1 //===- Core/File.h - A Container of Atoms ---------------------------------===//
      2 //
      3 //                             The LLVM Linker
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef LLD_CORE_FILE_H
     11 #define LLD_CORE_FILE_H
     12 
     13 #include "lld/Core/AbsoluteAtom.h"
     14 #include "lld/Core/DefinedAtom.h"
     15 #include "lld/Core/SharedLibraryAtom.h"
     16 #include "lld/Core/UndefinedAtom.h"
     17 #include "llvm/ADT/Optional.h"
     18 #include "llvm/ADT/STLExtras.h"
     19 #include "llvm/ADT/Twine.h"
     20 #include "llvm/Support/ErrorHandling.h"
     21 #include <functional>
     22 #include <memory>
     23 #include <mutex>
     24 #include <vector>
     25 
     26 namespace lld {
     27 
     28 class LinkingContext;
     29 
     30 /// Every Atom is owned by some File. A common scenario is for a single
     31 /// object file (.o) to be parsed by some reader and produce a single
     32 /// File object that represents the content of that object file.
     33 ///
     34 /// To iterate through the Atoms in a File there are four methods that
     35 /// return collections.  For instance to iterate through all the DefinedAtoms
     36 /// in a File object use:
     37 ///      for (const DefinedAtoms *atom : file->defined()) {
     38 ///      }
     39 ///
     40 /// The Atom objects in a File are owned by the File object.  The Atom objects
     41 /// are destroyed when the File object is destroyed.
     42 class File {
     43 public:
     44   virtual ~File();
     45 
     46   /// \brief Kinds of files that are supported.
     47   enum Kind {
     48     kindErrorObject,          ///< a error object file (.o)
     49     kindNormalizedObject,     ///< a normalized file (.o)
     50     kindMachObject,           ///< a MachO object file (.o)
     51     kindCEntryObject,         ///< a file for CEntries
     52     kindHeaderObject,         ///< a file for file headers
     53     kindEntryObject,          ///< a file for the entry
     54     kindUndefinedSymsObject,  ///< a file for undefined symbols
     55     kindStubHelperObject,     ///< a file for stub helpers
     56     kindResolverMergedObject, ///< the resolver merged file.
     57     kindSectCreateObject,     ///< a sect create object file (.o)
     58     kindSharedLibrary,        ///< shared library (.so)
     59     kindArchiveLibrary        ///< archive (.a)
     60   };
     61 
     62   /// \brief Returns file kind.  Need for dyn_cast<> on File objects.
     63   Kind kind() const {
     64     return _kind;
     65   }
     66 
     67   /// This returns the path to the file which was used to create this object
     68   /// (e.g. "/tmp/foo.o"). If the file is a member of an archive file, the
     69   /// returned string includes the archive file name.
     70   StringRef path() const {
     71     if (_archivePath.empty())
     72       return _path;
     73     if (_archiveMemberPath.empty())
     74       _archiveMemberPath = (_archivePath + "(" + _path + ")").str();
     75     return _archiveMemberPath;
     76   }
     77 
     78   /// Returns the path of the archive file name if this file is instantiated
     79   /// from an archive file. Otherwise returns the empty string.
     80   StringRef archivePath() const { return _archivePath; }
     81   void setArchivePath(StringRef path) { _archivePath = path; }
     82 
     83   /// Returns the path name of this file. It doesn't include archive file name.
     84   StringRef memberPath() const { return _path; }
     85 
     86   /// Returns the command line order of the file.
     87   uint64_t ordinal() const {
     88     assert(_ordinal != UINT64_MAX);
     89     return _ordinal;
     90   }
     91 
     92   /// Returns true/false depending on whether an ordinal has been set.
     93   bool hasOrdinal() const { return (_ordinal != UINT64_MAX); }
     94 
     95   /// Sets the command line order of the file.
     96   void setOrdinal(uint64_t ordinal) const { _ordinal = ordinal; }
     97 
     98   /// Returns the ordinal for the next atom to be defined in this file.
     99   uint64_t getNextAtomOrdinalAndIncrement() const {
    100     return _nextAtomOrdinal++;
    101   }
    102 
    103   /// For allocating any objects owned by this File.
    104   llvm::BumpPtrAllocator &allocator() const {
    105     return _allocator;
    106   }
    107 
    108   /// The type of atom mutable container.
    109   template <typename T> using AtomVector = std::vector<OwningAtomPtr<T>>;
    110 
    111   /// The range type for the atoms.
    112   template <typename T> class AtomRange {
    113   public:
    114     AtomRange(AtomVector<T> &v) : _v(v) {}
    115     AtomRange(const AtomVector<T> &v) : _v(const_cast<AtomVector<T> &>(v)) {}
    116 
    117     typedef std::pointer_to_unary_function<const OwningAtomPtr<T>&,
    118                                            const T*> ConstDerefFn;
    119 
    120     typedef std::pointer_to_unary_function<OwningAtomPtr<T>&, T*> DerefFn;
    121 
    122     typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator,
    123                                   ConstDerefFn> ConstItTy;
    124     typedef llvm::mapped_iterator<typename AtomVector<T>::iterator,
    125                                   DerefFn> ItTy;
    126 
    127     static const T* DerefConst(const OwningAtomPtr<T> &p) {
    128       return p.get();
    129     }
    130 
    131     static T* Deref(OwningAtomPtr<T> &p) {
    132       return p.get();
    133     }
    134 
    135     ConstItTy begin() const {
    136       return ConstItTy(_v.begin(), ConstDerefFn(DerefConst));
    137     }
    138     ConstItTy end() const {
    139       return ConstItTy(_v.end(), ConstDerefFn(DerefConst));
    140     }
    141 
    142     ItTy begin() {
    143       return ItTy(_v.begin(), DerefFn(Deref));
    144     }
    145     ItTy end() {
    146       return ItTy(_v.end(), DerefFn(Deref));
    147     }
    148 
    149     llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() {
    150       return llvm::make_range(_v.begin(), _v.end());
    151     }
    152 
    153     llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() const {
    154       return llvm::make_range(_v.begin(), _v.end());
    155     }
    156 
    157     bool empty() const {
    158       return _v.empty();
    159     }
    160 
    161     size_t size() const {
    162       return _v.size();
    163     }
    164 
    165     const OwningAtomPtr<T> &operator[](size_t idx) const {
    166       return _v[idx];
    167     }
    168 
    169     OwningAtomPtr<T> &operator[](size_t idx) {
    170       return _v[idx];
    171     }
    172 
    173   private:
    174     AtomVector<T> &_v;
    175   };
    176 
    177   /// \brief Must be implemented to return the AtomVector object for
    178   /// all DefinedAtoms in this File.
    179   virtual const AtomRange<DefinedAtom> defined() const = 0;
    180 
    181   /// \brief Must be implemented to return the AtomVector object for
    182   /// all UndefinedAtomw in this File.
    183   virtual const AtomRange<UndefinedAtom> undefined() const = 0;
    184 
    185   /// \brief Must be implemented to return the AtomVector object for
    186   /// all SharedLibraryAtoms in this File.
    187   virtual const AtomRange<SharedLibraryAtom> sharedLibrary() const = 0;
    188 
    189   /// \brief Must be implemented to return the AtomVector object for
    190   /// all AbsoluteAtoms in this File.
    191   virtual const AtomRange<AbsoluteAtom> absolute() const = 0;
    192 
    193   /// Drop all of the atoms owned by this file.  This will result in all of
    194   /// the atoms running their destructors.
    195   /// This is required because atoms may be allocated on a BumpPtrAllocator
    196   /// of a different file.  We need to destruct all atoms before any files.
    197   virtual void clearAtoms() = 0;
    198 
    199   /// \brief If a file is parsed using a different method than doParse(),
    200   /// one must use this method to set the last error status, so that
    201   /// doParse will not be called twice. Only YAML reader uses this
    202   /// (because YAML reader does not read blobs but structured data).
    203   void setLastError(std::error_code err) { _lastError = err; }
    204 
    205   std::error_code parse();
    206 
    207   // Usually each file owns a std::unique_ptr<MemoryBuffer>.
    208   // However, there's one special case. If a file is an archive file,
    209   // the archive file and its children all shares the same memory buffer.
    210   // This method is used by the ArchiveFile to give its children
    211   // co-ownership of the buffer.
    212   void setSharedMemoryBuffer(std::shared_ptr<MemoryBuffer> mb) {
    213     _sharedMemoryBuffer = mb;
    214   }
    215 
    216 protected:
    217   /// \brief only subclasses of File can be instantiated
    218   File(StringRef p, Kind kind)
    219     : _path(p), _kind(kind), _ordinal(UINT64_MAX),
    220       _nextAtomOrdinal(0) {}
    221 
    222   /// \brief Subclasses should override this method to parse the
    223   /// memory buffer passed to this file's constructor.
    224   virtual std::error_code doParse() { return std::error_code(); }
    225 
    226   static AtomVector<DefinedAtom> _noDefinedAtoms;
    227   static AtomVector<UndefinedAtom> _noUndefinedAtoms;
    228   static AtomVector<SharedLibraryAtom> _noSharedLibraryAtoms;
    229   static AtomVector<AbsoluteAtom> _noAbsoluteAtoms;
    230   mutable llvm::BumpPtrAllocator _allocator;
    231 
    232 private:
    233   StringRef _path;
    234   std::string _archivePath;
    235   mutable std::string _archiveMemberPath;
    236   Kind              _kind;
    237   mutable uint64_t  _ordinal;
    238   mutable uint64_t _nextAtomOrdinal;
    239   std::shared_ptr<MemoryBuffer> _sharedMemoryBuffer;
    240   llvm::Optional<std::error_code> _lastError;
    241   std::mutex _parseMutex;
    242 };
    243 
    244 /// An ErrorFile represents a file that doesn't exist.
    245 /// If you try to parse a file which doesn't exist, an instance of this
    246 /// class will be returned. That's parse method always returns an error.
    247 /// This is useful to delay erroring on non-existent files, so that we
    248 /// can do unit testing a driver using non-existing file paths.
    249 class ErrorFile : public File {
    250 public:
    251   ErrorFile(StringRef path, std::error_code ec)
    252       : File(path, kindErrorObject), _ec(ec) {}
    253 
    254   std::error_code doParse() override { return _ec; }
    255 
    256   const AtomRange<DefinedAtom> defined() const override {
    257     llvm_unreachable("internal error");
    258   }
    259   const AtomRange<UndefinedAtom> undefined() const override {
    260     llvm_unreachable("internal error");
    261   }
    262   const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
    263     llvm_unreachable("internal error");
    264   }
    265   const AtomRange<AbsoluteAtom> absolute() const override {
    266     llvm_unreachable("internal error");
    267   }
    268 
    269   void clearAtoms() override {
    270   }
    271 
    272 private:
    273   std::error_code _ec;
    274 };
    275 
    276 } // end namespace lld
    277 
    278 #endif
    279