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