1*e710425bSDimitry Andric //===- DylibReader.cpp -------------- TAPI MachO Dylib Reader --*- C++ -*-===//
2*e710425bSDimitry Andric //
3*e710425bSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e710425bSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*e710425bSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e710425bSDimitry Andric //
7*e710425bSDimitry Andric //===----------------------------------------------------------------------===//
8*e710425bSDimitry Andric ///
9*e710425bSDimitry Andric /// Implements the TAPI Reader for Mach-O dynamic libraries.
10*e710425bSDimitry Andric ///
11*e710425bSDimitry Andric //===----------------------------------------------------------------------===//
12*e710425bSDimitry Andric 
13*e710425bSDimitry Andric #include "llvm/TextAPI/DylibReader.h"
14*e710425bSDimitry Andric #include "llvm/ADT/STLExtras.h"
15*e710425bSDimitry Andric #include "llvm/ADT/StringMap.h"
16*e710425bSDimitry Andric #include "llvm/Object/Binary.h"
17*e710425bSDimitry Andric #include "llvm/Object/MachOUniversal.h"
18*e710425bSDimitry Andric #include "llvm/Support/Endian.h"
19*e710425bSDimitry Andric #include "llvm/TargetParser/Triple.h"
20*e710425bSDimitry Andric #include "llvm/TextAPI/RecordsSlice.h"
21*e710425bSDimitry Andric #include "llvm/TextAPI/TextAPIError.h"
22*e710425bSDimitry Andric #include <iomanip>
23*e710425bSDimitry Andric #include <set>
24*e710425bSDimitry Andric #include <sstream>
25*e710425bSDimitry Andric #include <string>
26*e710425bSDimitry Andric #include <tuple>
27*e710425bSDimitry Andric 
28*e710425bSDimitry Andric using namespace llvm;
29*e710425bSDimitry Andric using namespace llvm::object;
30*e710425bSDimitry Andric using namespace llvm::MachO;
31*e710425bSDimitry Andric using namespace llvm::MachO::DylibReader;
32*e710425bSDimitry Andric 
33*e710425bSDimitry Andric using TripleVec = std::vector<Triple>;
emplace(TripleVec & Container,Triple && T)34*e710425bSDimitry Andric static typename TripleVec::iterator emplace(TripleVec &Container, Triple &&T) {
35*e710425bSDimitry Andric   auto I = partition_point(Container, [=](const Triple &CT) {
36*e710425bSDimitry Andric     return std::forward_as_tuple(CT.getArch(), CT.getOS(),
37*e710425bSDimitry Andric                                  CT.getEnvironment()) <
38*e710425bSDimitry Andric            std::forward_as_tuple(T.getArch(), T.getOS(), T.getEnvironment());
39*e710425bSDimitry Andric   });
40*e710425bSDimitry Andric 
41*e710425bSDimitry Andric   if (I != Container.end() && *I == T)
42*e710425bSDimitry Andric     return I;
43*e710425bSDimitry Andric   return Container.emplace(I, T);
44*e710425bSDimitry Andric }
45*e710425bSDimitry Andric 
constructTriples(MachOObjectFile * Obj,const Architecture ArchT)46*e710425bSDimitry Andric static TripleVec constructTriples(MachOObjectFile *Obj,
47*e710425bSDimitry Andric                                   const Architecture ArchT) {
48*e710425bSDimitry Andric   auto getOSVersionStr = [](uint32_t V) {
49*e710425bSDimitry Andric     PackedVersion OSVersion(V);
50*e710425bSDimitry Andric     std::string Vers;
51*e710425bSDimitry Andric     raw_string_ostream VStream(Vers);
52*e710425bSDimitry Andric     VStream << OSVersion;
53*e710425bSDimitry Andric     return VStream.str();
54*e710425bSDimitry Andric   };
55*e710425bSDimitry Andric   auto getOSVersion = [&](const MachOObjectFile::LoadCommandInfo &cmd) {
56*e710425bSDimitry Andric     auto Vers = Obj->getVersionMinLoadCommand(cmd);
57*e710425bSDimitry Andric     return getOSVersionStr(Vers.version);
58*e710425bSDimitry Andric   };
59*e710425bSDimitry Andric 
60*e710425bSDimitry Andric   TripleVec Triples;
61*e710425bSDimitry Andric   bool IsIntel = ArchitectureSet(ArchT).hasX86();
62*e710425bSDimitry Andric   auto Arch = getArchitectureName(ArchT);
63*e710425bSDimitry Andric 
64*e710425bSDimitry Andric   for (const auto &cmd : Obj->load_commands()) {
65*e710425bSDimitry Andric     std::string OSVersion;
66*e710425bSDimitry Andric     switch (cmd.C.cmd) {
67*e710425bSDimitry Andric     case MachO::LC_VERSION_MIN_MACOSX:
68*e710425bSDimitry Andric       OSVersion = getOSVersion(cmd);
69*e710425bSDimitry Andric       emplace(Triples, {Arch, "apple", "macos" + OSVersion});
70*e710425bSDimitry Andric       break;
71*e710425bSDimitry Andric     case MachO::LC_VERSION_MIN_IPHONEOS:
72*e710425bSDimitry Andric       OSVersion = getOSVersion(cmd);
73*e710425bSDimitry Andric       if (IsIntel)
74*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "ios" + OSVersion, "simulator"});
75*e710425bSDimitry Andric       else
76*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "ios" + OSVersion});
77*e710425bSDimitry Andric       break;
78*e710425bSDimitry Andric     case MachO::LC_VERSION_MIN_TVOS:
79*e710425bSDimitry Andric       OSVersion = getOSVersion(cmd);
80*e710425bSDimitry Andric       if (IsIntel)
81*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "tvos" + OSVersion, "simulator"});
82*e710425bSDimitry Andric       else
83*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "tvos" + OSVersion});
84*e710425bSDimitry Andric       break;
85*e710425bSDimitry Andric     case MachO::LC_VERSION_MIN_WATCHOS:
86*e710425bSDimitry Andric       OSVersion = getOSVersion(cmd);
87*e710425bSDimitry Andric       if (IsIntel)
88*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "watchos" + OSVersion, "simulator"});
89*e710425bSDimitry Andric       else
90*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "watchos" + OSVersion});
91*e710425bSDimitry Andric       break;
92*e710425bSDimitry Andric     case MachO::LC_BUILD_VERSION: {
93*e710425bSDimitry Andric       OSVersion = getOSVersionStr(Obj->getBuildVersionLoadCommand(cmd).minos);
94*e710425bSDimitry Andric       switch (Obj->getBuildVersionLoadCommand(cmd).platform) {
95*e710425bSDimitry Andric       case MachO::PLATFORM_MACOS:
96*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "macos" + OSVersion});
97*e710425bSDimitry Andric         break;
98*e710425bSDimitry Andric       case MachO::PLATFORM_IOS:
99*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "ios" + OSVersion});
100*e710425bSDimitry Andric         break;
101*e710425bSDimitry Andric       case MachO::PLATFORM_TVOS:
102*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "tvos" + OSVersion});
103*e710425bSDimitry Andric         break;
104*e710425bSDimitry Andric       case MachO::PLATFORM_WATCHOS:
105*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "watchos" + OSVersion});
106*e710425bSDimitry Andric         break;
107*e710425bSDimitry Andric       case MachO::PLATFORM_BRIDGEOS:
108*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "bridgeos" + OSVersion});
109*e710425bSDimitry Andric         break;
110*e710425bSDimitry Andric       case MachO::PLATFORM_MACCATALYST:
111*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "ios" + OSVersion, "macabi"});
112*e710425bSDimitry Andric         break;
113*e710425bSDimitry Andric       case MachO::PLATFORM_IOSSIMULATOR:
114*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "ios" + OSVersion, "simulator"});
115*e710425bSDimitry Andric         break;
116*e710425bSDimitry Andric       case MachO::PLATFORM_TVOSSIMULATOR:
117*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "tvos" + OSVersion, "simulator"});
118*e710425bSDimitry Andric         break;
119*e710425bSDimitry Andric       case MachO::PLATFORM_WATCHOSSIMULATOR:
120*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "watchos" + OSVersion, "simulator"});
121*e710425bSDimitry Andric         break;
122*e710425bSDimitry Andric       case MachO::PLATFORM_DRIVERKIT:
123*e710425bSDimitry Andric         emplace(Triples, {Arch, "apple", "driverkit" + OSVersion});
124*e710425bSDimitry Andric         break;
125*e710425bSDimitry Andric       default:
126*e710425bSDimitry Andric         break; // Skip any others.
127*e710425bSDimitry Andric       }
128*e710425bSDimitry Andric       break;
129*e710425bSDimitry Andric     }
130*e710425bSDimitry Andric     default:
131*e710425bSDimitry Andric       break;
132*e710425bSDimitry Andric     }
133*e710425bSDimitry Andric   }
134*e710425bSDimitry Andric 
135*e710425bSDimitry Andric   // Record unknown platform for older binaries that don't enforce platform
136*e710425bSDimitry Andric   // load commands.
137*e710425bSDimitry Andric   if (Triples.empty())
138*e710425bSDimitry Andric     emplace(Triples, {Arch, "apple", "unknown"});
139*e710425bSDimitry Andric 
140*e710425bSDimitry Andric   return Triples;
141*e710425bSDimitry Andric }
142*e710425bSDimitry Andric 
readMachOHeader(MachOObjectFile * Obj,RecordsSlice & Slice)143*e710425bSDimitry Andric static Error readMachOHeader(MachOObjectFile *Obj, RecordsSlice &Slice) {
144*e710425bSDimitry Andric   auto H = Obj->getHeader();
145*e710425bSDimitry Andric   auto &BA = Slice.getBinaryAttrs();
146*e710425bSDimitry Andric 
147*e710425bSDimitry Andric   switch (H.filetype) {
148*e710425bSDimitry Andric   default:
149*e710425bSDimitry Andric     llvm_unreachable("unsupported binary type");
150*e710425bSDimitry Andric   case MachO::MH_DYLIB:
151*e710425bSDimitry Andric     BA.File = FileType::MachO_DynamicLibrary;
152*e710425bSDimitry Andric     break;
153*e710425bSDimitry Andric   case MachO::MH_DYLIB_STUB:
154*e710425bSDimitry Andric     BA.File = FileType::MachO_DynamicLibrary_Stub;
155*e710425bSDimitry Andric     break;
156*e710425bSDimitry Andric   case MachO::MH_BUNDLE:
157*e710425bSDimitry Andric     BA.File = FileType::MachO_Bundle;
158*e710425bSDimitry Andric     break;
159*e710425bSDimitry Andric   }
160*e710425bSDimitry Andric 
161*e710425bSDimitry Andric   if (H.flags & MachO::MH_TWOLEVEL)
162*e710425bSDimitry Andric     BA.TwoLevelNamespace = true;
163*e710425bSDimitry Andric   if (H.flags & MachO::MH_APP_EXTENSION_SAFE)
164*e710425bSDimitry Andric     BA.AppExtensionSafe = true;
165*e710425bSDimitry Andric 
166*e710425bSDimitry Andric   for (const auto &LCI : Obj->load_commands()) {
167*e710425bSDimitry Andric     switch (LCI.C.cmd) {
168*e710425bSDimitry Andric     case MachO::LC_ID_DYLIB: {
169*e710425bSDimitry Andric       auto DLLC = Obj->getDylibIDLoadCommand(LCI);
170*e710425bSDimitry Andric       BA.InstallName = Slice.copyString(LCI.Ptr + DLLC.dylib.name);
171*e710425bSDimitry Andric       BA.CurrentVersion = DLLC.dylib.current_version;
172*e710425bSDimitry Andric       BA.CompatVersion = DLLC.dylib.compatibility_version;
173*e710425bSDimitry Andric       break;
174*e710425bSDimitry Andric     }
175*e710425bSDimitry Andric     case MachO::LC_REEXPORT_DYLIB: {
176*e710425bSDimitry Andric       auto DLLC = Obj->getDylibIDLoadCommand(LCI);
177*e710425bSDimitry Andric       BA.RexportedLibraries.emplace_back(
178*e710425bSDimitry Andric           Slice.copyString(LCI.Ptr + DLLC.dylib.name));
179*e710425bSDimitry Andric       break;
180*e710425bSDimitry Andric     }
181*e710425bSDimitry Andric     case MachO::LC_SUB_FRAMEWORK: {
182*e710425bSDimitry Andric       auto SFC = Obj->getSubFrameworkCommand(LCI);
183*e710425bSDimitry Andric       BA.ParentUmbrella = Slice.copyString(LCI.Ptr + SFC.umbrella);
184*e710425bSDimitry Andric       break;
185*e710425bSDimitry Andric     }
186*e710425bSDimitry Andric     case MachO::LC_SUB_CLIENT: {
187*e710425bSDimitry Andric       auto SCLC = Obj->getSubClientCommand(LCI);
188*e710425bSDimitry Andric       BA.AllowableClients.emplace_back(Slice.copyString(LCI.Ptr + SCLC.client));
189*e710425bSDimitry Andric       break;
190*e710425bSDimitry Andric     }
191*e710425bSDimitry Andric     case MachO::LC_UUID: {
192*e710425bSDimitry Andric       auto UUIDLC = Obj->getUuidCommand(LCI);
193*e710425bSDimitry Andric       std::stringstream Stream;
194*e710425bSDimitry Andric       for (unsigned I = 0; I < 16; ++I) {
195*e710425bSDimitry Andric         if (I == 4 || I == 6 || I == 8 || I == 10)
196*e710425bSDimitry Andric           Stream << '-';
197*e710425bSDimitry Andric         Stream << std::setfill('0') << std::setw(2) << std::uppercase
198*e710425bSDimitry Andric                << std::hex << static_cast<int>(UUIDLC.uuid[I]);
199*e710425bSDimitry Andric       }
200*e710425bSDimitry Andric       BA.UUID = Slice.copyString(Stream.str());
201*e710425bSDimitry Andric       break;
202*e710425bSDimitry Andric     }
203*e710425bSDimitry Andric     case MachO::LC_RPATH: {
204*e710425bSDimitry Andric       auto RPLC = Obj->getRpathCommand(LCI);
205*e710425bSDimitry Andric       BA.RPaths.emplace_back(Slice.copyString(LCI.Ptr + RPLC.path));
206*e710425bSDimitry Andric       break;
207*e710425bSDimitry Andric     }
208*e710425bSDimitry Andric     case MachO::LC_SEGMENT_SPLIT_INFO: {
209*e710425bSDimitry Andric       auto SSILC = Obj->getLinkeditDataLoadCommand(LCI);
210*e710425bSDimitry Andric       if (SSILC.datasize == 0)
211*e710425bSDimitry Andric         BA.OSLibNotForSharedCache = true;
212*e710425bSDimitry Andric       break;
213*e710425bSDimitry Andric     }
214*e710425bSDimitry Andric     default:
215*e710425bSDimitry Andric       break;
216*e710425bSDimitry Andric     }
217*e710425bSDimitry Andric   }
218*e710425bSDimitry Andric 
219*e710425bSDimitry Andric   for (auto &Sect : Obj->sections()) {
220*e710425bSDimitry Andric     auto SectName = Sect.getName();
221*e710425bSDimitry Andric     if (!SectName)
222*e710425bSDimitry Andric       return SectName.takeError();
223*e710425bSDimitry Andric     if (*SectName != "__objc_imageinfo" && *SectName != "__image_info")
224*e710425bSDimitry Andric       continue;
225*e710425bSDimitry Andric 
226*e710425bSDimitry Andric     auto Content = Sect.getContents();
227*e710425bSDimitry Andric     if (!Content)
228*e710425bSDimitry Andric       return Content.takeError();
229*e710425bSDimitry Andric 
230*e710425bSDimitry Andric     if ((Content->size() >= 8) && (Content->front() == 0)) {
231*e710425bSDimitry Andric       uint32_t Flags;
232*e710425bSDimitry Andric       if (Obj->isLittleEndian()) {
233*e710425bSDimitry Andric         auto *p =
234*e710425bSDimitry Andric             reinterpret_cast<const support::ulittle32_t *>(Content->data() + 4);
235*e710425bSDimitry Andric         Flags = *p;
236*e710425bSDimitry Andric       } else {
237*e710425bSDimitry Andric         auto *p =
238*e710425bSDimitry Andric             reinterpret_cast<const support::ubig32_t *>(Content->data() + 4);
239*e710425bSDimitry Andric         Flags = *p;
240*e710425bSDimitry Andric       }
241*e710425bSDimitry Andric       BA.SwiftABI = (Flags >> 8) & 0xFF;
242*e710425bSDimitry Andric     }
243*e710425bSDimitry Andric   }
244*e710425bSDimitry Andric   return Error::success();
245*e710425bSDimitry Andric }
246*e710425bSDimitry Andric 
readSymbols(MachOObjectFile * Obj,RecordsSlice & Slice,const ParseOption & Opt)247*e710425bSDimitry Andric static Error readSymbols(MachOObjectFile *Obj, RecordsSlice &Slice,
248*e710425bSDimitry Andric                          const ParseOption &Opt) {
249*e710425bSDimitry Andric 
250*e710425bSDimitry Andric   auto parseExport = [](const auto ExportFlags,
251*e710425bSDimitry Andric                         auto Addr) -> std::tuple<SymbolFlags, RecordLinkage> {
252*e710425bSDimitry Andric     SymbolFlags Flags = SymbolFlags::None;
253*e710425bSDimitry Andric     switch (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) {
254*e710425bSDimitry Andric     case MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
255*e710425bSDimitry Andric       if (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION)
256*e710425bSDimitry Andric         Flags |= SymbolFlags::WeakDefined;
257*e710425bSDimitry Andric       break;
258*e710425bSDimitry Andric     case MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
259*e710425bSDimitry Andric       Flags |= SymbolFlags::ThreadLocalValue;
260*e710425bSDimitry Andric       break;
261*e710425bSDimitry Andric     }
262*e710425bSDimitry Andric 
263*e710425bSDimitry Andric     RecordLinkage Linkage = (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT)
264*e710425bSDimitry Andric                                 ? RecordLinkage::Rexported
265*e710425bSDimitry Andric                                 : RecordLinkage::Exported;
266*e710425bSDimitry Andric     return {Flags, Linkage};
267*e710425bSDimitry Andric   };
268*e710425bSDimitry Andric 
269*e710425bSDimitry Andric   Error Err = Error::success();
270*e710425bSDimitry Andric 
271*e710425bSDimitry Andric   StringMap<std::pair<SymbolFlags, RecordLinkage>> Exports;
272*e710425bSDimitry Andric   // Collect symbols from export trie first. Sometimes, there are more exports
273*e710425bSDimitry Andric   // in the trie than in n-list due to stripping. This is common for swift
274*e710425bSDimitry Andric   // mangled symbols.
275*e710425bSDimitry Andric   for (auto &Sym : Obj->exports(Err)) {
276*e710425bSDimitry Andric     auto [Flags, Linkage] = parseExport(Sym.flags(), Sym.address());
277*e710425bSDimitry Andric     Slice.addRecord(Sym.name(), Flags, GlobalRecord::Kind::Unknown, Linkage);
278*e710425bSDimitry Andric     Exports[Sym.name()] = {Flags, Linkage};
279*e710425bSDimitry Andric   }
280*e710425bSDimitry Andric 
281*e710425bSDimitry Andric   for (const auto &Sym : Obj->symbols()) {
282*e710425bSDimitry Andric     auto FlagsOrErr = Sym.getFlags();
283*e710425bSDimitry Andric     if (!FlagsOrErr)
284*e710425bSDimitry Andric       return FlagsOrErr.takeError();
285*e710425bSDimitry Andric     auto Flags = *FlagsOrErr;
286*e710425bSDimitry Andric 
287*e710425bSDimitry Andric     auto NameOrErr = Sym.getName();
288*e710425bSDimitry Andric     if (!NameOrErr)
289*e710425bSDimitry Andric       return NameOrErr.takeError();
290*e710425bSDimitry Andric     auto Name = *NameOrErr;
291*e710425bSDimitry Andric 
292*e710425bSDimitry Andric     RecordLinkage Linkage = RecordLinkage::Unknown;
293*e710425bSDimitry Andric     SymbolFlags RecordFlags = SymbolFlags::None;
294*e710425bSDimitry Andric 
295*e710425bSDimitry Andric     if (Opt.Undefineds && (Flags & SymbolRef::SF_Undefined)) {
296*e710425bSDimitry Andric       Linkage = RecordLinkage::Undefined;
297*e710425bSDimitry Andric       if (Flags & SymbolRef::SF_Weak)
298*e710425bSDimitry Andric         RecordFlags |= SymbolFlags::WeakReferenced;
299*e710425bSDimitry Andric     } else if (Flags & SymbolRef::SF_Exported) {
300*e710425bSDimitry Andric       auto Exp = Exports.find(Name);
301*e710425bSDimitry Andric       // This should never be possible when binaries are produced with Apple
302*e710425bSDimitry Andric       // linkers. However it is possible to craft dylibs where the export trie
303*e710425bSDimitry Andric       // is either malformed or has conflicting symbols compared to n_list.
304*e710425bSDimitry Andric       if (Exp != Exports.end())
305*e710425bSDimitry Andric         std::tie(RecordFlags, Linkage) = Exp->second;
306*e710425bSDimitry Andric       else
307*e710425bSDimitry Andric         Linkage = RecordLinkage::Exported;
308*e710425bSDimitry Andric     } else if (Flags & SymbolRef::SF_Hidden) {
309*e710425bSDimitry Andric       Linkage = RecordLinkage::Internal;
310*e710425bSDimitry Andric     } else
311*e710425bSDimitry Andric       continue;
312*e710425bSDimitry Andric 
313*e710425bSDimitry Andric     auto TypeOrErr = Sym.getType();
314*e710425bSDimitry Andric     if (!TypeOrErr)
315*e710425bSDimitry Andric       return TypeOrErr.takeError();
316*e710425bSDimitry Andric     auto Type = *TypeOrErr;
317*e710425bSDimitry Andric 
318*e710425bSDimitry Andric     GlobalRecord::Kind GV = (Type & SymbolRef::ST_Function)
319*e710425bSDimitry Andric                                 ? GlobalRecord::Kind::Function
320*e710425bSDimitry Andric                                 : GlobalRecord::Kind::Variable;
321*e710425bSDimitry Andric 
322*e710425bSDimitry Andric     if (GV == GlobalRecord::Kind::Function)
323*e710425bSDimitry Andric       RecordFlags |= SymbolFlags::Text;
324*e710425bSDimitry Andric     else
325*e710425bSDimitry Andric       RecordFlags |= SymbolFlags::Data;
326*e710425bSDimitry Andric 
327*e710425bSDimitry Andric     Slice.addRecord(Name, RecordFlags, GV, Linkage);
328*e710425bSDimitry Andric   }
329*e710425bSDimitry Andric   return Err;
330*e710425bSDimitry Andric }
331*e710425bSDimitry Andric 
load(MachOObjectFile * Obj,RecordsSlice & Slice,const ParseOption & Opt,const Architecture Arch)332*e710425bSDimitry Andric static Error load(MachOObjectFile *Obj, RecordsSlice &Slice,
333*e710425bSDimitry Andric                   const ParseOption &Opt, const Architecture Arch) {
334*e710425bSDimitry Andric   if (Arch == AK_unknown)
335*e710425bSDimitry Andric     return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget);
336*e710425bSDimitry Andric 
337*e710425bSDimitry Andric   if (Opt.MachOHeader)
338*e710425bSDimitry Andric     if (auto Err = readMachOHeader(Obj, Slice))
339*e710425bSDimitry Andric       return Err;
340*e710425bSDimitry Andric 
341*e710425bSDimitry Andric   if (Opt.SymbolTable)
342*e710425bSDimitry Andric     if (auto Err = readSymbols(Obj, Slice, Opt))
343*e710425bSDimitry Andric       return Err;
344*e710425bSDimitry Andric 
345*e710425bSDimitry Andric   return Error::success();
346*e710425bSDimitry Andric }
347*e710425bSDimitry Andric 
readFile(MemoryBufferRef Buffer,const ParseOption & Opt)348*e710425bSDimitry Andric Expected<Records> DylibReader::readFile(MemoryBufferRef Buffer,
349*e710425bSDimitry Andric                                         const ParseOption &Opt) {
350*e710425bSDimitry Andric   Records Results;
351*e710425bSDimitry Andric 
352*e710425bSDimitry Andric   auto BinOrErr = createBinary(Buffer);
353*e710425bSDimitry Andric   if (!BinOrErr)
354*e710425bSDimitry Andric     return BinOrErr.takeError();
355*e710425bSDimitry Andric 
356*e710425bSDimitry Andric   Binary &Bin = *BinOrErr.get();
357*e710425bSDimitry Andric   if (auto *Obj = dyn_cast<MachOObjectFile>(&Bin)) {
358*e710425bSDimitry Andric     const auto Arch = getArchitectureFromCpuType(Obj->getHeader().cputype,
359*e710425bSDimitry Andric                                                  Obj->getHeader().cpusubtype);
360*e710425bSDimitry Andric     if (!Opt.Archs.has(Arch))
361*e710425bSDimitry Andric       return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
362*e710425bSDimitry Andric 
363*e710425bSDimitry Andric     auto Triples = constructTriples(Obj, Arch);
364*e710425bSDimitry Andric     for (const auto &T : Triples) {
365*e710425bSDimitry Andric       if (mapToPlatformType(T) == PLATFORM_UNKNOWN)
366*e710425bSDimitry Andric         return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget);
367*e710425bSDimitry Andric       Results.emplace_back(std::make_shared<RecordsSlice>(RecordsSlice({T})));
368*e710425bSDimitry Andric       if (auto Err = load(Obj, *Results.back(), Opt, Arch))
369*e710425bSDimitry Andric         return std::move(Err);
370*e710425bSDimitry Andric       Results.back()->getBinaryAttrs().Path = Buffer.getBufferIdentifier();
371*e710425bSDimitry Andric     }
372*e710425bSDimitry Andric     return Results;
373*e710425bSDimitry Andric   }
374*e710425bSDimitry Andric 
375*e710425bSDimitry Andric   // Only expect MachO universal binaries at this point.
376*e710425bSDimitry Andric   assert(isa<MachOUniversalBinary>(&Bin) &&
377*e710425bSDimitry Andric          "Expected a MachO universal binary.");
378*e710425bSDimitry Andric   auto *UB = cast<MachOUniversalBinary>(&Bin);
379*e710425bSDimitry Andric 
380*e710425bSDimitry Andric   for (auto OI = UB->begin_objects(), OE = UB->end_objects(); OI != OE; ++OI) {
381*e710425bSDimitry Andric     // Skip architecture if not requested.
382*e710425bSDimitry Andric     auto Arch =
383*e710425bSDimitry Andric         getArchitectureFromCpuType(OI->getCPUType(), OI->getCPUSubType());
384*e710425bSDimitry Andric     if (!Opt.Archs.has(Arch))
385*e710425bSDimitry Andric       continue;
386*e710425bSDimitry Andric 
387*e710425bSDimitry Andric     // Skip unknown architectures.
388*e710425bSDimitry Andric     if (Arch == AK_unknown)
389*e710425bSDimitry Andric       continue;
390*e710425bSDimitry Andric 
391*e710425bSDimitry Andric     // This can fail if the object is an archive.
392*e710425bSDimitry Andric     auto ObjOrErr = OI->getAsObjectFile();
393*e710425bSDimitry Andric 
394*e710425bSDimitry Andric     // Skip the archive and consume the error.
395*e710425bSDimitry Andric     if (!ObjOrErr) {
396*e710425bSDimitry Andric       consumeError(ObjOrErr.takeError());
397*e710425bSDimitry Andric       continue;
398*e710425bSDimitry Andric     }
399*e710425bSDimitry Andric 
400*e710425bSDimitry Andric     auto &Obj = *ObjOrErr.get();
401*e710425bSDimitry Andric     switch (Obj.getHeader().filetype) {
402*e710425bSDimitry Andric     default:
403*e710425bSDimitry Andric       break;
404*e710425bSDimitry Andric     case MachO::MH_BUNDLE:
405*e710425bSDimitry Andric     case MachO::MH_DYLIB:
406*e710425bSDimitry Andric     case MachO::MH_DYLIB_STUB:
407*e710425bSDimitry Andric       for (const auto &T : constructTriples(&Obj, Arch)) {
408*e710425bSDimitry Andric         Results.emplace_back(std::make_shared<RecordsSlice>(RecordsSlice({T})));
409*e710425bSDimitry Andric         if (auto Err = load(&Obj, *Results.back(), Opt, Arch))
410*e710425bSDimitry Andric           return std::move(Err);
411*e710425bSDimitry Andric       }
412*e710425bSDimitry Andric       break;
413*e710425bSDimitry Andric     }
414*e710425bSDimitry Andric   }
415*e710425bSDimitry Andric 
416*e710425bSDimitry Andric   if (Results.empty())
417*e710425bSDimitry Andric     return make_error<TextAPIError>(TextAPIErrorCode::EmptyResults);
418*e710425bSDimitry Andric   return Results;
419*e710425bSDimitry Andric }
420*e710425bSDimitry Andric 
421*e710425bSDimitry Andric Expected<std::unique_ptr<InterfaceFile>>
get(MemoryBufferRef Buffer)422*e710425bSDimitry Andric DylibReader::get(MemoryBufferRef Buffer) {
423*e710425bSDimitry Andric   ParseOption Options;
424*e710425bSDimitry Andric   auto SlicesOrErr = readFile(Buffer, Options);
425*e710425bSDimitry Andric   if (!SlicesOrErr)
426*e710425bSDimitry Andric     return SlicesOrErr.takeError();
427*e710425bSDimitry Andric 
428*e710425bSDimitry Andric   return convertToInterfaceFile(*SlicesOrErr);
429*e710425bSDimitry Andric }
430