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