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