1 //===- Core/File.h - A Container of Atoms ---------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLD_CORE_FILE_H
10 #define LLD_CORE_FILE_H
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"
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.
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()) {
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.
45 /// Kinds of files that are supported.
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)
61 /// Returns file kind. Need for dyn_cast<> on File objects.
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())
72 if (_archiveMemberPath.empty())
73 _archiveMemberPath = (_archivePath + "(" + _path + ")").str();
74 return _archiveMemberPath;
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; }
82 /// Returns the path name of this file. It doesn't include archive file name.
83 StringRef memberPath() const { return _path; }
85 /// Returns the command line order of the file.
86 uint64_t ordinal() const {
87 assert(_ordinal != UINT64_MAX);
91 /// Returns true/false depending on whether an ordinal has been set.
92 bool hasOrdinal() const { return (_ordinal != UINT64_MAX); }
94 /// Sets the command line order of the file.
95 void setOrdinal(uint64_t ordinal) const { _ordinal = ordinal; }
97 /// Returns the ordinal for the next atom to be defined in this file.
98 uint64_t getNextAtomOrdinalAndIncrement() const {
99 return _nextAtomOrdinal++;
102 /// For allocating any objects owned by this File.
103 llvm::BumpPtrAllocator &allocator() const {
107 /// The type of atom mutable container.
108 template <typename T> using AtomVector = std::vector<OwningAtomPtr<T>>;
110 /// The range type for the atoms.
111 template <typename T> class AtomRange {
113 AtomRange(AtomVector<T> &v) : _v(v) {}
114 AtomRange(const AtomVector<T> &v) : _v(const_cast<AtomVector<T> &>(v)) {}
116 using ConstDerefFn = const T* (*)(const OwningAtomPtr<T>&);
117 using DerefFn = T* (*)(OwningAtomPtr<T>&);
119 typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator,
120 ConstDerefFn> ConstItTy;
121 typedef llvm::mapped_iterator<typename AtomVector<T>::iterator,
124 static const T* DerefConst(const OwningAtomPtr<T> &p) {
128 static T* Deref(OwningAtomPtr<T> &p) {
132 ConstItTy begin() const {
133 return ConstItTy(_v.begin(), ConstDerefFn(DerefConst));
135 ConstItTy end() const {
136 return ConstItTy(_v.end(), ConstDerefFn(DerefConst));
140 return ItTy(_v.begin(), DerefFn(Deref));
143 return ItTy(_v.end(), DerefFn(Deref));
146 llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() {
147 return llvm::make_range(_v.begin(), _v.end());
150 llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() const {
151 return llvm::make_range(_v.begin(), _v.end());
158 size_t size() const {
162 const OwningAtomPtr<T> &operator[](size_t idx) const {
166 OwningAtomPtr<T> &operator[](size_t idx) {
174 /// Must be implemented to return the AtomVector object for
175 /// all DefinedAtoms in this File.
176 virtual const AtomRange<DefinedAtom> defined() const = 0;
178 /// Must be implemented to return the AtomVector object for
179 /// all UndefinedAtomw in this File.
180 virtual const AtomRange<UndefinedAtom> undefined() const = 0;
182 /// Must be implemented to return the AtomVector object for
183 /// all SharedLibraryAtoms in this File.
184 virtual const AtomRange<SharedLibraryAtom> sharedLibrary() const = 0;
186 /// Must be implemented to return the AtomVector object for
187 /// all AbsoluteAtoms in this File.
188 virtual const AtomRange<AbsoluteAtom> absolute() const = 0;
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;
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; }
202 std::error_code parse();
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;
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) {}
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(); }
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;
231 std::string _archivePath;
232 mutable std::string _archiveMemberPath;
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;
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 {
248 ErrorFile(StringRef path, std::error_code ec)
249 : File(path, kindErrorObject), _ec(ec) {}
251 std::error_code doParse() override { return _ec; }
253 const AtomRange<DefinedAtom> defined() const override {
254 llvm_unreachable("internal error");
256 const AtomRange<UndefinedAtom> undefined() const override {
257 llvm_unreachable("internal error");
259 const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
260 llvm_unreachable("internal error");
262 const AtomRange<AbsoluteAtom> absolute() const override {
263 llvm_unreachable("internal error");
266 void clearAtoms() override {
273 } // end namespace lld