1 //===- MachOUniversal.h - Mach-O universal binaries -------------*- C++ -*-===//
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 // This file declares Mach-O fat/universal binaries.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_OBJECT_MACHOUNIVERSAL_H
14 #define LLVM_OBJECT_MACHOUNIVERSAL_H
15 
16 #include "llvm/ADT/iterator_range.h"
17 #include "llvm/BinaryFormat/MachO.h"
18 #include "llvm/Object/Binary.h"
19 #include "llvm/Object/MachO.h"
20 #include "llvm/TargetParser/Triple.h"
21 
22 namespace llvm {
23 class StringRef;
24 class LLVMContext;
25 
26 namespace object {
27 class Archive;
28 class IRObjectFile;
29 
30 class MachOUniversalBinary : public Binary {
31   virtual void anchor();
32 
33   uint32_t Magic;
34   uint32_t NumberOfObjects;
35 public:
36   static constexpr uint32_t MaxSectionAlignment = 15; /* 2**15 or 0x8000 */
37 
38   class ObjectForArch {
39     const MachOUniversalBinary *Parent;
40     /// Index of object in the universal binary.
41     uint32_t Index;
42     /// Descriptor of the object.
43     MachO::fat_arch Header;
44     MachO::fat_arch_64 Header64;
45 
46   public:
47     ObjectForArch(const MachOUniversalBinary *Parent, uint32_t Index);
48 
49     void clear() {
50       Parent = nullptr;
51       Index = 0;
52     }
53 
54     bool operator==(const ObjectForArch &Other) const {
55       return (Parent == Other.Parent) && (Index == Other.Index);
56     }
57 
58     ObjectForArch getNext() const { return ObjectForArch(Parent, Index + 1); }
59     uint32_t getCPUType() const {
60       if (Parent->getMagic() == MachO::FAT_MAGIC)
61         return Header.cputype;
62       else // Parent->getMagic() == MachO::FAT_MAGIC_64
63         return Header64.cputype;
64     }
65     uint32_t getCPUSubType() const {
66       if (Parent->getMagic() == MachO::FAT_MAGIC)
67         return Header.cpusubtype;
68       else // Parent->getMagic() == MachO::FAT_MAGIC_64
69         return Header64.cpusubtype;
70     }
71     uint64_t getOffset() const {
72       if (Parent->getMagic() == MachO::FAT_MAGIC)
73         return Header.offset;
74       else // Parent->getMagic() == MachO::FAT_MAGIC_64
75         return Header64.offset;
76     }
77     uint64_t getSize() const {
78       if (Parent->getMagic() == MachO::FAT_MAGIC)
79         return Header.size;
80       else // Parent->getMagic() == MachO::FAT_MAGIC_64
81         return Header64.size;
82     }
83     uint32_t getAlign() const {
84       if (Parent->getMagic() == MachO::FAT_MAGIC)
85         return Header.align;
86       else // Parent->getMagic() == MachO::FAT_MAGIC_64
87         return Header64.align;
88     }
89     uint32_t getReserved() const {
90       if (Parent->getMagic() == MachO::FAT_MAGIC)
91         return 0;
92       else // Parent->getMagic() == MachO::FAT_MAGIC_64
93         return Header64.reserved;
94     }
95     Triple getTriple() const {
96       return MachOObjectFile::getArchTriple(getCPUType(), getCPUSubType());
97     }
98     std::string getArchFlagName() const {
99       const char *McpuDefault, *ArchFlag;
100       MachOObjectFile::getArchTriple(getCPUType(), getCPUSubType(),
101                                      &McpuDefault, &ArchFlag);
102       return ArchFlag ? ArchFlag : std::string();
103     }
104 
105     Expected<std::unique_ptr<MachOObjectFile>> getAsObjectFile() const;
106     Expected<std::unique_ptr<IRObjectFile>>
107     getAsIRObject(LLVMContext &Ctx) const;
108 
109     Expected<std::unique_ptr<Archive>> getAsArchive() const;
110   };
111 
112   class object_iterator {
113     ObjectForArch Obj;
114   public:
115     object_iterator(const ObjectForArch &Obj) : Obj(Obj) {}
116     const ObjectForArch *operator->() const { return &Obj; }
117     const ObjectForArch &operator*() const { return Obj; }
118 
119     bool operator==(const object_iterator &Other) const {
120       return Obj == Other.Obj;
121     }
122     bool operator!=(const object_iterator &Other) const {
123       return !(*this == Other);
124     }
125 
126     object_iterator& operator++() {  // Preincrement
127       Obj = Obj.getNext();
128       return *this;
129     }
130   };
131 
132   MachOUniversalBinary(MemoryBufferRef Souce, Error &Err);
133   static Expected<std::unique_ptr<MachOUniversalBinary>>
134   create(MemoryBufferRef Source);
135 
136   object_iterator begin_objects() const {
137     return ObjectForArch(this, 0);
138   }
139   object_iterator end_objects() const {
140     return ObjectForArch(nullptr, 0);
141   }
142 
143   iterator_range<object_iterator> objects() const {
144     return make_range(begin_objects(), end_objects());
145   }
146 
147   uint32_t getMagic() const { return Magic; }
148   uint32_t getNumberOfObjects() const { return NumberOfObjects; }
149 
150   // Cast methods.
151   static bool classof(Binary const *V) {
152     return V->isMachOUniversalBinary();
153   }
154 
155   Expected<ObjectForArch>
156   getObjectForArch(StringRef ArchName) const;
157 
158   Expected<std::unique_ptr<MachOObjectFile>>
159   getMachOObjectForArch(StringRef ArchName) const;
160 
161   Expected<std::unique_ptr<IRObjectFile>>
162   getIRObjectForArch(StringRef ArchName, LLVMContext &Ctx) const;
163 
164   Expected<std::unique_ptr<Archive>>
165   getArchiveForArch(StringRef ArchName) const;
166 };
167 
168 }
169 }
170 
171 #endif
172