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
23namespace llvm {
24class StringRef;
25
26namespace object {
27
28class MachOUniversalBinary : public Binary {
29  virtual void anchor();
30
31  uint32_t Magic;
32  uint32_t NumberOfObjects;
33public:
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