+Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType,
+ const char **McpuDefault) {
+ if (McpuDefault)
+ *McpuDefault = nullptr;
+
+ switch (CPUType) {
+ case MachO::CPU_TYPE_I386:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_I386_ALL:
+ return Triple("i386-apple-darwin");
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_X86_64:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_X86_64_ALL:
+ return Triple("x86_64-apple-darwin");
+ case MachO::CPU_SUBTYPE_X86_64_H:
+ return Triple("x86_64h-apple-darwin");
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_ARM:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM_V4T:
+ return Triple("armv4t-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V5TEJ:
+ return Triple("armv5e-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_XSCALE:
+ return Triple("xscale-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V6:
+ return Triple("armv6-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V6M:
+ if (McpuDefault)
+ *McpuDefault = "cortex-m0";
+ return Triple("armv6m-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7:
+ return Triple("armv7-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7EM:
+ if (McpuDefault)
+ *McpuDefault = "cortex-m4";
+ return Triple("armv7em-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7K:
+ return Triple("armv7k-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7M:
+ if (McpuDefault)
+ *McpuDefault = "cortex-m3";
+ return Triple("armv7m-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7S:
+ return Triple("armv7s-apple-darwin");
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_ARM64:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM64_ALL:
+ return Triple("arm64-apple-darwin");
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_POWERPC:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_POWERPC_ALL:
+ return Triple("ppc-apple-darwin");
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_POWERPC64:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_POWERPC_ALL:
+ return Triple("ppc64-apple-darwin");
+ default:
+ return Triple();
+ }
+ default:
+ return Triple();
+ }
+}
+
+Triple MachOObjectFile::getThumbArch(uint32_t CPUType, uint32_t CPUSubType,
+ const char **McpuDefault) {
+ if (McpuDefault)
+ *McpuDefault = nullptr;
+
+ switch (CPUType) {
+ case MachO::CPU_TYPE_ARM:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM_V4T:
+ return Triple("thumbv4t-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V5TEJ:
+ return Triple("thumbv5e-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_XSCALE:
+ return Triple("xscale-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V6:
+ return Triple("thumbv6-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V6M:
+ if (McpuDefault)
+ *McpuDefault = "cortex-m0";
+ return Triple("thumbv6m-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7:
+ return Triple("thumbv7-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7EM:
+ if (McpuDefault)
+ *McpuDefault = "cortex-m4";
+ return Triple("thumbv7em-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7K:
+ return Triple("thumbv7k-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7M:
+ if (McpuDefault)
+ *McpuDefault = "cortex-m3";
+ return Triple("thumbv7m-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7S:
+ return Triple("thumbv7s-apple-darwin");
+ default:
+ return Triple();
+ }
+ default:
+ return Triple();
+ }
+}
+
+Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType,
+ const char **McpuDefault,
+ Triple *ThumbTriple) {
+ Triple T = MachOObjectFile::getArch(CPUType, CPUSubType, McpuDefault);
+ *ThumbTriple = MachOObjectFile::getThumbArch(CPUType, CPUSubType,
+ McpuDefault);
+ return T;
+}
+
+Triple MachOObjectFile::getHostArch() {
+ return Triple(sys::getDefaultTargetTriple());
+}
+
+bool MachOObjectFile::isValidArch(StringRef ArchFlag) {
+ return StringSwitch<bool>(ArchFlag)
+ .Case("i386", true)
+ .Case("x86_64", true)
+ .Case("x86_64h", true)
+ .Case("armv4t", true)
+ .Case("arm", true)
+ .Case("armv5e", true)
+ .Case("armv6", true)
+ .Case("armv6m", true)
+ .Case("armv7em", true)
+ .Case("armv7k", true)
+ .Case("armv7m", true)
+ .Case("armv7s", true)
+ .Case("arm64", true)
+ .Case("ppc", true)
+ .Case("ppc64", true)
+ .Default(false);
+}
+
+unsigned MachOObjectFile::getArch() const {
+ return getArch(getCPUType(this));
+}
+
+Triple MachOObjectFile::getArch(const char **McpuDefault,
+ Triple *ThumbTriple) const {
+ Triple T;
+ if (is64Bit()) {
+ MachO::mach_header_64 H_64;
+ H_64 = getHeader64();
+ T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype, McpuDefault);
+ *ThumbTriple = MachOObjectFile::getThumbArch(H_64.cputype, H_64.cpusubtype,
+ McpuDefault);
+ } else {
+ MachO::mach_header H;
+ H = getHeader();
+ T = MachOObjectFile::getArch(H.cputype, H.cpusubtype, McpuDefault);
+ *ThumbTriple = MachOObjectFile::getThumbArch(H.cputype, H.cpusubtype,
+ McpuDefault);
+ }
+ return T;
+}
+
+relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const {
+ DataRefImpl DRI;
+ DRI.d.a = Index;
+ return section_rel_begin(DRI);
+}
+
+relocation_iterator MachOObjectFile::section_rel_end(unsigned Index) const {
+ DataRefImpl DRI;
+ DRI.d.a = Index;
+ return section_rel_end(DRI);
+}
+
+dice_iterator MachOObjectFile::begin_dices() const {
+ DataRefImpl DRI;
+ if (!DataInCodeLoadCmd)
+ return dice_iterator(DiceRef(DRI, this));
+
+ MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand();
+ DRI.p = reinterpret_cast<uintptr_t>(getPtr(this, DicLC.dataoff));
+ return dice_iterator(DiceRef(DRI, this));
+}
+
+dice_iterator MachOObjectFile::end_dices() const {
+ DataRefImpl DRI;
+ if (!DataInCodeLoadCmd)
+ return dice_iterator(DiceRef(DRI, this));
+
+ MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand();
+ unsigned Offset = DicLC.dataoff + DicLC.datasize;
+ DRI.p = reinterpret_cast<uintptr_t>(getPtr(this, Offset));
+ return dice_iterator(DiceRef(DRI, this));
+}
+
+ExportEntry::ExportEntry(ArrayRef<uint8_t> T)
+ : Trie(T), Malformed(false), Done(false) { }
+
+void ExportEntry::moveToFirst() {
+ pushNode(0);
+ pushDownUntilBottom();
+}
+
+void ExportEntry::moveToEnd() {
+ Stack.clear();
+ Done = true;
+}
+
+bool ExportEntry::operator==(const ExportEntry &Other) const {
+ // Common case, one at end, other iterating from begin.
+ if (Done || Other.Done)
+ return (Done == Other.Done);
+ // Not equal if different stack sizes.
+ if (Stack.size() != Other.Stack.size())
+ return false;
+ // Not equal if different cumulative strings.
+ if (!CumulativeString.str().equals(Other.CumulativeString.str()))
+ return false;
+ // Equal if all nodes in both stacks match.
+ for (unsigned i=0; i < Stack.size(); ++i) {
+ if (Stack[i].Start != Other.Stack[i].Start)
+ return false;
+ }
+ return true;
+}
+
+uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr) {
+ unsigned Count;
+ uint64_t Result = decodeULEB128(Ptr, &Count);
+ Ptr += Count;
+ if (Ptr > Trie.end()) {
+ Ptr = Trie.end();
+ Malformed = true;
+ }
+ return Result;
+}
+
+StringRef ExportEntry::name() const {
+ return CumulativeString.str();
+}
+
+uint64_t ExportEntry::flags() const {
+ return Stack.back().Flags;
+}
+
+uint64_t ExportEntry::address() const {
+ return Stack.back().Address;
+}
+
+uint64_t ExportEntry::other() const {
+ return Stack.back().Other;
+}
+
+StringRef ExportEntry::otherName() const {
+ const char* ImportName = Stack.back().ImportName;
+ if (ImportName)
+ return StringRef(ImportName);
+ return StringRef();
+}
+
+uint32_t ExportEntry::nodeOffset() const {
+ return Stack.back().Start - Trie.begin();
+}
+
+ExportEntry::NodeState::NodeState(const uint8_t *Ptr)
+ : Start(Ptr), Current(Ptr), Flags(0), Address(0), Other(0),
+ ImportName(nullptr), ChildCount(0), NextChildIndex(0),
+ ParentStringLength(0), IsExportNode(false) {
+}
+
+void ExportEntry::pushNode(uint64_t offset) {
+ const uint8_t *Ptr = Trie.begin() + offset;
+ NodeState State(Ptr);
+ uint64_t ExportInfoSize = readULEB128(State.Current);
+ State.IsExportNode = (ExportInfoSize != 0);
+ const uint8_t* Children = State.Current + ExportInfoSize;
+ if (State.IsExportNode) {
+ State.Flags = readULEB128(State.Current);
+ if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) {
+ State.Address = 0;
+ State.Other = readULEB128(State.Current); // dylib ordinal
+ State.ImportName = reinterpret_cast<const char*>(State.Current);
+ } else {
+ State.Address = readULEB128(State.Current);
+ if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+ State.Other = readULEB128(State.Current);
+ }
+ }
+ State.ChildCount = *Children;
+ State.Current = Children + 1;
+ State.NextChildIndex = 0;
+ State.ParentStringLength = CumulativeString.size();
+ Stack.push_back(State);
+}
+
+void ExportEntry::pushDownUntilBottom() {
+ while (Stack.back().NextChildIndex < Stack.back().ChildCount) {
+ NodeState &Top = Stack.back();
+ CumulativeString.resize(Top.ParentStringLength);
+ for (;*Top.Current != 0; Top.Current++) {
+ char C = *Top.Current;
+ CumulativeString.push_back(C);
+ }
+ Top.Current += 1;
+ uint64_t childNodeIndex = readULEB128(Top.Current);
+ Top.NextChildIndex += 1;
+ pushNode(childNodeIndex);
+ }
+ if (!Stack.back().IsExportNode) {
+ Malformed = true;
+ moveToEnd();
+ }
+}
+
+// We have a trie data structure and need a way to walk it that is compatible
+// with the C++ iterator model. The solution is a non-recursive depth first
+// traversal where the iterator contains a stack of parent nodes along with a
+// string that is the accumulation of all edge strings along the parent chain
+// to this point.
+//
+// There is one “export” node for each exported symbol. But because some
+// symbols may be a prefix of another symbol (e.g. _dup and _dup2), an export
+// node may have child nodes too.
+//
+// The algorithm for moveNext() is to keep moving down the leftmost unvisited
+// child until hitting a node with no children (which is an export node or
+// else the trie is malformed). On the way down, each node is pushed on the
+// stack ivar. If there is no more ways down, it pops up one and tries to go
+// down a sibling path until a childless node is reached.
+void ExportEntry::moveNext() {
+ if (Stack.empty() || !Stack.back().IsExportNode) {
+ Malformed = true;
+ moveToEnd();
+ return;
+ }
+
+ Stack.pop_back();
+ while (!Stack.empty()) {
+ NodeState &Top = Stack.back();
+ if (Top.NextChildIndex < Top.ChildCount) {
+ pushDownUntilBottom();
+ // Now at the next export node.
+ return;
+ } else {
+ if (Top.IsExportNode) {
+ // This node has no children but is itself an export node.
+ CumulativeString.resize(Top.ParentStringLength);
+ return;
+ }
+ Stack.pop_back();
+ }
+ }
+ Done = true;
+}
+
+iterator_range<export_iterator>
+MachOObjectFile::exports(ArrayRef<uint8_t> Trie) {
+ ExportEntry Start(Trie);
+ Start.moveToFirst();
+
+ ExportEntry Finish(Trie);
+ Finish.moveToEnd();
+
+ return iterator_range<export_iterator>(export_iterator(Start),
+ export_iterator(Finish));
+}
+
+iterator_range<export_iterator> MachOObjectFile::exports() const {
+ return exports(getDyldInfoExportsTrie());