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