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