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     std::string getArchFlagName() const {
94       const char *McpuDefault, *ArchFlag;
95       if (Parent->getMagic() == MachO::FAT_MAGIC) {
96         Triple T =
97             MachOObjectFile::getArchTriple(Header.cputype, Header.cpusubtype,
98                                            &McpuDefault, &ArchFlag);
99       } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
100         Triple T =
101             MachOObjectFile::getArchTriple(Header64.cputype,
102                                            Header64.cpusubtype,
103                                            &McpuDefault, &ArchFlag);
104       }
105       if (ArchFlag) {
106         std::string ArchFlagName(ArchFlag);
107         return ArchFlagName;
108       } else {
109         std::string ArchFlagName("");
110         return ArchFlagName;
111       }
112     }
113 
114     Expected<std::unique_ptr<MachOObjectFile>> getAsObjectFile() const;
115 
116     Expected<std::unique_ptr<Archive>> getAsArchive() const;
117   };
118 
119   class object_iterator {
120     ObjectForArch Obj;
121   public:
122     object_iterator(const ObjectForArch &Obj) : Obj(Obj) {}
123     const ObjectForArch *operator->() const { return &Obj; }
124     const ObjectForArch &operator*() const { return Obj; }
125 
126     bool operator==(const object_iterator &Other) const {
127       return Obj == Other.Obj;
128     }
129     bool operator!=(const object_iterator &Other) const {
130       return !(*this == Other);
131     }
132 
133     object_iterator& operator++() {  // Preincrement
134       Obj = Obj.getNext();
135       return *this;
136     }
137   };
138 
139   MachOUniversalBinary(MemoryBufferRef Souce, Error &Err);
140   static Expected<std::unique_ptr<MachOUniversalBinary>>
141   create(MemoryBufferRef Source);
142 
143   object_iterator begin_objects() const {
144     return ObjectForArch(this, 0);
145   }
146   object_iterator end_objects() const {
147     return ObjectForArch(nullptr, 0);
148   }
149 
150   iterator_range<object_iterator> objects() const {
151     return make_range(begin_objects(), end_objects());
152   }
153 
154   uint32_t getMagic() const { return Magic; }
155   uint32_t getNumberOfObjects() const { return NumberOfObjects; }
156 
157   // Cast methods.
158   static bool classof(Binary const *V) {
159     return V->isMachOUniversalBinary();
160   }
161 
162   Expected<ObjectForArch>
163   getObjectForArch(StringRef ArchName) const;
164 
165   Expected<std::unique_ptr<MachOObjectFile>>
166   getMachOObjectForArch(StringRef ArchName) const;
167 
168   Expected<std::unique_ptr<Archive>>
169   getArchiveForArch(StringRef ArchName) const;
170 };
171 
172 }
173 }
174 
175 #endif
176